summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Axboe <axboe@kernel.dk>2021-07-23 11:53:54 -0600
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2021-08-08 09:06:56 +0200
commit989b27104a97642f6a1ed563ee32bec95a2552e2 (patch)
tree3a63da6bb0f4501b0a18f3afc887790eb7a27ad7
parentf7be9c72d1de9307a7fbc0c394996268d4fdc4e9 (diff)
io_uring: explicitly catch any illegal async queue attempt
[ Upstream commit 991468dcf198bb87f24da330676724a704912b47 ] Catch an illegal case to queue async from an unrelated task that got the ring fd passed to it. This should not be possible to hit, but better be proactive and catch it explicitly. io-wq is extended to check for early IO_WQ_WORK_CANCEL being set on a work item as well, so it can run the request through the normal cancelation path. Signed-off-by: Jens Axboe <axboe@kernel.dk> Signed-off-by: Sasha Levin <sashal@kernel.org>
-rw-r--r--fs/io-wq.c7
-rw-r--r--fs/io_uring.c11
2 files changed, 17 insertions, 1 deletions
diff --git a/fs/io-wq.c b/fs/io-wq.c
index 60f58efdb5f4..9efecdf025b9 100644
--- a/fs/io-wq.c
+++ b/fs/io-wq.c
@@ -736,7 +736,12 @@ static void io_wqe_enqueue(struct io_wqe *wqe, struct io_wq_work *work)
int work_flags;
unsigned long flags;
- if (test_bit(IO_WQ_BIT_EXIT, &wqe->wq->state)) {
+ /*
+ * If io-wq is exiting for this task, or if the request has explicitly
+ * been marked as one that should not get executed, cancel it here.
+ */
+ if (test_bit(IO_WQ_BIT_EXIT, &wqe->wq->state) ||
+ (work->flags & IO_WQ_WORK_CANCEL)) {
io_run_cancel(work, wqe);
return;
}
diff --git a/fs/io_uring.c b/fs/io_uring.c
index 86f609fa761c..32f3df13a812 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -1282,6 +1282,17 @@ static void io_queue_async_work(struct io_kiocb *req)
/* init ->work of the whole link before punting */
io_prep_async_link(req);
+
+ /*
+ * Not expected to happen, but if we do have a bug where this _can_
+ * happen, catch it here and ensure the request is marked as
+ * canceled. That will make io-wq go through the usual work cancel
+ * procedure rather than attempt to run this request (or create a new
+ * worker for it).
+ */
+ if (WARN_ON_ONCE(!same_thread_group(req->task, current)))
+ req->work.flags |= IO_WQ_WORK_CANCEL;
+
trace_io_uring_queue_async_work(ctx, io_wq_is_hashed(&req->work), req,
&req->work, req->flags);
io_wq_enqueue(tctx->io_wq, &req->work);