Commit affa87db authored by Pavel Begunkov's avatar Pavel Begunkov Committed by Jens Axboe

io_uring: fix multi ctx cancellation

io_uring_try_cancel_requests() loops until there is nothing left to do
with the ring, however there might be several rings and they might have
dependencies between them, e.g. via poll requests.

Instead of cancelling rings one by one, try to cancel them all and only
then loop over if we still potenially some work to do.
Signed-off-by: default avatarPavel Begunkov <asml.silence@gmail.com>
Link: https://lore.kernel.org/r/8d491fe02d8ac4c77ff38061cf86b9a827e8845c.1655684496.git.asml.silence@gmail.comSigned-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent d9dee430
...@@ -132,7 +132,7 @@ struct io_defer_entry { ...@@ -132,7 +132,7 @@ struct io_defer_entry {
#define IO_DISARM_MASK (REQ_F_ARM_LTIMEOUT | REQ_F_LINK_TIMEOUT | REQ_F_FAIL) #define IO_DISARM_MASK (REQ_F_ARM_LTIMEOUT | REQ_F_LINK_TIMEOUT | REQ_F_FAIL)
#define IO_REQ_LINK_FLAGS (REQ_F_LINK | REQ_F_HARDLINK) #define IO_REQ_LINK_FLAGS (REQ_F_LINK | REQ_F_HARDLINK)
static void io_uring_try_cancel_requests(struct io_ring_ctx *ctx, static bool io_uring_try_cancel_requests(struct io_ring_ctx *ctx,
struct task_struct *task, struct task_struct *task,
bool cancel_all); bool cancel_all);
...@@ -2648,7 +2648,9 @@ static __cold void io_ring_exit_work(struct work_struct *work) ...@@ -2648,7 +2648,9 @@ static __cold void io_ring_exit_work(struct work_struct *work)
* as nobody else will be looking for them. * as nobody else will be looking for them.
*/ */
do { do {
io_uring_try_cancel_requests(ctx, NULL, true); while (io_uring_try_cancel_requests(ctx, NULL, true))
cond_resched();
if (ctx->sq_data) { if (ctx->sq_data) {
struct io_sq_data *sqd = ctx->sq_data; struct io_sq_data *sqd = ctx->sq_data;
struct task_struct *tsk; struct task_struct *tsk;
...@@ -2806,20 +2808,18 @@ static __cold bool io_uring_try_cancel_iowq(struct io_ring_ctx *ctx) ...@@ -2806,20 +2808,18 @@ static __cold bool io_uring_try_cancel_iowq(struct io_ring_ctx *ctx)
return ret; return ret;
} }
static __cold void io_uring_try_cancel_requests(struct io_ring_ctx *ctx, static __cold bool io_uring_try_cancel_requests(struct io_ring_ctx *ctx,
struct task_struct *task, struct task_struct *task,
bool cancel_all) bool cancel_all)
{ {
struct io_task_cancel cancel = { .task = task, .all = cancel_all, }; struct io_task_cancel cancel = { .task = task, .all = cancel_all, };
struct io_uring_task *tctx = task ? task->io_uring : NULL; struct io_uring_task *tctx = task ? task->io_uring : NULL;
enum io_wq_cancel cret;
bool ret = false;
/* failed during ring init, it couldn't have issued any requests */ /* failed during ring init, it couldn't have issued any requests */
if (!ctx->rings) if (!ctx->rings)
return; return false;
while (1) {
enum io_wq_cancel cret;
bool ret = false;
if (!task) { if (!task) {
ret |= io_uring_try_cancel_iowq(ctx); ret |= io_uring_try_cancel_iowq(ctx);
...@@ -2849,10 +2849,7 @@ static __cold void io_uring_try_cancel_requests(struct io_ring_ctx *ctx, ...@@ -2849,10 +2849,7 @@ static __cold void io_uring_try_cancel_requests(struct io_ring_ctx *ctx,
ret |= io_kill_timeouts(ctx, task, cancel_all); ret |= io_kill_timeouts(ctx, task, cancel_all);
if (task) if (task)
ret |= io_run_task_work(); ret |= io_run_task_work();
if (!ret) return ret;
break;
cond_resched();
}
} }
static s64 tctx_inflight(struct io_uring_task *tctx, bool tracked) static s64 tctx_inflight(struct io_uring_task *tctx, bool tracked)
...@@ -2882,6 +2879,8 @@ __cold void io_uring_cancel_generic(bool cancel_all, struct io_sq_data *sqd) ...@@ -2882,6 +2879,8 @@ __cold void io_uring_cancel_generic(bool cancel_all, struct io_sq_data *sqd)
atomic_inc(&tctx->in_idle); atomic_inc(&tctx->in_idle);
do { do {
bool loop = false;
io_uring_drop_tctx_refs(current); io_uring_drop_tctx_refs(current);
/* read completions before cancelations */ /* read completions before cancelations */
inflight = tctx_inflight(tctx, !cancel_all); inflight = tctx_inflight(tctx, !cancel_all);
...@@ -2896,15 +2895,21 @@ __cold void io_uring_cancel_generic(bool cancel_all, struct io_sq_data *sqd) ...@@ -2896,15 +2895,21 @@ __cold void io_uring_cancel_generic(bool cancel_all, struct io_sq_data *sqd)
/* sqpoll task will cancel all its requests */ /* sqpoll task will cancel all its requests */
if (node->ctx->sq_data) if (node->ctx->sq_data)
continue; continue;
io_uring_try_cancel_requests(node->ctx, current, loop |= io_uring_try_cancel_requests(node->ctx,
cancel_all); current, cancel_all);
} }
} else { } else {
list_for_each_entry(ctx, &sqd->ctx_list, sqd_list) list_for_each_entry(ctx, &sqd->ctx_list, sqd_list)
io_uring_try_cancel_requests(ctx, current, loop |= io_uring_try_cancel_requests(ctx,
current,
cancel_all); cancel_all);
} }
if (loop) {
cond_resched();
continue;
}
prepare_to_wait(&tctx->wait, &wait, TASK_INTERRUPTIBLE); prepare_to_wait(&tctx->wait, &wait, TASK_INTERRUPTIBLE);
io_run_task_work(); io_run_task_work();
io_uring_drop_tctx_refs(current); io_uring_drop_tctx_refs(current);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment