> Il giorno 24 mag 2021, alle ore 12:04, Jan Kara <jack@xxxxxxx> ha scritto: > > 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(). > I didn't even remember any longer why I had to handle that deferred removal in bfq_finish_requeue_request() :) Your solution seems very clean to me. Acked-by: Paolo Valente <paolo.valente@xxxxxxxxxx> > Signed-off-by: Jan Kara <jack@xxxxxxx> > --- > block/bfq-iosched.c | 41 +++++++++++++---------------------------- > 1 file changed, 13 insertions(+), 28 deletions(-) > > diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c > index acd1f881273e..50a29fdf51da 100644 > --- a/block/bfq-iosched.c > +++ b/block/bfq-iosched.c > @@ -2405,7 +2405,7 @@ static void bfq_requests_merged(struct request_queue *q, struct request *rq, > *next_bfqq = bfq_init_rq(next); > > if (!bfqq) > - return; > + goto remove; > > /* > * If next and rq belong to the same bfq_queue and next is older > @@ -2428,6 +2428,14 @@ static void bfq_requests_merged(struct request_queue *q, struct request *rq, > bfqq->next_rq = rq; > > bfqg_stats_update_io_merged(bfqq_group(bfqq), next->cmd_flags); > +remove: > + /* Merged request may be in the IO scheduler. Remove it. */ > + if (!RB_EMPTY_NODE(&next->rb_node)) { > + bfq_remove_request(next->q, next); > + if (next_bfqq) > + bfqg_stats_update_io_remove(bfqq_group(next_bfqq), > + next->cmd_flags); > + } > } > > /* Must be called with bfqq != NULL */ > @@ -6376,6 +6384,7 @@ static void bfq_finish_requeue_request(struct request *rq) > { > struct bfq_queue *bfqq = RQ_BFQQ(rq); > struct bfq_data *bfqd; > + unsigned long flags; > > /* > * rq either is not associated with any icq, or is an already > @@ -6393,39 +6402,15 @@ static void bfq_finish_requeue_request(struct request *rq) > rq->io_start_time_ns, > rq->cmd_flags); > > + spin_lock_irqsave(&bfqd->lock, flags); > if (likely(rq->rq_flags & RQF_STARTED)) { > - unsigned long flags; > - > - spin_lock_irqsave(&bfqd->lock, flags); > - > if (rq == bfqd->waited_rq) > bfq_update_inject_limit(bfqd, bfqq); > > bfq_completed_request(bfqq, bfqd); > - bfq_finish_requeue_request_body(bfqq); > - > - spin_unlock_irqrestore(&bfqd->lock, flags); > - } else { > - /* > - * Request rq may be still/already in the scheduler, > - * in which case we need to remove it (this should > - * never happen in case of requeue). And we cannot > - * defer such a check and removal, to avoid > - * inconsistencies in the time interval from the end > - * of this function to the start of the deferred work. > - * This situation seems to occur only in process > - * context, as a consequence of a merge. In the > - * current version of the code, this implies that the > - * lock is held. > - */ > - > - if (!RB_EMPTY_NODE(&rq->rb_node)) { > - bfq_remove_request(rq->q, rq); > - bfqg_stats_update_io_remove(bfqq_group(bfqq), > - rq->cmd_flags); > - } > - bfq_finish_requeue_request_body(bfqq); > } > + bfq_finish_requeue_request_body(bfqq); > + spin_unlock_irqrestore(&bfqd->lock, flags); > > /* > * Reset private fields. In case of a requeue, this allows > -- > 2.26.2 >