]> www.infradead.org Git - users/willy/xarray.git/commitdiff
io_uring: tighten task exit cancellations
authorPavel Begunkov <asml.silence@gmail.com>
Wed, 24 Jul 2024 11:16:16 +0000 (12:16 +0100)
committerJens Axboe <axboe@kernel.dk>
Wed, 24 Jul 2024 14:01:49 +0000 (08:01 -0600)
io_uring_cancel_generic() should retry if any state changes like a
request is completed, however in case of a task exit it only goes for
another loop and avoids schedule() if any tracked (i.e. REQ_F_INFLIGHT)
request got completed.

Let's assume we have a non-tracked request executing in iowq and a
tracked request linked to it. Let's also assume
io_uring_cancel_generic() fails to find and cancel the request, i.e.
via io_run_local_work(), which may happen as io-wq has gaps.
Next, the request logically completes, io-wq still hold a ref but queues
it for completion via tw, which happens in
io_uring_try_cancel_requests(). After, right before prepare_to_wait()
io-wq puts the request, grabs the linked one and tries executes it, e.g.
arms polling. Finally the cancellation loop calls prepare_to_wait(),
there are no tw to run, no tracked request was completed, so the
tctx_inflight() check passes and the task is put to indefinite sleep.

Cc: stable@vger.kernel.org
Fixes: 3f48cf18f886c ("io_uring: unify files and task cancel")
Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
Link: https://lore.kernel.org/r/acac7311f4e02ce3c43293f8f1fda9c705d158f1.1721819383.git.asml.silence@gmail.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
io_uring/io_uring.c

index 8e6faa942a6f9de66b2a859771606d5855a68497..10c409e56241e7009d0ac3b22b35357189ad2a30 100644 (file)
@@ -3031,8 +3031,11 @@ __cold void io_uring_cancel_generic(bool cancel_all, struct io_sq_data *sqd)
                bool loop = false;
 
                io_uring_drop_tctx_refs(current);
+               if (!tctx_inflight(tctx, !cancel_all))
+                       break;
+
                /* read completions before cancelations */
-               inflight = tctx_inflight(tctx, !cancel_all);
+               inflight = tctx_inflight(tctx, false);
                if (!inflight)
                        break;