Skip to content

Commit b484a40

Browse files
Ming Leiaxboe
authored andcommitted
io_uring: fix IO hang in io_wq_put_and_exit from do_exit()
io_wq_put_and_exit() is called from do_exit(), but all FIXED_FILE requests in io_wq aren't canceled in io_uring_cancel_generic() called from do_exit(). Meantime io_wq IO code path may share resource with normal iopoll code path. So if any HIPRI request is submittd via io_wq, this request may not get resouce for moving on, given iopoll isn't possible in io_wq_put_and_exit(). The issue can be triggered when terminating 't/io_uring -n4 /dev/nullb0' with default null_blk parameters. Fix it by always cancelling all requests in io_wq by adding helper of io_uring_cancel_wq(), and this way is reasonable because io_wq destroying follows canceling requests immediately. Closes: https://lore.kernel.org/linux-block/3893581.1691785261@warthog.procyon.org.uk/ Reported-by: David Howells <dhowells@redhat.com> Cc: Chengming Zhou <zhouchengming@bytedance.com> Signed-off-by: Ming Lei <ming.lei@redhat.com> Link: https://lore.kernel.org/r/20230901134916.2415386-1-ming.lei@redhat.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent bd6fc5d commit b484a40

File tree

1 file changed

+32
-0
lines changed

1 file changed

+32
-0
lines changed

io_uring/io_uring.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3290,6 +3290,37 @@ static s64 tctx_inflight(struct io_uring_task *tctx, bool tracked)
32903290
return percpu_counter_sum(&tctx->inflight);
32913291
}
32923292

3293+
static void io_uring_cancel_wq(struct io_uring_task *tctx)
3294+
{
3295+
int ret;
3296+
3297+
if (!tctx->io_wq)
3298+
return;
3299+
3300+
/*
3301+
* FIXED_FILE request isn't tracked in do_exit(), and these
3302+
* requests may be submitted to our io_wq as iopoll, so have to
3303+
* cancel them before destroying io_wq for avoiding IO hang
3304+
*/
3305+
do {
3306+
struct io_tctx_node *node;
3307+
unsigned long index;
3308+
3309+
ret = 0;
3310+
xa_for_each(&tctx->xa, index, node) {
3311+
struct io_ring_ctx *ctx = node->ctx;
3312+
struct io_task_cancel cancel = { .task = current, .all = true, };
3313+
enum io_wq_cancel cret;
3314+
3315+
io_iopoll_try_reap_events(ctx);
3316+
cret = io_wq_cancel_cb(tctx->io_wq, io_cancel_task_cb,
3317+
&cancel, true);
3318+
ret |= (cret != IO_WQ_CANCEL_NOTFOUND);
3319+
cond_resched();
3320+
}
3321+
} while (ret);
3322+
}
3323+
32933324
/*
32943325
* Find any io_uring ctx that this task has registered or done IO on, and cancel
32953326
* requests. @sqd should be not-null IFF it's an SQPOLL thread cancellation.
@@ -3361,6 +3392,7 @@ __cold void io_uring_cancel_generic(bool cancel_all, struct io_sq_data *sqd)
33613392
finish_wait(&tctx->wait, &wait);
33623393
} while (1);
33633394

3395+
io_uring_cancel_wq(tctx);
33643396
io_uring_clean_tctx(tctx);
33653397
if (cancel_all) {
33663398
/*

0 commit comments

Comments
 (0)