History

io_uring: support buffer selection for OP_READ and OP_RECV

If a server process has tons of pending socket connections, generally it uses epoll to wait for activity. When the socket is ready for reading (or writing), the task can select a buffer and issue a recv/send on the given fd. Now that we have fast (non-async thread) support, a task can have tons of pending reads or writes pending. But that means they need buffers to back that data, and if the number of connections is high enough, having them preallocated for all possible connections is unfeasible. With IORING_OP_PROVIDE_BUFFERS, an application can register buffers to use for any request. The request then sets IOSQE_BUFFER_SELECT in the sqe, and a given group ID in sqe->buf_group. When the fd becomes ready, a free buffer from the specified group is selected. If none are available, the request is terminated with -ENOBUFS. If successful, the CQE on completion will contain the buffer ID chosen in the cqe->flags member, encoded as: (buffer_id << IORING_CQE_BUFFER_SHIFT) | IORING_CQE_F_BUFFER; Once a buffer has been consumed by a request, it is no longer available and must be registered again with IORING_OP_PROVIDE_BUFFERS. Requests need to support this feature. For now, IORING_OP_READ and IORING_OP_RECV support it. This is checked on SQE submission, a CQE with res == -EOPNOTSUPP will be posted if attempted on unsupported requests.

Jens Axboe committed 6 years ago

Commit bcda7ba1 parent ddf03222 files · +199 −39Browse files

Showing the changes to include/uapi/linux (1 of 2 files). Show all

Unified · Split

include/uapi/linux/io_uring.h+14−0
@@ -66,6 +66,7 @@ enum { · 65 unmodified lines
66 IOSQE_IO_LINK_BIT,66 IOSQE_IO_LINK_BIT,
67 IOSQE_IO_HARDLINK_BIT,67 IOSQE_IO_HARDLINK_BIT,
68 IOSQE_ASYNC_BIT,68 IOSQE_ASYNC_BIT,
69 IOSQE_BUFFER_SELECT_BIT,
69};70};
70 71
71/*72/*
@@ -81,6 +82,8 @@ enum { · 9 unmodified lines
81#define IOSQE_IO_HARDLINK (1U << IOSQE_IO_HARDLINK_BIT)82#define IOSQE_IO_HARDLINK (1U << IOSQE_IO_HARDLINK_BIT)
82/* always go async */83/* always go async */
83#define IOSQE_ASYNC (1U << IOSQE_ASYNC_BIT)84#define IOSQE_ASYNC (1U << IOSQE_ASYNC_BIT)
85/* select buffer from sqe->buf_group */
86#define IOSQE_BUFFER_SELECT (1U << IOSQE_BUFFER_SELECT_BIT)
84 87
85/*88/*
86 * io_uring_setup() flags89 * io_uring_setup() flags
@@ -155,6 +158,17 @@ struct io_uring_cqe { · 68 unmodified lines
155 __u32 flags;158 __u32 flags;
156};159};
157 160
161/*
162 * cqe->flags
163 *
164 * IORING_CQE_F_BUFFER If set, the upper 16 bits are the buffer ID
165 */
166#define IORING_CQE_F_BUFFER (1U << 0)
167
168enum {
169 IORING_CQE_BUFFER_SHIFT = 16,
170};
171
158/*172/*
159 * Magic offsets for the application to mmap the data it needs173 * Magic offsets for the application to mmap the data it needs
160 */174 */