Currently sqe->addr must contain the user_data of the request being canceled. Introduce the IORING_ASYNC_CANCEL_FD flag, which tells the kernel that we're keying off the file fd instead for cancelation. This allows canceling any request that a) uses a file, and b) was assigned the file based on the value being passed in. Signed-off-by: Jens Axboe <axboe@xxxxxxxxx> --- fs/io_uring.c | 58 +++++++++++++++++++++++++++++------ include/uapi/linux/io_uring.h | 8 +++++ 2 files changed, 56 insertions(+), 10 deletions(-) diff --git a/fs/io_uring.c b/fs/io_uring.c index 0ef8401b6552..c86a92a975b7 100644 --- a/fs/io_uring.c +++ b/fs/io_uring.c @@ -567,7 +567,8 @@ struct io_sync { struct io_cancel { struct file *file; - u64 addr; + u64 data; + u32 flags; }; struct io_timeout { @@ -6306,6 +6307,25 @@ static struct io_kiocb *io_poll_find(struct io_ring_ctx *ctx, __u64 sqe_addr, return NULL; } +static struct io_kiocb *io_poll_fd_find(struct io_ring_ctx *ctx, int fd) + __must_hold(&ctx->completion_lock) +{ + struct io_kiocb *req; + int i; + + for (i = 0; i < (1U << ctx->cancel_hash_bits); i++) { + struct hlist_head *list; + + list = &ctx->cancel_hash[i]; + hlist_for_each_entry(req, list, hash_node) { + if (!req->file || fd != req->cqe.fd) + continue; + return req; + } + } + return NULL; +} + static bool io_poll_disarm(struct io_kiocb *req) __must_hold(&ctx->completion_lock) { @@ -6319,13 +6339,18 @@ static bool io_poll_disarm(struct io_kiocb *req) struct io_cancel_data { struct io_ring_ctx *ctx; u64 data; + unsigned int flags; }; static int io_poll_cancel(struct io_ring_ctx *ctx, struct io_cancel_data *cd) __must_hold(&ctx->completion_lock) { - struct io_kiocb *req = io_poll_find(ctx, cd->data, false); + struct io_kiocb *req; + if (cd->flags & IORING_ASYNC_CANCEL_FD) + req = io_poll_fd_find(ctx, cd->data); + else + req = io_poll_find(ctx, cd->data, false); if (!req) return -ENOENT; io_poll_cancel_req(req); @@ -6762,7 +6787,11 @@ static bool io_cancel_cb(struct io_wq_work *work, void *data) struct io_kiocb *req = container_of(work, struct io_kiocb, work); struct io_cancel_data *cd = data; - return req->ctx == cd->ctx && req->cqe.user_data == cd->data; + if (req->ctx != cd->ctx) + return false; + if (cd->flags & IORING_ASYNC_CANCEL_FD) + return req->file && cd->data == req->cqe.fd; + return req->cqe.user_data == cd->data; } static int io_async_cancel_one(struct io_uring_task *tctx, @@ -6811,9 +6840,11 @@ static int io_try_cancel_userdata(struct io_kiocb *req, if (ret != -ENOENT) goto out; - spin_lock_irq(&ctx->timeout_lock); - ret = io_timeout_cancel(ctx, cd->data); - spin_unlock_irq(&ctx->timeout_lock); + if (!(cd->flags & IORING_ASYNC_CANCEL_FD)) { + spin_lock_irq(&ctx->timeout_lock); + ret = io_timeout_cancel(ctx, cd->data); + spin_unlock_irq(&ctx->timeout_lock); + } out: spin_unlock(&ctx->completion_lock); return ret; @@ -6826,11 +6857,17 @@ static int io_async_cancel_prep(struct io_kiocb *req, return -EINVAL; if (unlikely(req->flags & (REQ_F_FIXED_FILE | REQ_F_BUFFER_SELECT))) return -EINVAL; - if (sqe->ioprio || sqe->off || sqe->len || sqe->cancel_flags || - sqe->splice_fd_in) + if (sqe->ioprio || sqe->off || sqe->len || sqe->splice_fd_in) + return -EINVAL; + + req->cancel.data = READ_ONCE(sqe->addr); + req->cancel.flags = READ_ONCE(sqe->cancel_flags); + if (req->cancel.flags & ~IORING_ASYNC_CANCEL_FD) + return -EINVAL; + else if ((req->cancel.flags & IORING_ASYNC_CANCEL_FD) && + req->cancel.data > INT_MAX) return -EINVAL; - req->cancel.addr = READ_ONCE(sqe->addr); return 0; } @@ -6839,7 +6876,8 @@ static int io_async_cancel(struct io_kiocb *req, unsigned int issue_flags) struct io_ring_ctx *ctx = req->ctx; struct io_cancel_data cd = { .ctx = ctx, - .data = req->cancel.addr, + .data = req->cancel.data, + .flags = req->cancel.flags, }; struct io_tctx_node *node; int ret; diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h index 1845cf7c80ba..806c473dde9f 100644 --- a/include/uapi/linux/io_uring.h +++ b/include/uapi/linux/io_uring.h @@ -187,6 +187,14 @@ enum { #define IORING_POLL_UPDATE_EVENTS (1U << 1) #define IORING_POLL_UPDATE_USER_DATA (1U << 2) +/* + * ASYNC_CANCEL flags. + * + * IORING_ASYNC_CANCEL_FD Key off 'fd' for cancelation rather than the + * request 'user_data' + */ +#define IORING_ASYNC_CANCEL_FD (1U << 0) + /* * IO completion data structure (Completion Queue Entry) */ -- 2.35.1