Skip to content

Commit a921c65

Browse files
jankaraaxboe
authored andcommitted
bfq: Remove merged request already in bfq_requests_merged()
Currently, bfq does very little in bfq_requests_merged() and handles all the request cleanup in bfq_finish_requeue_request() called from blk_mq_free_request(). That is currently safe only because blk_mq_free_request() is called shortly after bfq_requests_merged() while bfqd->lock is still held. However to fix a lock inversion between bfqd->lock and ioc->lock, we need to call blk_mq_free_request() after dropping bfqd->lock. That would mean that already merged request could be seen by other processes inside bfq queues and possibly dispatched to the device which is wrong. So move cleanup of the request from bfq_finish_requeue_request() to bfq_requests_merged(). Acked-by: Paolo Valente <[email protected]> Signed-off-by: Jan Kara <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent 0384264 commit a921c65

File tree

1 file changed

+13
-28
lines changed

1 file changed

+13
-28
lines changed

block/bfq-iosched.c

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2433,7 +2433,7 @@ static void bfq_requests_merged(struct request_queue *q, struct request *rq,
24332433
*next_bfqq = bfq_init_rq(next);
24342434

24352435
if (!bfqq)
2436-
return;
2436+
goto remove;
24372437

24382438
/*
24392439
* If next and rq belong to the same bfq_queue and next is older
@@ -2456,6 +2456,14 @@ static void bfq_requests_merged(struct request_queue *q, struct request *rq,
24562456
bfqq->next_rq = rq;
24572457

24582458
bfqg_stats_update_io_merged(bfqq_group(bfqq), next->cmd_flags);
2459+
remove:
2460+
/* Merged request may be in the IO scheduler. Remove it. */
2461+
if (!RB_EMPTY_NODE(&next->rb_node)) {
2462+
bfq_remove_request(next->q, next);
2463+
if (next_bfqq)
2464+
bfqg_stats_update_io_remove(bfqq_group(next_bfqq),
2465+
next->cmd_flags);
2466+
}
24592467
}
24602468

24612469
/* Must be called with bfqq != NULL */
@@ -6414,6 +6422,7 @@ static void bfq_finish_requeue_request(struct request *rq)
64146422
{
64156423
struct bfq_queue *bfqq = RQ_BFQQ(rq);
64166424
struct bfq_data *bfqd;
6425+
unsigned long flags;
64176426

64186427
/*
64196428
* rq either is not associated with any icq, or is an already
@@ -6431,39 +6440,15 @@ static void bfq_finish_requeue_request(struct request *rq)
64316440
rq->io_start_time_ns,
64326441
rq->cmd_flags);
64336442

6443+
spin_lock_irqsave(&bfqd->lock, flags);
64346444
if (likely(rq->rq_flags & RQF_STARTED)) {
6435-
unsigned long flags;
6436-
6437-
spin_lock_irqsave(&bfqd->lock, flags);
6438-
64396445
if (rq == bfqd->waited_rq)
64406446
bfq_update_inject_limit(bfqd, bfqq);
64416447

64426448
bfq_completed_request(bfqq, bfqd);
6443-
bfq_finish_requeue_request_body(bfqq);
6444-
6445-
spin_unlock_irqrestore(&bfqd->lock, flags);
6446-
} else {
6447-
/*
6448-
* Request rq may be still/already in the scheduler,
6449-
* in which case we need to remove it (this should
6450-
* never happen in case of requeue). And we cannot
6451-
* defer such a check and removal, to avoid
6452-
* inconsistencies in the time interval from the end
6453-
* of this function to the start of the deferred work.
6454-
* This situation seems to occur only in process
6455-
* context, as a consequence of a merge. In the
6456-
* current version of the code, this implies that the
6457-
* lock is held.
6458-
*/
6459-
6460-
if (!RB_EMPTY_NODE(&rq->rb_node)) {
6461-
bfq_remove_request(rq->q, rq);
6462-
bfqg_stats_update_io_remove(bfqq_group(bfqq),
6463-
rq->cmd_flags);
6464-
}
6465-
bfq_finish_requeue_request_body(bfqq);
64666449
}
6450+
bfq_finish_requeue_request_body(bfqq);
6451+
spin_unlock_irqrestore(&bfqd->lock, flags);
64676452

64686453
/*
64696454
* Reset private fields. In case of a requeue, this allows

0 commit comments

Comments
 (0)