Skip to content

Commit

Permalink
blk-mq: release scheduler resource when request completes
Browse files Browse the repository at this point in the history
Chuck reported [1] an IO hang problem on NFS exports that reside on SATA
devices and bisected to commit 615939a ("blk-mq: defer to the normal
submission path for post-flush requests").

We analysed the IO hang problem, found there are two postflush requests
waiting for each other.

The first postflush request completed the REQ_FSEQ_DATA sequence, so go to
the REQ_FSEQ_POSTFLUSH sequence and added in the flush pending list, but
failed to blk_kick_flush() because of the second postflush request which
is inflight waiting in scheduler queue.

The second postflush waiting in scheduler queue can't be dispatched because
the first postflush hasn't released scheduler resource even though it has
completed by itself.

Fix it by releasing scheduler resource when the first postflush request
completed, so the second postflush can be dispatched and completed, then
make blk_kick_flush() succeed.

While at it, remove the check for e->ops.finish_request, as all
schedulers set that. Reaffirm this requirement by adding a WARN_ON_ONCE()
at scheduler registration time, just like we do for insert_requests and
dispatch_request.

[1] https://lore.kernel.org/all/[email protected]/

Link: https://lore.kernel.org/linux-block/[email protected]/
Reported-by: kernel test robot <[email protected]>
Closes: https://lore.kernel.org/oe-lkp/[email protected]
Fixes: 615939a ("blk-mq: defer to the normal submission path for post-flush requests")
Reported-by: Chuck Lever <[email protected]>
Signed-off-by: Chengming Zhou <[email protected]>
Tested-by: Chuck Lever <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
[axboe: folded in incremental fix and added tags]
Signed-off-by: Jens Axboe <[email protected]>
  • Loading branch information
Chengming Zhou authored and axboe committed Aug 19, 2023
1 parent c984ff1 commit e5c0ca1
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 3 deletions.
23 changes: 20 additions & 3 deletions block/blk-mq.c
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,21 @@ struct request *blk_mq_alloc_request_hctx(struct request_queue *q,
}
EXPORT_SYMBOL_GPL(blk_mq_alloc_request_hctx);

static void blk_mq_finish_request(struct request *rq)
{
struct request_queue *q = rq->q;

if (rq->rq_flags & RQF_USE_SCHED) {
q->elevator->type->ops.finish_request(rq);
/*
* For postflush request that may need to be
* completed twice, we should clear this flag
* to avoid double finish_request() on the rq.
*/
rq->rq_flags &= ~RQF_USE_SCHED;
}
}

static void __blk_mq_free_request(struct request *rq)
{
struct request_queue *q = rq->q;
Expand All @@ -707,9 +722,7 @@ void blk_mq_free_request(struct request *rq)
{
struct request_queue *q = rq->q;

if ((rq->rq_flags & RQF_USE_SCHED) &&
q->elevator->type->ops.finish_request)
q->elevator->type->ops.finish_request(rq);
blk_mq_finish_request(rq);

if (unlikely(laptop_mode && !blk_rq_is_passthrough(rq)))
laptop_io_completion(q->disk->bdi);
Expand Down Expand Up @@ -1020,6 +1033,8 @@ inline void __blk_mq_end_request(struct request *rq, blk_status_t error)
if (blk_mq_need_time_stamp(rq))
__blk_mq_end_request_acct(rq, ktime_get_ns());

blk_mq_finish_request(rq);

if (rq->end_io) {
rq_qos_done(rq->q, rq);
if (rq->end_io(rq, error) == RQ_END_IO_FREE)
Expand Down Expand Up @@ -1074,6 +1089,8 @@ void blk_mq_end_request_batch(struct io_comp_batch *iob)
if (iob->need_ts)
__blk_mq_end_request_acct(rq, now);

blk_mq_finish_request(rq);

rq_qos_done(rq->q, rq);

/*
Expand Down
3 changes: 3 additions & 0 deletions block/elevator.c
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,9 @@ void elv_unregister_queue(struct request_queue *q)

int elv_register(struct elevator_type *e)
{
/* finish request is mandatory */
if (WARN_ON_ONCE(!e->ops.finish_request))
return -EINVAL;
/* insert_requests and dispatch_request are mandatory */
if (WARN_ON_ONCE(!e->ops.insert_requests || !e->ops.dispatch_request))
return -EINVAL;
Expand Down

0 comments on commit e5c0ca1

Please sign in to comment.