Merge tag 'for-6.18/io_uring-20250929' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux

Pull io_uring updates from Jens Axboe:

 - Store ring provided buffers locally for the users, rather than stuff
   them into struct io_kiocb.

   These types of buffers must always be fully consumed or recycled in
   the current context, and leaving them in struct io_kiocb is hence not
   a good ideas as that struct has a vastly different life time.

   Basically just an architecture cleanup that can help prevent issues
   with ring provided buffers in the future.

 - Support for mixed CQE sizes in the same ring.

   Before this change, a CQ ring either used the default 16b CQEs, or it
   was setup with 32b CQE using IORING_SETUP_CQE32. For use cases where
   a few 32b CQEs were needed, this caused everything else to use big
   CQEs. This is wasteful both in terms of memory usage, but also memory
   bandwidth for the posted CQEs.

   With IORING_SETUP_CQE_MIXED, applications may use request types that
   post both normal 16b and big 32b CQEs on the same ring.

 - Add helpers for async data management, to make it harder for opcode
   handlers to mess it up.

 - Add support for multishot for uring_cmd, which ublk can use. This
   helps improve efficiency, by providing a persistent request type that
   can trigger multiple CQEs.

 - Add initial support for ring feature querying.

   We had basic support for probe operations, but the API isn't great.
   Rather than expand that, add support for QUERY which is easily
   expandable and can cover a lot more cases than the existing probe
   support. This will help applications get a better idea of what
   operations are supported on a given host.

 - zcrx improvements from Pavel:
        - Improve refill entry alignment for better caching
        - Various cleanups, especially around deduplicating normal
          memory vs dmabuf setup.
        - Generalisation of the niov size (Patch 12). It's still hard
          coded to PAGE_SIZE on init, but will let the user to specify
          the rx buffer length on setup.
        - Syscall / synchronous bufer return. It'll be used as a slow
          fallback path for returning buffers when the refill queue is
          full. Useful for tolerating slight queue size misconfiguration
          or with inconsistent load.
        - Accounting more memory to cgroups.
        - Additional independent cleanups that will also be useful for
          mutli-area support.

 - Various fixes and cleanups

* tag 'for-6.18/io_uring-20250929' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux: (68 commits)
  io_uring/cmd: drop unused res2 param from io_uring_cmd_done()
  io_uring: fix nvme's 32b cqes on mixed cq
  io_uring/query: cap number of queries
  io_uring/query: prevent infinite loops
  io_uring/zcrx: account niov arrays to cgroup
  io_uring/zcrx: allow synchronous buffer return
  io_uring/zcrx: introduce io_parse_rqe()
  io_uring/zcrx: don't adjust free cache space
  io_uring/zcrx: use guards for the refill lock
  io_uring/zcrx: reduce netmem scope in refill
  io_uring/zcrx: protect netdev with pp_lock
  io_uring/zcrx: rename dma lock
  io_uring/zcrx: make niov size variable
  io_uring/zcrx: set sgt for umem area
  io_uring/zcrx: remove dmabuf_offset
  io_uring/zcrx: deduplicate area mapping
  io_uring/zcrx: pass ifq to io_zcrx_alloc_fallback()
  io_uring/zcrx: check all niovs filled with dma addresses
  io_uring/zcrx: move area reg checks into io_import_area
  io_uring/zcrx: don't pass slot to io_zcrx_create_area
  ...
This commit is contained in:
Linus Torvalds
2025-10-02 09:56:23 -07:00
37 changed files with 1001 additions and 452 deletions
+1 -1
View File
@@ -75,7 +75,7 @@ Create an io_uring instance with the following required setup flags::
IORING_SETUP_SINGLE_ISSUER
IORING_SETUP_DEFER_TASKRUN
IORING_SETUP_CQE32
IORING_SETUP_CQE32 or IORING_SETUP_CQE_MIXED
Create memory area
------------------
+1 -1
View File
@@ -776,7 +776,7 @@ static void blk_cmd_complete(struct io_uring_cmd *cmd, unsigned int issue_flags)
if (bic->res == -EAGAIN && bic->nowait)
io_uring_cmd_issue_blocking(cmd);
else
io_uring_cmd_done(cmd, bic->res, 0, issue_flags);
io_uring_cmd_done(cmd, bic->res, issue_flags);
}
static void bio_cmd_bio_end_io(struct bio *bio)
+3 -3
View File
@@ -1189,7 +1189,7 @@ static void ublk_complete_io_cmd(struct ublk_io *io, struct request *req,
struct io_uring_cmd *cmd = __ublk_prep_compl_io_cmd(io, req);
/* tell ublksrv one io request is coming */
io_uring_cmd_done(cmd, res, 0, issue_flags);
io_uring_cmd_done(cmd, res, issue_flags);
}
#define UBLK_REQUEUE_DELAY_MS 3
@@ -1873,7 +1873,7 @@ static void ublk_cancel_cmd(struct ublk_queue *ubq, unsigned tag,
spin_unlock(&ubq->cancel_lock);
if (!done)
io_uring_cmd_done(io->cmd, UBLK_IO_RES_ABORT, 0, issue_flags);
io_uring_cmd_done(io->cmd, UBLK_IO_RES_ABORT, issue_flags);
}
/*
@@ -2520,7 +2520,7 @@ static void ublk_ch_uring_cmd_cb(struct io_uring_cmd *cmd,
int ret = ublk_ch_uring_cmd_local(cmd, issue_flags);
if (ret != -EIOCBQUEUED)
io_uring_cmd_done(cmd, ret, 0, issue_flags);
io_uring_cmd_done(cmd, ret, issue_flags);
}
static int ublk_ch_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
+1 -1
View File
@@ -410,7 +410,7 @@ static void nvme_uring_task_cb(struct io_uring_cmd *ioucmd,
if (pdu->bio)
blk_rq_unmap_user(pdu->bio);
io_uring_cmd_done(ioucmd, pdu->status, pdu->result, issue_flags);
io_uring_cmd_done32(ioucmd, pdu->status, pdu->result, issue_flags);
}
static enum rq_end_io_ret nvme_uring_cmd_end_io(struct request *req,
+1 -1
View File
@@ -4695,7 +4695,7 @@ out:
btrfs_unlock_extent(io_tree, priv->start, priv->lockend, &priv->cached_state);
btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
io_uring_cmd_done(cmd, ret, 0, issue_flags);
io_uring_cmd_done(cmd, ret, issue_flags);
add_rchar(current, ret);
for (index = 0; index < priv->nr_pages; index++)
+4 -4
View File
@@ -351,7 +351,7 @@ static void fuse_uring_entry_teardown(struct fuse_ring_ent *ent)
spin_unlock(&queue->lock);
if (cmd)
io_uring_cmd_done(cmd, -ENOTCONN, 0, IO_URING_F_UNLOCKED);
io_uring_cmd_done(cmd, -ENOTCONN, IO_URING_F_UNLOCKED);
if (req)
fuse_uring_stop_fuse_req_end(req);
@@ -518,7 +518,7 @@ static void fuse_uring_cancel(struct io_uring_cmd *cmd,
if (need_cmd_done) {
/* no queue lock to avoid lock order issues */
io_uring_cmd_done(cmd, -ENOTCONN, 0, issue_flags);
io_uring_cmd_done(cmd, -ENOTCONN, issue_flags);
}
}
@@ -733,7 +733,7 @@ static int fuse_uring_send_next_to_ring(struct fuse_ring_ent *ent,
list_move_tail(&ent->list, &queue->ent_in_userspace);
spin_unlock(&queue->lock);
io_uring_cmd_done(cmd, 0, 0, issue_flags);
io_uring_cmd_done(cmd, 0, issue_flags);
return 0;
}
@@ -1200,7 +1200,7 @@ static void fuse_uring_send(struct fuse_ring_ent *ent, struct io_uring_cmd *cmd,
ent->cmd = NULL;
spin_unlock(&queue->lock);
io_uring_cmd_done(cmd, ret, 0, issue_flags);
io_uring_cmd_done(cmd, ret, issue_flags);
}
/*
+49 -20
View File
@@ -11,11 +11,14 @@
/* io_uring_cmd is being issued again */
#define IORING_URING_CMD_REISSUE (1U << 31)
typedef void (*io_uring_cmd_tw_t)(struct io_uring_cmd *cmd,
unsigned issue_flags);
struct io_uring_cmd {
struct file *file;
const struct io_uring_sqe *sqe;
/* callback to defer completions to task context */
void (*task_work_cb)(struct io_uring_cmd *cmd, unsigned);
io_uring_cmd_tw_t task_work_cb;
u32 cmd_op;
u32 flags;
u8 pdu[32]; /* available inline for free use */
@@ -53,11 +56,11 @@ int io_uring_cmd_import_fixed_vec(struct io_uring_cmd *ioucmd,
* Note: the caller should never hard code @issue_flags and is only allowed
* to pass the mask provided by the core io_uring code.
*/
void io_uring_cmd_done(struct io_uring_cmd *cmd, ssize_t ret, u64 res2,
unsigned issue_flags);
void __io_uring_cmd_done(struct io_uring_cmd *cmd, s32 ret, u64 res2,
unsigned issue_flags, bool is_cqe32);
void __io_uring_cmd_do_in_task(struct io_uring_cmd *ioucmd,
void (*task_work_cb)(struct io_uring_cmd *, unsigned),
io_uring_cmd_tw_t task_work_cb,
unsigned flags);
/*
@@ -70,6 +73,21 @@ void io_uring_cmd_mark_cancelable(struct io_uring_cmd *cmd,
/* Execute the request from a blocking context */
void io_uring_cmd_issue_blocking(struct io_uring_cmd *ioucmd);
/*
* Select a buffer from the provided buffer group for multishot uring_cmd.
* Returns the selected buffer address and size.
*/
struct io_br_sel io_uring_cmd_buffer_select(struct io_uring_cmd *ioucmd,
unsigned buf_group, size_t *len,
unsigned int issue_flags);
/*
* Complete a multishot uring_cmd event. This will post a CQE to the completion
* queue and update the provided buffer.
*/
bool io_uring_mshot_cmd_post_cqe(struct io_uring_cmd *ioucmd,
struct io_br_sel *sel, unsigned int issue_flags);
#else
static inline int
io_uring_cmd_import_fixed(u64 ubuf, unsigned long len, int rw,
@@ -86,13 +104,12 @@ static inline int io_uring_cmd_import_fixed_vec(struct io_uring_cmd *ioucmd,
{
return -EOPNOTSUPP;
}
static inline void io_uring_cmd_done(struct io_uring_cmd *cmd, ssize_t ret,
u64 ret2, unsigned issue_flags)
static inline void __io_uring_cmd_done(struct io_uring_cmd *cmd, s32 ret,
u64 ret2, unsigned issue_flags, bool is_cqe32)
{
}
static inline void __io_uring_cmd_do_in_task(struct io_uring_cmd *ioucmd,
void (*task_work_cb)(struct io_uring_cmd *, unsigned),
unsigned flags)
io_uring_cmd_tw_t task_work_cb, unsigned flags)
{
}
static inline void io_uring_cmd_mark_cancelable(struct io_uring_cmd *cmd,
@@ -102,28 +119,28 @@ static inline void io_uring_cmd_mark_cancelable(struct io_uring_cmd *cmd,
static inline void io_uring_cmd_issue_blocking(struct io_uring_cmd *ioucmd)
{
}
#endif
/*
* Polled completions must ensure they are coming from a poll queue, and
* hence are completed inside the usual poll handling loops.
*/
static inline void io_uring_cmd_iopoll_done(struct io_uring_cmd *ioucmd,
ssize_t ret, ssize_t res2)
static inline struct io_br_sel
io_uring_cmd_buffer_select(struct io_uring_cmd *ioucmd, unsigned buf_group,
size_t *len, unsigned int issue_flags)
{
lockdep_assert(in_task());
io_uring_cmd_done(ioucmd, ret, res2, 0);
return (struct io_br_sel) { .val = -EOPNOTSUPP };
}
static inline bool io_uring_mshot_cmd_post_cqe(struct io_uring_cmd *ioucmd,
struct io_br_sel *sel, unsigned int issue_flags)
{
return true;
}
#endif
/* users must follow the IOU_F_TWQ_LAZY_WAKE semantics */
static inline void io_uring_cmd_do_in_task_lazy(struct io_uring_cmd *ioucmd,
void (*task_work_cb)(struct io_uring_cmd *, unsigned))
io_uring_cmd_tw_t task_work_cb)
{
__io_uring_cmd_do_in_task(ioucmd, task_work_cb, IOU_F_TWQ_LAZY_WAKE);
}
static inline void io_uring_cmd_complete_in_task(struct io_uring_cmd *ioucmd,
void (*task_work_cb)(struct io_uring_cmd *, unsigned))
io_uring_cmd_tw_t task_work_cb)
{
__io_uring_cmd_do_in_task(ioucmd, task_work_cb, 0);
}
@@ -142,6 +159,18 @@ static inline void *io_uring_cmd_ctx_handle(struct io_uring_cmd *cmd)
return cmd_to_io_kiocb(cmd)->ctx;
}
static inline void io_uring_cmd_done(struct io_uring_cmd *ioucmd, s32 ret,
unsigned issue_flags)
{
return __io_uring_cmd_done(ioucmd, ret, 0, issue_flags, false);
}
static inline void io_uring_cmd_done32(struct io_uring_cmd *ioucmd, s32 ret,
u64 res2, unsigned issue_flags)
{
return __io_uring_cmd_done(ioucmd, ret, res2, issue_flags, true);
}
int io_buffer_register_bvec(struct io_uring_cmd *cmd, struct request *rq,
void (*release)(void *), unsigned int index,
unsigned int issue_flags);
+19 -12
View File
@@ -85,6 +85,25 @@ struct io_mapped_region {
unsigned flags;
};
/*
* Return value from io_buffer_list selection, to avoid stashing it in
* struct io_kiocb. For legacy/classic provided buffers, keeping a reference
* across execution contexts are fine. But for ring provided buffers, the
* list may go away as soon as ->uring_lock is dropped. As the io_kiocb
* persists, it's better to just keep the buffer local for those cases.
*/
struct io_br_sel {
struct io_buffer_list *buf_list;
/*
* Some selection parts return the user address, others return an error.
*/
union {
void __user *addr;
ssize_t val;
};
};
/*
* Arbitrary limit, can be raised if need be
*/
@@ -671,12 +690,6 @@ struct io_kiocb {
/* stores selected buf, valid IFF REQ_F_BUFFER_SELECTED is set */
struct io_buffer *kbuf;
/*
* stores buffer ID for ring provided buffers, valid IFF
* REQ_F_BUFFER_RING is set.
*/
struct io_buffer_list *buf_list;
struct io_rsrc_node *buf_node;
};
@@ -724,10 +737,4 @@ struct io_overflow_cqe {
struct list_head list;
struct io_uring_cqe cqe;
};
static inline bool io_ctx_cqe32(struct io_ring_ctx *ctx)
{
return ctx->flags & IORING_SETUP_CQE32;
}
#endif
+3
View File
@@ -90,4 +90,7 @@
/********** lib/stackdepot.c **********/
#define STACK_DEPOT_POISON ((void *)(0xD390 + POISON_POINTER_DELTA))
/********** io_uring/ **********/
#define IO_URING_PTR_POISON ((void *)(0x1091UL + POISON_POINTER_DELTA))
#endif
+2 -2
View File
@@ -340,8 +340,8 @@ TP_PROTO(struct io_ring_ctx *ctx, void *req, struct io_uring_cqe *cqe),
__entry->user_data = cqe->user_data;
__entry->res = cqe->res;
__entry->cflags = cqe->flags;
__entry->extra1 = io_ctx_cqe32(ctx) ? cqe->big_cqe[0] : 0;
__entry->extra2 = io_ctx_cqe32(ctx) ? cqe->big_cqe[1] : 0;
__entry->extra1 = ctx->flags & IORING_SETUP_CQE32 || cqe->flags & IORING_CQE_F_32 ? cqe->big_cqe[0] : 0;
__entry->extra2 = ctx->flags & IORING_SETUP_CQE32 || cqe->flags & IORING_CQE_F_32 ? cqe->big_cqe[1] : 0;
),
TP_printk("ring %p, req %p, user_data 0x%llx, result %d, cflags 0x%x "
+37 -1
View File
@@ -225,6 +225,12 @@ enum io_uring_sqe_flags_bit {
/* Use hybrid poll in iopoll process */
#define IORING_SETUP_HYBRID_IOPOLL (1U << 17)
/*
* Allow both 16b and 32b CQEs. If a 32b CQE is posted, it will have
* IORING_CQE_F_32 set in cqe->flags.
*/
#define IORING_SETUP_CQE_MIXED (1U << 18)
enum io_uring_op {
IORING_OP_NOP,
IORING_OP_READV,
@@ -298,9 +304,13 @@ enum io_uring_op {
* 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_MULTISHOT must be used with buffer select, like other
* multishot commands. Not compatible with
* IORING_URING_CMD_FIXED, for now.
*/
#define IORING_URING_CMD_FIXED (1U << 0)
#define IORING_URING_CMD_MASK IORING_URING_CMD_FIXED
#define IORING_URING_CMD_MULTISHOT (1U << 1)
#define IORING_URING_CMD_MASK (IORING_URING_CMD_FIXED | IORING_URING_CMD_MULTISHOT)
/*
@@ -454,6 +464,7 @@ enum io_uring_msg_ring_flags {
#define IORING_NOP_FIXED_FILE (1U << 2)
#define IORING_NOP_FIXED_BUFFER (1U << 3)
#define IORING_NOP_TW (1U << 4)
#define IORING_NOP_CQE32 (1U << 5)
/*
* IO completion data structure (Completion Queue Entry)
@@ -487,12 +498,22 @@ struct io_uring_cqe {
* other provided buffer type, all completions with a
* buffer passed back is automatically returned to the
* application.
* IORING_CQE_F_SKIP If set, then the application/liburing must ignore this
* CQE. It's only purpose is to fill a gap in the ring,
* if a large CQE is attempted posted when the ring has
* just a single small CQE worth of space left before
* wrapping.
* IORING_CQE_F_32 If set, this is a 32b/big-cqe posting. Use with rings
* setup in a mixed CQE mode, where both 16b and 32b
* CQEs may be posted to the CQ ring.
*/
#define IORING_CQE_F_BUFFER (1U << 0)
#define IORING_CQE_F_MORE (1U << 1)
#define IORING_CQE_F_SOCK_NONEMPTY (1U << 2)
#define IORING_CQE_F_NOTIF (1U << 3)
#define IORING_CQE_F_BUF_MORE (1U << 4)
#define IORING_CQE_F_SKIP (1U << 5)
#define IORING_CQE_F_32 (1U << 15)
#define IORING_CQE_BUFFER_SHIFT 16
@@ -665,6 +686,12 @@ enum io_uring_register_op {
IORING_REGISTER_MEM_REGION = 34,
/* query various aspects of io_uring, see linux/io_uring/query.h */
IORING_REGISTER_QUERY = 35,
/* return zcrx buffers back into circulation */
IORING_REGISTER_ZCRX_REFILL = 36,
/* this goes last */
IORING_REGISTER_LAST,
@@ -1046,6 +1073,15 @@ struct io_uring_zcrx_ifq_reg {
__u64 __resv[3];
};
struct io_uring_zcrx_sync_refill {
__u32 zcrx_id;
/* the number of entries to return */
__u32 nr_entries;
/* pointer to an array of struct io_uring_zcrx_rqe */
__u64 rqes;
__u64 __resv[2];
};
#ifdef __cplusplus
}
#endif
+41
View File
@@ -0,0 +1,41 @@
/* SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) OR MIT */
/*
* Header file for the io_uring query interface.
*/
#ifndef LINUX_IO_URING_QUERY_H
#define LINUX_IO_URING_QUERY_H
#include <linux/types.h>
struct io_uring_query_hdr {
__u64 next_entry;
__u64 query_data;
__u32 query_op;
__u32 size;
__s32 result;
__u32 __resv[3];
};
enum {
IO_URING_QUERY_OPCODES = 0,
__IO_URING_QUERY_MAX,
};
/* Doesn't require a ring */
struct io_uring_query_opcode {
/* The number of supported IORING_OP_* opcodes */
__u32 nr_request_opcodes;
/* The number of supported IORING_[UN]REGISTER_* opcodes */
__u32 nr_register_opcodes;
/* Bitmask of all supported IORING_FEAT_* flags */
__u64 feature_flags;
/* Bitmask of all supported IORING_SETUP_* flags */
__u64 ring_setup_flags;
/* Bitmask of all supported IORING_ENTER_** flags */
__u64 enter_flags;
/* Bitmask of all supported IOSQE_* flags */
__u64 sqe_flags;
};
#endif
+1 -1
View File
@@ -13,7 +13,7 @@ obj-$(CONFIG_IO_URING) += io_uring.o opdef.o kbuf.o rsrc.o notif.o \
sync.o msg_ring.o advise.o openclose.o \
statx.o timeout.o cancel.o \
waitid.o register.o truncate.o \
memmap.o alloc_cache.o
memmap.o alloc_cache.o query.o
obj-$(CONFIG_IO_URING_ZCRX) += zcrx.o
obj-$(CONFIG_IO_WQ) += io-wq.o
obj-$(CONFIG_FUTEX) += futex.o
+1
View File
@@ -11,6 +11,7 @@
#include <uapi/linux/io_uring.h>
#include "filetable.h"
#include "io_uring.h"
#include "tctx.h"
#include "poll.h"
+2 -1
View File
@@ -4,6 +4,7 @@
#include <net/sock.h>
#include "uring_cmd.h"
#include "io_uring.h"
static inline int io_uring_cmd_getsockopt(struct socket *sock,
struct io_uring_cmd *cmd,
@@ -73,7 +74,7 @@ static bool io_process_timestamp_skb(struct io_uring_cmd *cmd, struct sock *sk,
cqe->user_data = 0;
cqe->res = tskey;
cqe->flags = IORING_CQE_F_MORE;
cqe->flags = IORING_CQE_F_MORE | ctx_cqe32_flags(cmd_to_io_kiocb(cmd)->ctx);
cqe->flags |= tstype << IORING_TIMESTAMP_TYPE_SHIFT;
if (ret == SOF_TIMESTAMPING_TX_HARDWARE)
cqe->flags |= IORING_CQE_F_TSTAMP_HW;
+13 -11
View File
@@ -9,7 +9,7 @@
#include <uapi/linux/io_uring.h>
#include "io_uring.h"
#include "filetable.h"
#include "sqpoll.h"
#include "fdinfo.h"
#include "cancel.h"
@@ -65,15 +65,12 @@ static void __io_uring_show_fdinfo(struct io_ring_ctx *ctx, struct seq_file *m)
unsigned int sq_tail = READ_ONCE(r->sq.tail);
unsigned int cq_head = READ_ONCE(r->cq.head);
unsigned int cq_tail = READ_ONCE(r->cq.tail);
unsigned int cq_shift = 0;
unsigned int sq_shift = 0;
unsigned int sq_entries, cq_entries;
unsigned int sq_entries;
int sq_pid = -1, sq_cpu = -1;
u64 sq_total_time = 0, sq_work_time = 0;
unsigned int i;
if (ctx->flags & IORING_SETUP_CQE32)
cq_shift = 1;
if (ctx->flags & IORING_SETUP_SQE128)
sq_shift = 1;
@@ -125,18 +122,23 @@ static void __io_uring_show_fdinfo(struct io_ring_ctx *ctx, struct seq_file *m)
seq_printf(m, "\n");
}
seq_printf(m, "CQEs:\t%u\n", cq_tail - cq_head);
cq_entries = min(cq_tail - cq_head, ctx->cq_entries);
for (i = 0; i < cq_entries; i++) {
unsigned int entry = i + cq_head;
struct io_uring_cqe *cqe = &r->cqes[(entry & cq_mask) << cq_shift];
while (cq_head < cq_tail) {
struct io_uring_cqe *cqe;
bool cqe32 = false;
cqe = &r->cqes[(cq_head & cq_mask)];
if (cqe->flags & IORING_CQE_F_32 || ctx->flags & IORING_SETUP_CQE32)
cqe32 = true;
seq_printf(m, "%5u: user_data:%llu, res:%d, flag:%x",
entry & cq_mask, cqe->user_data, cqe->res,
cq_head & cq_mask, cqe->user_data, cqe->res,
cqe->flags);
if (cq_shift)
if (cqe32)
seq_printf(m, ", extra1:%llu, extra2:%llu\n",
cqe->big_cqe[0], cqe->big_cqe[1]);
seq_printf(m, "\n");
cq_head++;
if (cqe32)
cq_head++;
}
if (ctx->flags & IORING_SETUP_SQPOLL) {
+4 -9
View File
@@ -43,7 +43,6 @@ void io_futex_cache_free(struct io_ring_ctx *ctx)
static void __io_futex_complete(struct io_kiocb *req, io_tw_token_t tw)
{
req->async_data = NULL;
hlist_del_init(&req->hash_node);
io_req_task_complete(req, tw);
}
@@ -54,6 +53,7 @@ static void io_futex_complete(struct io_kiocb *req, io_tw_token_t tw)
io_tw_lock(ctx, tw);
io_cache_free(&ctx->futex_cache, req->async_data);
io_req_async_data_clear(req, 0);
__io_futex_complete(req, tw);
}
@@ -72,8 +72,7 @@ static void io_futexv_complete(struct io_kiocb *req, io_tw_token_t tw)
io_req_set_res(req, res, 0);
}
kfree(req->async_data);
req->flags &= ~REQ_F_ASYNC_DATA;
io_req_async_data_free(req);
__io_futex_complete(req, tw);
}
@@ -232,9 +231,7 @@ int io_futexv_wait(struct io_kiocb *req, unsigned int issue_flags)
io_ring_submit_unlock(ctx, issue_flags);
req_set_fail(req);
io_req_set_res(req, ret, 0);
kfree(futexv);
req->async_data = NULL;
req->flags &= ~REQ_F_ASYNC_DATA;
io_req_async_data_free(req);
return IOU_COMPLETE;
}
@@ -310,9 +307,7 @@ done:
if (ret < 0)
req_set_fail(req);
io_req_set_res(req, ret, 0);
req->async_data = NULL;
req->flags &= ~REQ_F_ASYNC_DATA;
kfree(ifd);
io_req_async_data_free(req);
return IOU_COMPLETE;
}
+96 -49
View File
@@ -79,6 +79,7 @@
#include "io-wq.h"
#include "filetable.h"
#include "io_uring.h"
#include "opdef.h"
#include "refs.h"
@@ -108,9 +109,6 @@
#define SQE_COMMON_FLAGS (IOSQE_FIXED_FILE | IOSQE_IO_LINK | \
IOSQE_IO_HARDLINK | IOSQE_ASYNC)
#define SQE_VALID_FLAGS (SQE_COMMON_FLAGS | IOSQE_BUFFER_SELECT | \
IOSQE_IO_DRAIN | IOSQE_CQE_SKIP_SUCCESS)
#define IO_REQ_LINK_FLAGS (REQ_F_LINK | REQ_F_HARDLINK)
#define IO_REQ_CLEAN_FLAGS (REQ_F_BUFFER_SELECTED | REQ_F_NEED_CLEANUP | \
@@ -179,6 +177,26 @@ static const struct ctl_table kernel_io_uring_disabled_table[] = {
};
#endif
static void io_poison_cached_req(struct io_kiocb *req)
{
req->ctx = IO_URING_PTR_POISON;
req->tctx = IO_URING_PTR_POISON;
req->file = IO_URING_PTR_POISON;
req->creds = IO_URING_PTR_POISON;
req->io_task_work.func = IO_URING_PTR_POISON;
req->apoll = IO_URING_PTR_POISON;
}
static void io_poison_req(struct io_kiocb *req)
{
io_poison_cached_req(req);
req->async_data = IO_URING_PTR_POISON;
req->kbuf = IO_URING_PTR_POISON;
req->comp_list.next = IO_URING_PTR_POISON;
req->file_node = IO_URING_PTR_POISON;
req->link = IO_URING_PTR_POISON;
}
static inline unsigned int __io_cqring_events(struct io_ring_ctx *ctx)
{
return ctx->cached_cq_tail - READ_ONCE(ctx->rings->cq.head);
@@ -235,6 +253,8 @@ static inline void req_fail_link_node(struct io_kiocb *req, int res)
static inline void io_req_add_to_cache(struct io_kiocb *req, struct io_ring_ctx *ctx)
{
if (IS_ENABLED(CONFIG_KASAN))
io_poison_cached_req(req);
wq_stack_add_head(&req->comp_list, &ctx->submit_state.free_list);
}
@@ -594,27 +614,29 @@ static void io_cq_unlock_post(struct io_ring_ctx *ctx)
static void __io_cqring_overflow_flush(struct io_ring_ctx *ctx, bool dying)
{
size_t cqe_size = sizeof(struct io_uring_cqe);
lockdep_assert_held(&ctx->uring_lock);
/* don't abort if we're dying, entries must get freed */
if (!dying && __io_cqring_events(ctx) == ctx->cq_entries)
return;
if (ctx->flags & IORING_SETUP_CQE32)
cqe_size <<= 1;
io_cq_lock(ctx);
while (!list_empty(&ctx->cq_overflow_list)) {
size_t cqe_size = sizeof(struct io_uring_cqe);
struct io_uring_cqe *cqe;
struct io_overflow_cqe *ocqe;
bool is_cqe32 = false;
ocqe = list_first_entry(&ctx->cq_overflow_list,
struct io_overflow_cqe, list);
if (ocqe->cqe.flags & IORING_CQE_F_32 ||
ctx->flags & IORING_SETUP_CQE32) {
is_cqe32 = true;
cqe_size <<= 1;
}
if (!dying) {
if (!io_get_cqe_overflow(ctx, &cqe, true))
if (!io_get_cqe_overflow(ctx, &cqe, true, is_cqe32))
break;
memcpy(cqe, &ocqe->cqe, cqe_size);
}
@@ -726,10 +748,12 @@ static struct io_overflow_cqe *io_alloc_ocqe(struct io_ring_ctx *ctx,
{
struct io_overflow_cqe *ocqe;
size_t ocq_size = sizeof(struct io_overflow_cqe);
bool is_cqe32 = (ctx->flags & IORING_SETUP_CQE32);
bool is_cqe32 = false;
if (is_cqe32)
if (cqe->flags & IORING_CQE_F_32 || ctx->flags & IORING_SETUP_CQE32) {
is_cqe32 = true;
ocq_size += sizeof(struct io_uring_cqe);
}
ocqe = kzalloc(ocq_size, gfp | __GFP_ACCOUNT);
trace_io_uring_cqe_overflow(ctx, cqe->user_data, cqe->res, cqe->flags, ocqe);
@@ -747,12 +771,30 @@ static struct io_overflow_cqe *io_alloc_ocqe(struct io_ring_ctx *ctx,
return ocqe;
}
/*
* Fill an empty dummy CQE, in case alignment is off for posting a 32b CQE
* because the ring is a single 16b entry away from wrapping.
*/
static bool io_fill_nop_cqe(struct io_ring_ctx *ctx, unsigned int off)
{
if (__io_cqring_events(ctx) < ctx->cq_entries) {
struct io_uring_cqe *cqe = &ctx->rings->cqes[off];
cqe->user_data = 0;
cqe->res = 0;
cqe->flags = IORING_CQE_F_SKIP;
ctx->cached_cq_tail++;
return true;
}
return false;
}
/*
* writes to the cq entry need to come after reading head; the
* control dependency is enough as we're using WRITE_ONCE to
* fill the cq entry
*/
bool io_cqe_cache_refill(struct io_ring_ctx *ctx, bool overflow)
bool io_cqe_cache_refill(struct io_ring_ctx *ctx, bool overflow, bool cqe32)
{
struct io_rings *rings = ctx->rings;
unsigned int off = ctx->cached_cq_tail & (ctx->cq_entries - 1);
@@ -766,12 +808,22 @@ bool io_cqe_cache_refill(struct io_ring_ctx *ctx, bool overflow)
if (!overflow && (ctx->check_cq & BIT(IO_CHECK_CQ_OVERFLOW_BIT)))
return false;
/*
* Post dummy CQE if a 32b CQE is needed and there's only room for a
* 16b CQE before the ring wraps.
*/
if (cqe32 && off + 1 == ctx->cq_entries) {
if (!io_fill_nop_cqe(ctx, off))
return false;
off = 0;
}
/* userspace may cheat modifying the tail, be safe and do min */
queued = min(__io_cqring_events(ctx), ctx->cq_entries);
free = ctx->cq_entries - queued;
/* we need a contiguous range, limit based on the current array offset */
len = min(free, ctx->cq_entries - off);
if (!len)
if (len < (cqe32 + 1))
return false;
if (ctx->flags & IORING_SETUP_CQE32) {
@@ -789,9 +841,9 @@ static bool io_fill_cqe_aux32(struct io_ring_ctx *ctx,
{
struct io_uring_cqe *cqe;
if (WARN_ON_ONCE(!(ctx->flags & IORING_SETUP_CQE32)))
if (WARN_ON_ONCE(!(ctx->flags & (IORING_SETUP_CQE32|IORING_SETUP_CQE_MIXED))))
return false;
if (unlikely(!io_get_cqe(ctx, &cqe)))
if (unlikely(!io_get_cqe(ctx, &cqe, true)))
return false;
memcpy(cqe, src_cqe, 2 * sizeof(*cqe));
@@ -802,14 +854,15 @@ static bool io_fill_cqe_aux32(struct io_ring_ctx *ctx,
static bool io_fill_cqe_aux(struct io_ring_ctx *ctx, u64 user_data, s32 res,
u32 cflags)
{
bool cqe32 = cflags & IORING_CQE_F_32;
struct io_uring_cqe *cqe;
if (likely(io_get_cqe(ctx, &cqe))) {
if (likely(io_get_cqe(ctx, &cqe, cqe32))) {
WRITE_ONCE(cqe->user_data, user_data);
WRITE_ONCE(cqe->res, res);
WRITE_ONCE(cqe->flags, cflags);
if (ctx->flags & IORING_SETUP_CQE32) {
if (cqe32) {
WRITE_ONCE(cqe->big_cqe[0], 0);
WRITE_ONCE(cqe->big_cqe[1], 0);
}
@@ -981,7 +1034,7 @@ void io_req_defer_failed(struct io_kiocb *req, s32 res)
lockdep_assert_held(&req->ctx->uring_lock);
req_set_fail(req);
io_req_set_res(req, res, io_put_kbuf(req, res, IO_URING_F_UNLOCKED));
io_req_set_res(req, res, io_put_kbuf(req, res, NULL));
if (def->fail)
def->fail(req);
io_req_complete_defer(req);
@@ -2001,11 +2054,9 @@ fail:
switch (io_arm_poll_handler(req, 0)) {
case IO_APOLL_READY:
io_kbuf_recycle(req, 0);
io_req_task_queue(req);
break;
case IO_APOLL_ABORTED:
io_kbuf_recycle(req, 0);
io_queue_iowq(req);
break;
case IO_APOLL_OK:
@@ -2734,6 +2785,10 @@ unsigned long rings_size(unsigned int flags, unsigned int sq_entries,
if (check_shl_overflow(off, 1, &off))
return SIZE_MAX;
}
if (flags & IORING_SETUP_CQE_MIXED) {
if (cq_entries < 2)
return SIZE_MAX;
}
#ifdef CONFIG_SMP
off = ALIGN(off, SMP_CACHE_BYTES);
@@ -2765,6 +2820,7 @@ static __cold void __io_req_caches_free(struct io_ring_ctx *ctx)
while (!io_req_cache_empty(ctx)) {
req = io_extract_req(ctx);
io_poison_req(req);
kmem_cache_free(req_cachep, req);
nr++;
}
@@ -3045,10 +3101,10 @@ static __cold void io_ring_ctx_wait_and_kill(struct io_ring_ctx *ctx)
INIT_WORK(&ctx->exit_work, io_ring_exit_work);
/*
* Use system_unbound_wq to avoid spawning tons of event kworkers
* Use system_dfl_wq to avoid spawning tons of event kworkers
* if we're exiting a ton of rings at the same time. It just adds
* noise and overhead, there's no discernable change in runtime
* over using system_wq.
* over using system_percpu_wq.
*/
queue_work(iou_wq, &ctx->exit_work);
}
@@ -3402,12 +3458,7 @@ SYSCALL_DEFINE6(io_uring_enter, unsigned int, fd, u32, to_submit,
struct file *file;
long ret;
if (unlikely(flags & ~(IORING_ENTER_GETEVENTS | IORING_ENTER_SQ_WAKEUP |
IORING_ENTER_SQ_WAIT | IORING_ENTER_EXT_ARG |
IORING_ENTER_REGISTERED_RING |
IORING_ENTER_ABS_TIMER |
IORING_ENTER_EXT_ARG_REG |
IORING_ENTER_NO_IOWAIT)))
if (unlikely(flags & ~IORING_ENTER_FLAGS))
return -EINVAL;
/*
@@ -3657,6 +3708,14 @@ static int io_uring_sanitise_params(struct io_uring_params *p)
!(flags & IORING_SETUP_SINGLE_ISSUER))
return -EINVAL;
/*
* Nonsensical to ask for CQE32 and mixed CQE support, it's not
* supported to post 16b CQEs on a ring setup with CQE32.
*/
if ((flags & (IORING_SETUP_CQE32|IORING_SETUP_CQE_MIXED)) ==
(IORING_SETUP_CQE32|IORING_SETUP_CQE_MIXED))
return -EINVAL;
return 0;
}
@@ -3807,15 +3866,7 @@ static __cold int io_uring_create(unsigned entries, struct io_uring_params *p,
if (ret)
goto err;
p->features = IORING_FEAT_SINGLE_MMAP | IORING_FEAT_NODROP |
IORING_FEAT_SUBMIT_STABLE | IORING_FEAT_RW_CUR_POS |
IORING_FEAT_CUR_PERSONALITY | IORING_FEAT_FAST_POLL |
IORING_FEAT_POLL_32BITS | IORING_FEAT_SQPOLL_NONFIXED |
IORING_FEAT_EXT_ARG | IORING_FEAT_NATIVE_WORKERS |
IORING_FEAT_RSRC_TAGS | IORING_FEAT_CQE_SKIP |
IORING_FEAT_LINKED_FILE | IORING_FEAT_REG_REG_RING |
IORING_FEAT_RECVSEND_BUNDLE | IORING_FEAT_MIN_TIMEOUT |
IORING_FEAT_RW_ATTR | IORING_FEAT_NO_IOWAIT;
p->features = IORING_FEAT_FLAGS;
if (copy_to_user(params, p, sizeof(*p))) {
ret = -EFAULT;
@@ -3823,8 +3874,13 @@ static __cold int io_uring_create(unsigned entries, struct io_uring_params *p,
}
if (ctx->flags & IORING_SETUP_SINGLE_ISSUER
&& !(ctx->flags & IORING_SETUP_R_DISABLED))
WRITE_ONCE(ctx->submitter_task, get_task_struct(current));
&& !(ctx->flags & IORING_SETUP_R_DISABLED)) {
/*
* Unlike io_register_enable_rings(), don't need WRITE_ONCE()
* since ctx isn't yet accessible from other tasks
*/
ctx->submitter_task = get_task_struct(current);
}
file = io_uring_get_file(ctx);
if (IS_ERR(file)) {
@@ -3875,17 +3931,8 @@ static long io_uring_setup(u32 entries, struct io_uring_params __user *params)
return -EINVAL;
}
if (p.flags & ~(IORING_SETUP_IOPOLL | IORING_SETUP_SQPOLL |
IORING_SETUP_SQ_AFF | IORING_SETUP_CQSIZE |
IORING_SETUP_CLAMP | IORING_SETUP_ATTACH_WQ |
IORING_SETUP_R_DISABLED | IORING_SETUP_SUBMIT_ALL |
IORING_SETUP_COOP_TASKRUN | IORING_SETUP_TASKRUN_FLAG |
IORING_SETUP_SQE128 | IORING_SETUP_CQE32 |
IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_DEFER_TASKRUN |
IORING_SETUP_NO_MMAP | IORING_SETUP_REGISTERED_FD_ONLY |
IORING_SETUP_NO_SQARRAY | IORING_SETUP_HYBRID_IOPOLL))
if (p.flags & ~IORING_SETUP_FLAGS)
return -EINVAL;
return io_uring_create(entries, &p, params);
}
+105 -15
View File
@@ -11,13 +11,69 @@
#include "alloc_cache.h"
#include "io-wq.h"
#include "slist.h"
#include "filetable.h"
#include "opdef.h"
#ifndef CREATE_TRACE_POINTS
#include <trace/events/io_uring.h>
#endif
#define IORING_FEAT_FLAGS (IORING_FEAT_SINGLE_MMAP |\
IORING_FEAT_NODROP |\
IORING_FEAT_SUBMIT_STABLE |\
IORING_FEAT_RW_CUR_POS |\
IORING_FEAT_CUR_PERSONALITY |\
IORING_FEAT_FAST_POLL |\
IORING_FEAT_POLL_32BITS |\
IORING_FEAT_SQPOLL_NONFIXED |\
IORING_FEAT_EXT_ARG |\
IORING_FEAT_NATIVE_WORKERS |\
IORING_FEAT_RSRC_TAGS |\
IORING_FEAT_CQE_SKIP |\
IORING_FEAT_LINKED_FILE |\
IORING_FEAT_REG_REG_RING |\
IORING_FEAT_RECVSEND_BUNDLE |\
IORING_FEAT_MIN_TIMEOUT |\
IORING_FEAT_RW_ATTR |\
IORING_FEAT_NO_IOWAIT)
#define IORING_SETUP_FLAGS (IORING_SETUP_IOPOLL |\
IORING_SETUP_SQPOLL |\
IORING_SETUP_SQ_AFF |\
IORING_SETUP_CQSIZE |\
IORING_SETUP_CLAMP |\
IORING_SETUP_ATTACH_WQ |\
IORING_SETUP_R_DISABLED |\
IORING_SETUP_SUBMIT_ALL |\
IORING_SETUP_COOP_TASKRUN |\
IORING_SETUP_TASKRUN_FLAG |\
IORING_SETUP_SQE128 |\
IORING_SETUP_CQE32 |\
IORING_SETUP_SINGLE_ISSUER |\
IORING_SETUP_DEFER_TASKRUN |\
IORING_SETUP_NO_MMAP |\
IORING_SETUP_REGISTERED_FD_ONLY |\
IORING_SETUP_NO_SQARRAY |\
IORING_SETUP_HYBRID_IOPOLL |\
IORING_SETUP_CQE_MIXED)
#define IORING_ENTER_FLAGS (IORING_ENTER_GETEVENTS |\
IORING_ENTER_SQ_WAKEUP |\
IORING_ENTER_SQ_WAIT |\
IORING_ENTER_EXT_ARG |\
IORING_ENTER_REGISTERED_RING |\
IORING_ENTER_ABS_TIMER |\
IORING_ENTER_EXT_ARG_REG |\
IORING_ENTER_NO_IOWAIT)
#define SQE_VALID_FLAGS (IOSQE_FIXED_FILE |\
IOSQE_IO_DRAIN |\
IOSQE_IO_LINK |\
IOSQE_IO_HARDLINK |\
IOSQE_ASYNC |\
IOSQE_BUFFER_SELECT |\
IOSQE_CQE_SKIP_SUCCESS)
enum {
IOU_COMPLETE = 0,
@@ -75,7 +131,7 @@ static inline bool io_should_wake(struct io_wait_queue *iowq)
unsigned long rings_size(unsigned int flags, unsigned int sq_entries,
unsigned int cq_entries, size_t *sq_offset);
int io_uring_fill_params(unsigned entries, struct io_uring_params *p);
bool io_cqe_cache_refill(struct io_ring_ctx *ctx, bool overflow);
bool io_cqe_cache_refill(struct io_ring_ctx *ctx, bool overflow, bool cqe32);
int io_run_task_work_sig(struct io_ring_ctx *ctx);
void io_req_defer_failed(struct io_kiocb *req, s32 res);
bool io_post_aux_cqe(struct io_ring_ctx *ctx, u64 user_data, s32 res, u32 cflags);
@@ -169,25 +225,31 @@ static inline void io_submit_flush_completions(struct io_ring_ctx *ctx)
static inline bool io_get_cqe_overflow(struct io_ring_ctx *ctx,
struct io_uring_cqe **ret,
bool overflow)
bool overflow, bool cqe32)
{
io_lockdep_assert_cq_locked(ctx);
if (unlikely(ctx->cqe_cached >= ctx->cqe_sentinel)) {
if (unlikely(!io_cqe_cache_refill(ctx, overflow)))
if (unlikely(ctx->cqe_sentinel - ctx->cqe_cached < (cqe32 + 1))) {
if (unlikely(!io_cqe_cache_refill(ctx, overflow, cqe32)))
return false;
}
*ret = ctx->cqe_cached;
ctx->cached_cq_tail++;
ctx->cqe_cached++;
if (ctx->flags & IORING_SETUP_CQE32)
if (ctx->flags & IORING_SETUP_CQE32) {
ctx->cqe_cached++;
} else if (cqe32 && ctx->flags & IORING_SETUP_CQE_MIXED) {
ctx->cqe_cached++;
ctx->cached_cq_tail++;
}
WARN_ON_ONCE(ctx->cqe_cached > ctx->cqe_sentinel);
return true;
}
static inline bool io_get_cqe(struct io_ring_ctx *ctx, struct io_uring_cqe **ret)
static inline bool io_get_cqe(struct io_ring_ctx *ctx, struct io_uring_cqe **ret,
bool cqe32)
{
return io_get_cqe_overflow(ctx, ret, false);
return io_get_cqe_overflow(ctx, ret, false, cqe32);
}
static inline bool io_defer_get_uncommited_cqe(struct io_ring_ctx *ctx,
@@ -196,25 +258,24 @@ static inline bool io_defer_get_uncommited_cqe(struct io_ring_ctx *ctx,
io_lockdep_assert_cq_locked(ctx);
ctx->submit_state.cq_flush = true;
return io_get_cqe(ctx, cqe_ret);
return io_get_cqe(ctx, cqe_ret, ctx->flags & IORING_SETUP_CQE_MIXED);
}
static __always_inline bool io_fill_cqe_req(struct io_ring_ctx *ctx,
struct io_kiocb *req)
{
bool is_cqe32 = req->cqe.flags & IORING_CQE_F_32;
struct io_uring_cqe *cqe;
/*
* If we can't get a cq entry, userspace overflowed the
* submission (by quite a lot). Increment the overflow count in
* the ring.
* If we can't get a cq entry, userspace overflowed the submission
* (by quite a lot).
*/
if (unlikely(!io_get_cqe(ctx, &cqe)))
if (unlikely(!io_get_cqe(ctx, &cqe, is_cqe32)))
return false;
memcpy(cqe, &req->cqe, sizeof(*cqe));
if (ctx->flags & IORING_SETUP_CQE32) {
if (ctx->flags & IORING_SETUP_CQE32 || is_cqe32) {
memcpy(cqe->big_cqe, &req->big_cqe, sizeof(*cqe));
memset(&req->big_cqe, 0, sizeof(req->big_cqe));
}
@@ -239,6 +300,22 @@ static inline void io_req_set_res(struct io_kiocb *req, s32 res, u32 cflags)
req->cqe.flags = cflags;
}
static inline u32 ctx_cqe32_flags(struct io_ring_ctx *ctx)
{
if (ctx->flags & IORING_SETUP_CQE_MIXED)
return IORING_CQE_F_32;
return 0;
}
static inline void io_req_set_res32(struct io_kiocb *req, s32 res, u32 cflags,
__u64 extra1, __u64 extra2)
{
req->cqe.res = res;
req->cqe.flags = cflags | ctx_cqe32_flags(req->ctx);
req->big_cqe.extra1 = extra1;
req->big_cqe.extra2 = extra2;
}
static inline void *io_uring_alloc_async_data(struct io_alloc_cache *cache,
struct io_kiocb *req)
{
@@ -260,6 +337,19 @@ static inline bool req_has_async_data(struct io_kiocb *req)
return req->flags & REQ_F_ASYNC_DATA;
}
static inline void io_req_async_data_clear(struct io_kiocb *req,
io_req_flags_t extra_flags)
{
req->flags &= ~(REQ_F_ASYNC_DATA|extra_flags);
req->async_data = NULL;
}
static inline void io_req_async_data_free(struct io_kiocb *req)
{
kfree(req->async_data);
io_req_async_data_clear(req, 0);
}
static inline void io_put_file(struct io_kiocb *req)
{
if (!(req->flags & REQ_F_FIXED_FILE) && req->file)
+36 -31
View File
@@ -155,19 +155,19 @@ static int io_provided_buffers_select(struct io_kiocb *req, size_t *len,
return 1;
}
static void __user *io_ring_buffer_select(struct io_kiocb *req, size_t *len,
struct io_buffer_list *bl,
unsigned int issue_flags)
static struct io_br_sel io_ring_buffer_select(struct io_kiocb *req, size_t *len,
struct io_buffer_list *bl,
unsigned int issue_flags)
{
struct io_uring_buf_ring *br = bl->buf_ring;
__u16 tail, head = bl->head;
struct io_br_sel sel = { };
struct io_uring_buf *buf;
void __user *ret;
u32 buf_len;
tail = smp_load_acquire(&br->tail);
if (unlikely(tail == head))
return NULL;
return sel;
if (head + 1 == tail)
req->flags |= REQ_F_BL_EMPTY;
@@ -177,9 +177,9 @@ static void __user *io_ring_buffer_select(struct io_kiocb *req, size_t *len,
if (*len == 0 || *len > buf_len)
*len = buf_len;
req->flags |= REQ_F_BUFFER_RING | REQ_F_BUFFERS_COMMIT;
req->buf_list = bl;
req->buf_index = buf->bid;
ret = u64_to_user_ptr(buf->addr);
sel.buf_list = bl;
sel.addr = u64_to_user_ptr(buf->addr);
if (issue_flags & IO_URING_F_UNLOCKED || !io_file_can_poll(req)) {
/*
@@ -192,30 +192,30 @@ static void __user *io_ring_buffer_select(struct io_kiocb *req, size_t *len,
* the transfer completes (or if we get -EAGAIN and must poll of
* retry).
*/
io_kbuf_commit(req, bl, *len, 1);
req->buf_list = NULL;
io_kbuf_commit(req, sel.buf_list, *len, 1);
sel.buf_list = NULL;
}
return ret;
return sel;
}
void __user *io_buffer_select(struct io_kiocb *req, size_t *len,
unsigned buf_group, unsigned int issue_flags)
struct io_br_sel io_buffer_select(struct io_kiocb *req, size_t *len,
unsigned buf_group, unsigned int issue_flags)
{
struct io_ring_ctx *ctx = req->ctx;
struct io_br_sel sel = { };
struct io_buffer_list *bl;
void __user *ret = NULL;
io_ring_submit_lock(req->ctx, issue_flags);
bl = io_buffer_get_list(ctx, buf_group);
if (likely(bl)) {
if (bl->flags & IOBL_BUF_RING)
ret = io_ring_buffer_select(req, len, bl, issue_flags);
sel = io_ring_buffer_select(req, len, bl, issue_flags);
else
ret = io_provided_buffer_select(req, len, bl);
sel.addr = io_provided_buffer_select(req, len, bl);
}
io_ring_submit_unlock(req->ctx, issue_flags);
return ret;
return sel;
}
/* cap it at a reasonable 256, will be one page even for 4K */
@@ -300,24 +300,22 @@ static int io_ring_buffers_peek(struct io_kiocb *req, struct buf_sel_arg *arg,
req->flags |= REQ_F_BL_EMPTY;
req->flags |= REQ_F_BUFFER_RING;
req->buf_list = bl;
return iov - arg->iovs;
}
int io_buffers_select(struct io_kiocb *req, struct buf_sel_arg *arg,
unsigned int issue_flags)
struct io_br_sel *sel, unsigned int issue_flags)
{
struct io_ring_ctx *ctx = req->ctx;
struct io_buffer_list *bl;
int ret = -ENOENT;
io_ring_submit_lock(ctx, issue_flags);
bl = io_buffer_get_list(ctx, arg->buf_group);
if (unlikely(!bl))
sel->buf_list = io_buffer_get_list(ctx, arg->buf_group);
if (unlikely(!sel->buf_list))
goto out_unlock;
if (bl->flags & IOBL_BUF_RING) {
ret = io_ring_buffers_peek(req, arg, bl);
if (sel->buf_list->flags & IOBL_BUF_RING) {
ret = io_ring_buffers_peek(req, arg, sel->buf_list);
/*
* Don't recycle these buffers if we need to go through poll.
* Nobody else can use them anyway, and holding on to provided
@@ -327,17 +325,21 @@ int io_buffers_select(struct io_kiocb *req, struct buf_sel_arg *arg,
*/
if (ret > 0) {
req->flags |= REQ_F_BUFFERS_COMMIT | REQ_F_BL_NO_RECYCLE;
io_kbuf_commit(req, bl, arg->out_len, ret);
io_kbuf_commit(req, sel->buf_list, arg->out_len, ret);
}
} else {
ret = io_provided_buffers_select(req, &arg->out_len, bl, arg->iovs);
ret = io_provided_buffers_select(req, &arg->out_len, sel->buf_list, arg->iovs);
}
out_unlock:
io_ring_submit_unlock(ctx, issue_flags);
if (issue_flags & IO_URING_F_UNLOCKED) {
sel->buf_list = NULL;
mutex_unlock(&ctx->uring_lock);
}
return ret;
}
int io_buffers_peek(struct io_kiocb *req, struct buf_sel_arg *arg)
int io_buffers_peek(struct io_kiocb *req, struct buf_sel_arg *arg,
struct io_br_sel *sel)
{
struct io_ring_ctx *ctx = req->ctx;
struct io_buffer_list *bl;
@@ -353,16 +355,18 @@ int io_buffers_peek(struct io_kiocb *req, struct buf_sel_arg *arg)
ret = io_ring_buffers_peek(req, arg, bl);
if (ret > 0)
req->flags |= REQ_F_BUFFERS_COMMIT;
sel->buf_list = bl;
return ret;
}
/* don't support multiple buffer selections for legacy */
sel->buf_list = NULL;
return io_provided_buffers_select(req, &arg->max_len, bl, arg->iovs);
}
static inline bool __io_put_kbuf_ring(struct io_kiocb *req, int len, int nr)
static inline bool __io_put_kbuf_ring(struct io_kiocb *req,
struct io_buffer_list *bl, int len, int nr)
{
struct io_buffer_list *bl = req->buf_list;
bool ret = true;
if (bl)
@@ -372,7 +376,8 @@ static inline bool __io_put_kbuf_ring(struct io_kiocb *req, int len, int nr)
return ret;
}
unsigned int __io_put_kbufs(struct io_kiocb *req, int len, int nbufs)
unsigned int __io_put_kbufs(struct io_kiocb *req, struct io_buffer_list *bl,
int len, int nbufs)
{
unsigned int ret;
@@ -383,7 +388,7 @@ unsigned int __io_put_kbufs(struct io_kiocb *req, int len, int nbufs)
return ret;
}
if (!__io_put_kbuf_ring(req, len, nbufs))
if (!__io_put_kbuf_ring(req, bl, len, nbufs))
ret |= IORING_CQE_F_BUF_MORE;
return ret;
}

Some files were not shown because too many files have changed in this diff Show More