Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
d06fa23
io_uring/rw: mark readv/writev as vectored in the opcode definition
axboe Sep 11, 2023
19b28be
io_uring/rw: add support for IORING_OP_READ_MULTISHOT
axboe Sep 11, 2023
1529c45
exit: abstract out should_wake helper for child_wait_callback()
axboe Jul 11, 2023
756ed24
exit: move core of do_wait() into helper
axboe Jul 11, 2023
ee6c224
exit: add kernel_waitid_prepare() helper
axboe Jul 11, 2023
69b2ebb
exit: add internal include file with helpers
axboe Jul 11, 2023
b7c71c3
io_uring: add IORING_OP_WAITID support
axboe Jul 10, 2023
ea74706
io_uring: retain top 8bits of uring_cmd flags for kernel internal use
Sep 28, 2023
4edc681
io_uring: cancelable uring_cmd
Sep 28, 2023
715193e
io_uring/waitid: clear waitid info before copying it to userspace
Yeonba0918 May 16, 2026
61e915b
io_uring/rw: don't attempt to allocate async data if opcode doesn't n…
axboe Nov 3, 2023
d982070
io_uring: do not allow multishot read to set addr or len
DylanZA Nov 6, 2023
e2a4136
io_uring: do not clamp read length for multishot read
DylanZA Nov 6, 2023
21c5f27
io_uring/rw: ensure poll based multishot read retries appropriately
axboe Jan 27, 2024
d2cdef9
io_uring: fix mshot read defer taskrun cqe posting
isilence Mar 6, 2024
d09f49d
io_uring/rw: return IOU_ISSUE_SKIP_COMPLETE for multishot retry
axboe Mar 12, 2024
d6f6152
io_uring/waitid: always remove waitid entry for cancel all
axboe Mar 15, 2024
26cc028
io_uring/rw: don't allow multishot reads without NOWAIT support
axboe Apr 1, 2024
96c3274
io_uring/waitid: always prune wait queue entry in io_waitid_wait()
axboe Oct 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions include/linux/io_uring.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,15 @@ enum io_uring_cmd_flags {
IO_URING_F_SQE128 = (1 << 8),
IO_URING_F_CQE32 = (1 << 9),
IO_URING_F_IOPOLL = (1 << 10),

/* set when uring wants to cancel a previously issued command */
IO_URING_F_CANCEL = (1 << 11),
};

/* only top 8 bits of sqe->uring_cmd_flags for kernel internal use */
#define IORING_URING_CMD_CANCELABLE (1U << 30)
#define IORING_URING_CMD_POLLED (1U << 31)

struct io_uring_cmd {
struct file *file;
const struct io_uring_sqe *sqe;
Expand Down Expand Up @@ -80,6 +87,9 @@ static inline void io_uring_free(struct task_struct *tsk)
}
int io_uring_cmd_sock(struct io_uring_cmd *cmd, unsigned int issue_flags);
bool io_is_uring_fops(struct file *file);
void io_uring_cmd_mark_cancelable(struct io_uring_cmd *cmd,
unsigned int issue_flags);
struct task_struct *io_uring_cmd_get_task(struct io_uring_cmd *cmd);
#else
static inline int io_uring_cmd_import_fixed(u64 ubuf, unsigned long len, int rw,
struct iov_iter *iter, void *ioucmd)
Expand Down Expand Up @@ -120,6 +130,15 @@ static inline bool io_is_uring_fops(struct file *file)
{
return false;
}

static inline void io_uring_cmd_mark_cancelable(struct io_uring_cmd *cmd,
unsigned int issue_flags)
{
}
static inline struct task_struct *io_uring_cmd_get_task(struct io_uring_cmd *cmd)
{
return NULL;
}
#endif

#endif
8 changes: 8 additions & 0 deletions include/linux/io_uring_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,12 @@ struct io_ring_ctx {
*/
struct io_wq_work_list iopoll_list;
bool poll_multi_queue;

/*
* Any cancelable uring_cmd is added to this list in
* ->uring_cmd() by io_uring_cmd_insert_cancelable()
*/
struct hlist_head cancelable_uring_cmd;
} ____cacheline_aligned_in_smp;

struct {
Expand Down Expand Up @@ -312,6 +318,8 @@ struct io_ring_ctx {
struct list_head cq_overflow_list;
struct io_hash_table cancel_table;

struct hlist_head waitid_list;

const struct cred *sq_creds; /* cred used for __io_sq_thread() */
struct io_sq_data *sq_data; /* if using sq thread polling */

Expand Down
8 changes: 5 additions & 3 deletions include/uapi/linux/io_uring.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ struct io_uring_sqe {
__u32 xattr_flags;
__u32 msg_ring_flags;
__u32 uring_cmd_flags;
__u32 waitid_flags;
};
__u64 user_data; /* data to be passed back at completion time */
/* pack this to avoid bogus arm OABI complaints */
Expand Down Expand Up @@ -240,19 +241,20 @@ enum io_uring_op {
IORING_OP_URING_CMD,
IORING_OP_SEND_ZC,
IORING_OP_SENDMSG_ZC,
IORING_OP_READ_MULTISHOT,
IORING_OP_WAITID,

/* this goes last, obviously */
IORING_OP_LAST,
};

/*
* sqe->uring_cmd_flags
* sqe->uring_cmd_flags top 8bits aren't available for userspace
* IORING_URING_CMD_FIXED use registered buffer; pass this flag
* along with setting sqe->buf_index.
* IORING_URING_CMD_POLLED driver use only
*/
#define IORING_URING_CMD_FIXED (1U << 0)
#define IORING_URING_CMD_POLLED (1U << 31)
#define IORING_URING_CMD_MASK IORING_URING_CMD_FIXED


/*
Expand Down
3 changes: 2 additions & 1 deletion io_uring/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ obj-$(CONFIG_IO_URING) += io_uring.o xattr.o nop.o fs.o splice.o \
openclose.o uring_cmd.o epoll.o \
statx.o net.o msg_ring.o timeout.o \
sqpoll.o fdinfo.o tctx.o poll.o \
cancel.o kbuf.o rsrc.o rw.o opdef.o notif.o
cancel.o kbuf.o rsrc.o rw.o opdef.o \
notif.o waitid.o
obj-$(CONFIG_IO_WQ) += io-wq.o
5 changes: 5 additions & 0 deletions io_uring/cancel.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "tctx.h"
#include "poll.h"
#include "timeout.h"
#include "waitid.h"
#include "cancel.h"

struct io_cancel {
Expand Down Expand Up @@ -119,6 +120,10 @@ int io_try_cancel(struct io_uring_task *tctx, struct io_cancel_data *cd,
if (ret != -ENOENT)
return ret;

ret = io_waitid_cancel(ctx, cd, issue_flags);
if (ret != -ENOENT)
return ret;

spin_lock(&ctx->completion_lock);
if (!(cd->flags & IORING_ASYNC_CANCEL_FD))
ret = io_timeout_cancel(ctx, cd);
Expand Down
39 changes: 39 additions & 0 deletions io_uring/io_uring.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
#include "cancel.h"
#include "net.h"
#include "notif.h"
#include "waitid.h"

#include "timeout.h"
#include "poll.h"
Expand Down Expand Up @@ -336,8 +337,10 @@ static __cold struct io_ring_ctx *io_ring_ctx_alloc(struct io_uring_params *p)
INIT_LIST_HEAD(&ctx->tctx_list);
ctx->submit_state.free_list.next = NULL;
INIT_WQ_LIST(&ctx->locked_free_list);
INIT_HLIST_HEAD(&ctx->waitid_list);
INIT_DELAYED_WORK(&ctx->fallback_work, io_fallback_req_func);
INIT_WQ_LIST(&ctx->submit_state.compl_reqs);
INIT_HLIST_HEAD(&ctx->cancelable_uring_cmd);
return ctx;
err:
kfree(ctx->cancel_table.hbs);
Expand Down Expand Up @@ -3368,6 +3371,37 @@ static __cold bool io_uring_try_cancel_iowq(struct io_ring_ctx *ctx)
return ret;
}

static bool io_uring_try_cancel_uring_cmd(struct io_ring_ctx *ctx,
struct task_struct *task, bool cancel_all)
{
struct hlist_node *tmp;
struct io_kiocb *req;
bool ret = false;

lockdep_assert_held(&ctx->uring_lock);

hlist_for_each_entry_safe(req, tmp, &ctx->cancelable_uring_cmd,
hash_node) {
struct io_uring_cmd *cmd = io_kiocb_to_cmd(req,
struct io_uring_cmd);
struct file *file = req->file;

if (!cancel_all && req->task != task)
continue;

if (cmd->flags & IORING_URING_CMD_CANCELABLE) {
/* ->sqe isn't available if no async data */
if (!req_has_async_data(req))
cmd->sqe = NULL;
file->f_op->uring_cmd(cmd, IO_URING_F_CANCEL);
ret = true;
}
}
io_submit_flush_completions(ctx);

return ret;
}

static __cold bool io_uring_try_cancel_requests(struct io_ring_ctx *ctx,
struct task_struct *task,
bool cancel_all)
Expand Down Expand Up @@ -3415,6 +3449,8 @@ static __cold bool io_uring_try_cancel_requests(struct io_ring_ctx *ctx,
ret |= io_cancel_defer_files(ctx, task, cancel_all);
mutex_lock(&ctx->uring_lock);
ret |= io_poll_remove_all(ctx, task, cancel_all);
ret |= io_waitid_remove_all(ctx, task, cancel_all);
ret |= io_uring_try_cancel_uring_cmd(ctx, task, cancel_all);
mutex_unlock(&ctx->uring_lock);
ret |= io_kill_timeouts(ctx, task, cancel_all);
if (task)
Expand Down Expand Up @@ -4783,6 +4819,9 @@ static int __init io_uring_init(void)

BUILD_BUG_ON(sizeof(atomic_t) != sizeof(u32));

/* top 8bits are for internal use */
BUILD_BUG_ON((IORING_URING_CMD_MASK & 0xff000000) != 0);

io_uring_optable_init();

/*
Expand Down
24 changes: 23 additions & 1 deletion io_uring/opdef.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "poll.h"
#include "cancel.h"
#include "rw.h"
#include "waitid.h"

static int io_no_issue(struct io_kiocb *req, unsigned int issue_flags)
{
Expand Down Expand Up @@ -63,6 +64,7 @@ const struct io_issue_def io_issue_defs[] = {
.ioprio = 1,
.iopoll = 1,
.iopoll_queue = 1,
.vectored = 1,
.prep = io_prep_rw,
.issue = io_read,
},
Expand All @@ -76,6 +78,7 @@ const struct io_issue_def io_issue_defs[] = {
.ioprio = 1,
.iopoll = 1,
.iopoll_queue = 1,
.vectored = 1,
.prep = io_prep_rw,
.issue = io_write,
},
Expand Down Expand Up @@ -429,9 +432,21 @@ const struct io_issue_def io_issue_defs[] = {
.prep = io_eopnotsupp_prep,
#endif
},
[IORING_OP_READ_MULTISHOT] = {
.needs_file = 1,
.unbound_nonreg_file = 1,
.pollin = 1,
.buffer_select = 1,
.audit_skip = 1,
.prep = io_read_mshot_prep,
.issue = io_read_mshot,
},
[IORING_OP_WAITID] = {
.prep = io_waitid_prep,
.issue = io_waitid,
},
};


const struct io_cold_def io_cold_defs[] = {
[IORING_OP_NOP] = {
.name = "NOP",
Expand Down Expand Up @@ -649,6 +664,13 @@ const struct io_cold_def io_cold_defs[] = {
.fail = io_sendrecv_fail,
#endif
},
[IORING_OP_READ_MULTISHOT] = {
.name = "READ_MULTISHOT",
},
[IORING_OP_WAITID] = {
.name = "WAITID",
.async_size = sizeof(struct io_waitid_async),
},
};

const char *io_uring_get_opcode(u8 opcode)
Expand Down
2 changes: 2 additions & 0 deletions io_uring/opdef.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ struct io_issue_def {
unsigned iopoll_queue : 1;
/* opcode specific path will handle ->async_data allocation if needed */
unsigned manual_alloc : 1;
/* vectored opcode, set if 1) vectored, and 2) handler needs to know */
unsigned vectored : 1;

int (*issue)(struct io_kiocb *, unsigned int);
int (*prep)(struct io_kiocb *, const struct io_uring_sqe *);
Expand Down
9 changes: 9 additions & 0 deletions io_uring/poll.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ struct async_poll {
struct io_poll *double_poll;
};

/*
* Must only be called inside issue_flags & IO_URING_F_MULTISHOT, or
* potentially other cases where we already "own" this poll request.
*/
static inline void io_poll_multishot_retry(struct io_kiocb *req)
{
atomic_inc(&req->poll_refs);
}

int io_poll_add_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
int io_poll_add(struct io_kiocb *req, unsigned int issue_flags);

Expand Down
Loading
Loading