io_uring: find and cancel head link async work on files exit
authorJens Axboe <axboe@kernel.dk>
Sun, 16 Aug 2020 15:23:05 +0000 (08:23 -0700)
committerJens Axboe <axboe@kernel.dk>
Sun, 16 Aug 2020 21:36:31 +0000 (14:36 -0700)
Commit f254ac04c874 ("io_uring: enable lookup of links holding inflight files")
only handled 2 out of the three head link cases we have, we also need to
lookup and cancel work that is blocked in io-wq if that work has a link
that's holding a reference to the files structure.

Put the "cancel head links that hold this request pending" logic into
io_attempt_cancel(), which will to through the motions of finding and
canceling head links that hold the current inflight files stable request
pending.

Cc: stable@vger.kernel.org
Reported-by: Pavel Begunkov <asml.silence@gmail.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
fs/io_uring.c

index dc506b7..346a3eb 100644 (file)
@@ -8063,6 +8063,33 @@ static bool io_timeout_remove_link(struct io_ring_ctx *ctx,
        return found;
 }
 
+static bool io_cancel_link_cb(struct io_wq_work *work, void *data)
+{
+       return io_match_link(container_of(work, struct io_kiocb, work), data);
+}
+
+static void io_attempt_cancel(struct io_ring_ctx *ctx, struct io_kiocb *req)
+{
+       enum io_wq_cancel cret;
+
+       /* cancel this particular work, if it's running */
+       cret = io_wq_cancel_work(ctx->io_wq, &req->work);
+       if (cret != IO_WQ_CANCEL_NOTFOUND)
+               return;
+
+       /* find links that hold this pending, cancel those */
+       cret = io_wq_cancel_cb(ctx->io_wq, io_cancel_link_cb, req, true);
+       if (cret != IO_WQ_CANCEL_NOTFOUND)
+               return;
+
+       /* if we have a poll link holding this pending, cancel that */
+       if (io_poll_remove_link(ctx, req))
+               return;
+
+       /* final option, timeout link is holding this req pending */
+       io_timeout_remove_link(ctx, req);
+}
+
 static void io_uring_cancel_files(struct io_ring_ctx *ctx,
                                  struct files_struct *files)
 {
@@ -8116,10 +8143,8 @@ static void io_uring_cancel_files(struct io_ring_ctx *ctx,
                                continue;
                        }
                } else {
-                       io_wq_cancel_work(ctx->io_wq, &cancel_req->work);
-                       /* could be a link, check and remove if it is */
-                       if (!io_poll_remove_link(ctx, cancel_req))
-                               io_timeout_remove_link(ctx, cancel_req);
+                       /* cancel this request, or head link requests */
+                       io_attempt_cancel(ctx, cancel_req);
                        io_put_req(cancel_req);
                }