Skip to content

Commit 7ea96ee

Browse files
Algodev-githubaxboe
authored andcommitted
block, bfq: avoid circular stable merges
BFQ may merge a new bfq_queue, stably, with the last bfq_queue created. In particular, BFQ first waits a little bit for some I/O to flow inside the new queue, say Q2, if this is needed to understand whether it is better or worse to merge Q2 with the last queue created, say Q1. This delayed stable merge is performed by assigning bic->stable_merge_bfqq = Q1, for the bic associated with Q1. Yet, while waiting for some I/O to flow in Q2, a non-stable queue merge of Q2 with Q1 may happen, causing the bic previously associated with Q2 to be associated with exactly Q1 (bic->bfqq = Q1). After that, Q2 and Q1 may happen to be split, and, in the split, Q1 may happen to be recycled as a non-shared bfq_queue. In that case, Q1 may then happen to undergo a stable merge with the bfq_queue pointed by bic->stable_merge_bfqq. Yet bic->stable_merge_bfqq still points to Q1. So Q1 would be merged with itself. This commit fixes this error by intercepting this situation, and canceling the schedule of the stable merge. Fixes: 430a67f ("block, bfq: merge bursts of newly-created queues") Signed-off-by: Pietro Pedroni <[email protected]> Signed-off-by: Paolo Valente <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent e9f4eee commit 7ea96ee

File tree

1 file changed

+29
-2
lines changed

1 file changed

+29
-2
lines changed

block/bfq-iosched.c

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -372,9 +372,38 @@ struct bfq_queue *bic_to_bfqq(struct bfq_io_cq *bic, bool is_sync)
372372
return bic->bfqq[is_sync];
373373
}
374374

375+
static void bfq_put_stable_ref(struct bfq_queue *bfqq);
376+
375377
void bic_set_bfqq(struct bfq_io_cq *bic, struct bfq_queue *bfqq, bool is_sync)
376378
{
379+
/*
380+
* If bfqq != NULL, then a non-stable queue merge between
381+
* bic->bfqq and bfqq is happening here. This causes troubles
382+
* in the following case: bic->bfqq has also been scheduled
383+
* for a possible stable merge with bic->stable_merge_bfqq,
384+
* and bic->stable_merge_bfqq == bfqq happens to
385+
* hold. Troubles occur because bfqq may then undergo a split,
386+
* thereby becoming eligible for a stable merge. Yet, if
387+
* bic->stable_merge_bfqq points exactly to bfqq, then bfqq
388+
* would be stably merged with itself. To avoid this anomaly,
389+
* we cancel the stable merge if
390+
* bic->stable_merge_bfqq == bfqq.
391+
*/
377392
bic->bfqq[is_sync] = bfqq;
393+
394+
if (bfqq && bic->stable_merge_bfqq == bfqq) {
395+
/*
396+
* Actually, these same instructions are executed also
397+
* in bfq_setup_cooperator, in case of abort or actual
398+
* execution of a stable merge. We could avoid
399+
* repeating these instructions there too, but if we
400+
* did so, we would nest even more complexity in this
401+
* function.
402+
*/
403+
bfq_put_stable_ref(bic->stable_merge_bfqq);
404+
405+
bic->stable_merge_bfqq = NULL;
406+
}
378407
}
379408

380409
struct bfq_data *bic_to_bfqd(struct bfq_io_cq *bic)
@@ -2630,8 +2659,6 @@ static bool bfq_may_be_close_cooperator(struct bfq_queue *bfqq,
26302659
static bool idling_boosts_thr_without_issues(struct bfq_data *bfqd,
26312660
struct bfq_queue *bfqq);
26322661

2633-
static void bfq_put_stable_ref(struct bfq_queue *bfqq);
2634-
26352662
/*
26362663
* Attempt to schedule a merge of bfqq with the currently in-service
26372664
* queue or with a close queue among the scheduled queues. Return

0 commit comments

Comments
 (0)