Skip to content

Commit 4bf9461

Browse files
committed
io_uring: allow IORING_OP_ASYNC_CANCEL with 'fd' key
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 <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 8e29da6 commit 4bf9461

File tree

2 files changed

+63
-7
lines changed

2 files changed

+63
-7
lines changed

fs/io_uring.c

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,7 @@ struct io_cancel {
587587
struct file *file;
588588
u64 addr;
589589
u32 flags;
590+
s32 fd;
590591
};
591592

592593
struct io_timeout {
@@ -992,7 +993,10 @@ struct io_defer_entry {
992993

993994
struct io_cancel_data {
994995
struct io_ring_ctx *ctx;
995-
u64 data;
996+
union {
997+
u64 data;
998+
struct file *file;
999+
};
9961000
u32 flags;
9971001
int seq;
9981002
};
@@ -6332,6 +6336,29 @@ static struct io_kiocb *io_poll_find(struct io_ring_ctx *ctx, bool poll_only,
63326336
return NULL;
63336337
}
63346338

6339+
static struct io_kiocb *io_poll_file_find(struct io_ring_ctx *ctx,
6340+
struct io_cancel_data *cd)
6341+
__must_hold(&ctx->completion_lock)
6342+
{
6343+
struct io_kiocb *req;
6344+
int i;
6345+
6346+
for (i = 0; i < (1U << ctx->cancel_hash_bits); i++) {
6347+
struct hlist_head *list;
6348+
6349+
list = &ctx->cancel_hash[i];
6350+
hlist_for_each_entry(req, list, hash_node) {
6351+
if (req->file != cd->file)
6352+
continue;
6353+
if (cd->seq == req->work.cancel_seq)
6354+
continue;
6355+
req->work.cancel_seq = cd->seq;
6356+
return req;
6357+
}
6358+
}
6359+
return NULL;
6360+
}
6361+
63356362
static bool io_poll_disarm(struct io_kiocb *req)
63366363
__must_hold(&ctx->completion_lock)
63376364
{
@@ -6345,8 +6372,12 @@ static bool io_poll_disarm(struct io_kiocb *req)
63456372
static int io_poll_cancel(struct io_ring_ctx *ctx, struct io_cancel_data *cd)
63466373
__must_hold(&ctx->completion_lock)
63476374
{
6348-
struct io_kiocb *req = io_poll_find(ctx, false, cd);
6375+
struct io_kiocb *req;
63496376

6377+
if (cd->flags & IORING_ASYNC_CANCEL_FD)
6378+
req = io_poll_file_find(ctx, cd);
6379+
else
6380+
req = io_poll_find(ctx, false, cd);
63506381
if (!req)
63516382
return -ENOENT;
63526383
io_poll_cancel_req(req);
@@ -6796,8 +6827,13 @@ static bool io_cancel_cb(struct io_wq_work *work, void *data)
67966827

67976828
if (req->ctx != cd->ctx)
67986829
return false;
6799-
if (req->cqe.user_data != cd->data)
6800-
return false;
6830+
if (cd->flags & IORING_ASYNC_CANCEL_FD) {
6831+
if (req->file != cd->file)
6832+
return false;
6833+
} else {
6834+
if (req->cqe.user_data != cd->data)
6835+
return false;
6836+
}
68016837
if (cd->flags & IORING_ASYNC_CANCEL_ALL) {
68026838
if (cd->seq == req->work.cancel_seq)
68036839
return false;
@@ -6851,7 +6887,8 @@ static int io_try_cancel(struct io_kiocb *req, struct io_cancel_data *cd)
68516887
ret = io_poll_cancel(ctx, cd);
68526888
if (ret != -ENOENT)
68536889
goto out;
6854-
ret = io_timeout_cancel(ctx, cd);
6890+
if (!(cd->flags & IORING_ASYNC_CANCEL_FD))
6891+
ret = io_timeout_cancel(ctx, cd);
68556892
out:
68566893
spin_unlock(&ctx->completion_lock);
68576894
return ret;
@@ -6862,15 +6899,17 @@ static int io_async_cancel_prep(struct io_kiocb *req,
68626899
{
68636900
if (unlikely(req->ctx->flags & IORING_SETUP_IOPOLL))
68646901
return -EINVAL;
6865-
if (unlikely(req->flags & (REQ_F_FIXED_FILE | REQ_F_BUFFER_SELECT)))
6902+
if (unlikely(req->flags & REQ_F_BUFFER_SELECT))
68666903
return -EINVAL;
68676904
if (sqe->ioprio || sqe->off || sqe->len || sqe->splice_fd_in)
68686905
return -EINVAL;
68696906

68706907
req->cancel.addr = READ_ONCE(sqe->addr);
68716908
req->cancel.flags = READ_ONCE(sqe->cancel_flags);
6872-
if (req->cancel.flags & ~IORING_ASYNC_CANCEL_ALL)
6909+
if (req->cancel.flags & ~(IORING_ASYNC_CANCEL_ALL|IORING_ASYNC_CANCEL_FD))
68736910
return -EINVAL;
6911+
if (req->cancel.flags & IORING_ASYNC_CANCEL_FD)
6912+
req->cancel.fd = READ_ONCE(sqe->fd);
68746913

68756914
return 0;
68766915
}
@@ -6919,7 +6958,21 @@ static int io_async_cancel(struct io_kiocb *req, unsigned int issue_flags)
69196958
};
69206959
int ret;
69216960

6961+
if (cd.flags & IORING_ASYNC_CANCEL_FD) {
6962+
if (req->flags & REQ_F_FIXED_FILE)
6963+
req->file = io_file_get_fixed(req, req->cancel.fd,
6964+
issue_flags);
6965+
else
6966+
req->file = io_file_get_normal(req, req->cancel.fd);
6967+
if (!req->file) {
6968+
ret = -EBADF;
6969+
goto done;
6970+
}
6971+
cd.file = req->file;
6972+
}
6973+
69226974
ret = __io_async_cancel(&cd, req, issue_flags);
6975+
done:
69236976
if (ret < 0)
69246977
req_set_fail(req);
69256978
io_req_complete_post(req, ret, 0);

include/uapi/linux/io_uring.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,8 +191,11 @@ enum {
191191
* ASYNC_CANCEL flags.
192192
*
193193
* IORING_ASYNC_CANCEL_ALL Cancel all requests that match the given key
194+
* IORING_ASYNC_CANCEL_FD Key off 'fd' for cancelation rather than the
195+
* request 'user_data'
194196
*/
195197
#define IORING_ASYNC_CANCEL_ALL (1U << 0)
198+
#define IORING_ASYNC_CANCEL_FD (1U << 1)
196199

197200
/*
198201
* IO completion data structure (Completion Queue Entry)

0 commit comments

Comments
 (0)