* [PATCH v5 0/8] io_uring: Initial support for {s,g}etsockopt commands
@ 2023-09-11 10:33 Breno Leitao
2023-09-11 10:34 ` [PATCH v5 1/8] net/socket: Break down __sys_setsockopt Breno Leitao
` (7 more replies)
0 siblings, 8 replies; 14+ messages in thread
From: Breno Leitao @ 2023-09-11 10:33 UTC (permalink / raw)
To: sdf, axboe, asml.silence, willemdebruijn.kernel, kuba, martin.lau,
krisman
Cc: bpf, linux-kernel, netdev, io-uring, pabeni
This patchset adds support for getsockopt (SOCKET_URING_OP_GETSOCKOPT)
and setsockopt (SOCKET_URING_OP_SETSOCKOPT) in io_uring commands.
SOCKET_URING_OP_SETSOCKOPT and SOCKET_URING_OP_GETSOCKOPT implement generic
case, covering all levels and optnames (a change from the previous
version, where getsockopt was limited to level=SOL_SOCKET).
In order to keep the implementation (and tests) simple, some refactors
were done prior to the changes, as follows:
Patch 1-2: Remove the core {s,g}etsockopt() core function from
__sys_{g,s}etsockopt, so, the code could be reused by other callers,
such as io_uring.
Patch 3: Pass compat mode to the file/socket callbacks
Patch 4: Move io_uring helpers from io_uring_zerocopy_tx to a generic
io_uring headers. This simplify the test case (last patch)
Patch 5: Protect io_uring_cmd_sock() to not be called if CONFIG_NET is
disabled.
Important to say that userspace pointers need to be alive until the
operation is completed, as in the systemcall.
These changes were tested with a new test[1] in liburing, LTP sockopt*
tests, as also with bpf/progs/sockopt test case, which is now adapted to
run using both system calls and io_uring commands.
[1] Link: https://github.com/leitao/liburing/blob/getsock/test/socket-getsetsock-cmd.c
RFC -> V1:
* Copy user memory at io_uring subsystem, and call proto_ops
callbacks using kernel memory
* Implement all the cases for SOCKET_URING_OP_SETSOCKOPT
V1 -> V2
* Implemented the BPF part
* Using user pointers from optval to avoid kmalloc in io_uring part.
V2 -> V3:
* Break down __sys_setsockopt and reuse the core code, avoiding
duplicated code. This removed the requirement to expose
sock_use_custom_sol_socket().
* Added io_uring test to selftests/bpf/sockopt.
* Fixed compat argument, by passing it to the issue_flags.
V3 -> V4:
* Rebase on top of commit 1ded5e5a5931b ("net: annotate data-races around sock->ops")
* Also broke down __sys_setsockopt() to reuse the core function
from io_uring.
* Create a new patch to return -EOPNOTSUPP if CONFIG_NET is
disabled
* Added two SOL_SOCKET tests in bpf/prog_tests/sockopt.
V4 -> V5:
* Do not use sockptr anymore, by changing the optlen getsock argument
to be a user pointer (instead of a kernel pointer). This change also drop
the limitation on getsockopt from previous versions, and now all
levels are supported.
* Simplified the BPF sockopt test, since there is no more limitation on
the io_uring commands.
* No more changes in the BPF subsystem.
* Moved the optlen field in the SQE struct. It is now a pointer instead
of u32.
Breno Leitao (8):
net/socket: Break down __sys_setsockopt
net/socket: Break down __sys_getsockopt
io_uring/cmd: Pass compat mode in issue_flags
selftests/net: Extract uring helpers to be reusable
io_uring/cmd: return -EOPNOTSUPP if net is disabled
io_uring/cmd: Introduce SOCKET_URING_OP_GETSOCKOPT
io_uring/cmd: Introduce SOCKET_URING_OP_SETSOCKOPT
selftests/bpf/sockopt: Add io_uring support
include/linux/io_uring.h | 1 +
include/net/sock.h | 5 +
include/uapi/linux/io_uring.h | 10 +
io_uring/uring_cmd.c | 41 +++
net/socket.c | 89 ++++--
tools/include/io_uring/mini_liburing.h | 292 ++++++++++++++++++
.../selftests/bpf/prog_tests/sockopt.c | 95 +++++-
tools/testing/selftests/net/Makefile | 1 +
.../selftests/net/io_uring_zerocopy_tx.c | 268 +---------------
9 files changed, 497 insertions(+), 305 deletions(-)
create mode 100644 tools/include/io_uring/mini_liburing.h
--
2.34.1
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v5 1/8] net/socket: Break down __sys_setsockopt
2023-09-11 10:33 [PATCH v5 0/8] io_uring: Initial support for {s,g}etsockopt commands Breno Leitao
@ 2023-09-11 10:34 ` Breno Leitao
2023-09-11 10:34 ` [PATCH v5 2/8] net/socket: Break down __sys_getsockopt Breno Leitao
` (6 subsequent siblings)
7 siblings, 0 replies; 14+ messages in thread
From: Breno Leitao @ 2023-09-11 10:34 UTC (permalink / raw)
To: sdf, axboe, asml.silence, willemdebruijn.kernel, kuba, martin.lau,
krisman, David S. Miller, Eric Dumazet, Paolo Abeni
Cc: bpf, linux-kernel, netdev, io-uring, Willem de Bruijn
Split __sys_setsockopt() into two functions by removing the core
logic into a sub-function (do_sock_setsockopt()). This will avoid
code duplication when doing the same operation in other callers, for
instance.
do_sock_setsockopt() will be called by io_uring setsockopt() command
operation in the following patch.
Signed-off-by: Breno Leitao <[email protected]>
Reviewed-by: Willem de Bruijn <[email protected]>
---
include/net/sock.h | 2 ++
net/socket.c | 38 +++++++++++++++++++++++++-------------
2 files changed, 27 insertions(+), 13 deletions(-)
diff --git a/include/net/sock.h b/include/net/sock.h
index 11d503417591..aa8fb54ad0af 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1861,6 +1861,8 @@ int sk_setsockopt(struct sock *sk, int level, int optname,
sockptr_t optval, unsigned int optlen);
int sock_setsockopt(struct socket *sock, int level, int op,
sockptr_t optval, unsigned int optlen);
+int do_sock_setsockopt(struct socket *sock, bool compat, int level,
+ int optname, char __user *user_optval, int optlen);
int sk_getsockopt(struct sock *sk, int level, int optname,
sockptr_t optval, sockptr_t optlen);
diff --git a/net/socket.c b/net/socket.c
index 77f28328e387..360332e098d4 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -2261,31 +2261,22 @@ static bool sock_use_custom_sol_socket(const struct socket *sock)
return test_bit(SOCK_CUSTOM_SOCKOPT, &sock->flags);
}
-/*
- * Set a socket option. Because we don't know the option lengths we have
- * to pass the user mode parameter for the protocols to sort out.
- */
-int __sys_setsockopt(int fd, int level, int optname, char __user *user_optval,
- int optlen)
+int do_sock_setsockopt(struct socket *sock, bool compat, int level,
+ int optname, char __user *user_optval, int optlen)
{
sockptr_t optval = USER_SOCKPTR(user_optval);
const struct proto_ops *ops;
char *kernel_optval = NULL;
- int err, fput_needed;
- struct socket *sock;
+ int err;
if (optlen < 0)
return -EINVAL;
- sock = sockfd_lookup_light(fd, &err, &fput_needed);
- if (!sock)
- return err;
-
err = security_socket_setsockopt(sock, level, optname);
if (err)
goto out_put;
- if (!in_compat_syscall())
+ if (!compat)
err = BPF_CGROUP_RUN_PROG_SETSOCKOPT(sock->sk, &level, &optname,
user_optval, &optlen,
&kernel_optval);
@@ -2308,6 +2299,27 @@ int __sys_setsockopt(int fd, int level, int optname, char __user *user_optval,
optlen);
kfree(kernel_optval);
out_put:
+ return err;
+}
+EXPORT_SYMBOL(do_sock_setsockopt);
+
+/* Set a socket option. Because we don't know the option lengths we have
+ * to pass the user mode parameter for the protocols to sort out.
+ */
+int __sys_setsockopt(int fd, int level, int optname, char __user *user_optval,
+ int optlen)
+{
+ bool compat = in_compat_syscall();
+ int err, fput_needed;
+ struct socket *sock;
+
+ sock = sockfd_lookup_light(fd, &err, &fput_needed);
+ if (!sock)
+ return err;
+
+ err = do_sock_setsockopt(sock, compat, level, optname, user_optval,
+ optlen);
+
fput_light(sock->file, fput_needed);
return err;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v5 2/8] net/socket: Break down __sys_getsockopt
2023-09-11 10:33 [PATCH v5 0/8] io_uring: Initial support for {s,g}etsockopt commands Breno Leitao
2023-09-11 10:34 ` [PATCH v5 1/8] net/socket: Break down __sys_setsockopt Breno Leitao
@ 2023-09-11 10:34 ` Breno Leitao
2023-09-12 9:37 ` Paolo Abeni
2023-09-11 10:34 ` [PATCH v5 3/8] io_uring/cmd: Pass compat mode in issue_flags Breno Leitao
` (5 subsequent siblings)
7 siblings, 1 reply; 14+ messages in thread
From: Breno Leitao @ 2023-09-11 10:34 UTC (permalink / raw)
To: sdf, axboe, asml.silence, willemdebruijn.kernel, kuba, martin.lau,
krisman, David S. Miller, Eric Dumazet, Paolo Abeni
Cc: bpf, linux-kernel, netdev, io-uring
Split __sys_getsockopt() into two functions by removing the core
logic into a sub-function (do_sock_getsockopt()). This will avoid
code duplication when executing the same operation in other callers, for
instance.
do_sock_getsockopt() will be called by io_uring getsockopt() command
operation in the following patch.
Suggested-by: Martin KaFai Lau <[email protected]>
Signed-off-by: Breno Leitao <[email protected]>
---
include/net/sock.h | 3 +++
net/socket.c | 51 ++++++++++++++++++++++++++++------------------
2 files changed, 34 insertions(+), 20 deletions(-)
diff --git a/include/net/sock.h b/include/net/sock.h
index aa8fb54ad0af..fbd568a43d28 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1863,6 +1863,9 @@ int sock_setsockopt(struct socket *sock, int level, int op,
sockptr_t optval, unsigned int optlen);
int do_sock_setsockopt(struct socket *sock, bool compat, int level,
int optname, char __user *user_optval, int optlen);
+int do_sock_getsockopt(struct socket *sock, bool compat, int level,
+ int optname, char __user *user_optval,
+ int __user *user_optlen);
int sk_getsockopt(struct sock *sk, int level, int optname,
sockptr_t optval, sockptr_t optlen);
diff --git a/net/socket.c b/net/socket.c
index 360332e098d4..3ec779a56f79 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -2333,28 +2333,17 @@ SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname,
INDIRECT_CALLABLE_DECLARE(bool tcp_bpf_bypass_getsockopt(int level,
int optname));
-/*
- * Get a socket option. Because we don't know the option lengths we have
- * to pass a user mode parameter for the protocols to sort out.
- */
-int __sys_getsockopt(int fd, int level, int optname, char __user *optval,
- int __user *optlen)
+int do_sock_getsockopt(struct socket *sock, bool compat, int level,
+ int optname, char __user *optval,
+ int __user *optlen)
{
int max_optlen __maybe_unused;
const struct proto_ops *ops;
- int err, fput_needed;
- struct socket *sock;
-
- sock = sockfd_lookup_light(fd, &err, &fput_needed);
- if (!sock)
- return err;
+ int err;
err = security_socket_getsockopt(sock, level, optname);
if (err)
- goto out_put;
-
- if (!in_compat_syscall())
- max_optlen = BPF_CGROUP_GETSOCKOPT_MAX_OPTLEN(optlen);
+ return err;
ops = READ_ONCE(sock->ops);
if (level == SOL_SOCKET)
@@ -2362,14 +2351,36 @@ int __sys_getsockopt(int fd, int level, int optname, char __user *optval,
else if (unlikely(!ops->getsockopt))
err = -EOPNOTSUPP;
else
- err = ops->getsockopt(sock, level, optname, optval,
- optlen);
+ err = ops->getsockopt(sock, level, optname, optval, optlen);
- if (!in_compat_syscall())
+ if (!compat) {
+ max_optlen = BPF_CGROUP_GETSOCKOPT_MAX_OPTLEN(optlen);
err = BPF_CGROUP_RUN_PROG_GETSOCKOPT(sock->sk, level, optname,
optval, optlen, max_optlen,
err);
-out_put:
+ }
+
+ return err;
+}
+EXPORT_SYMBOL(do_sock_getsockopt);
+
+/* Get a socket option. Because we don't know the option lengths we have
+ * to pass a user mode parameter for the protocols to sort out.
+ */
+int __sys_getsockopt(int fd, int level, int optname, char __user *optval,
+ int __user *optlen)
+{
+ int err, fput_needed;
+ bool compat = in_compat_syscall();
+ struct socket *sock;
+
+ sock = sockfd_lookup_light(fd, &err, &fput_needed);
+ if (!sock)
+ return err;
+
+ err = do_sock_getsockopt(sock, compat, level, optname, optval,
+ optlen);
+
fput_light(sock->file, fput_needed);
return err;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v5 3/8] io_uring/cmd: Pass compat mode in issue_flags
2023-09-11 10:33 [PATCH v5 0/8] io_uring: Initial support for {s,g}etsockopt commands Breno Leitao
2023-09-11 10:34 ` [PATCH v5 1/8] net/socket: Break down __sys_setsockopt Breno Leitao
2023-09-11 10:34 ` [PATCH v5 2/8] net/socket: Break down __sys_getsockopt Breno Leitao
@ 2023-09-11 10:34 ` Breno Leitao
2023-09-11 15:42 ` Gabriel Krisman Bertazi
2023-09-11 10:34 ` [PATCH v5 4/8] selftests/net: Extract uring helpers to be reusable Breno Leitao
` (4 subsequent siblings)
7 siblings, 1 reply; 14+ messages in thread
From: Breno Leitao @ 2023-09-11 10:34 UTC (permalink / raw)
To: sdf, axboe, asml.silence, willemdebruijn.kernel, kuba, martin.lau,
krisman
Cc: bpf, linux-kernel, netdev, io-uring, pabeni
Create a new flag to track if the operation is running compat mode.
This basically check the context->compat and pass it to the issue_flags,
so, it could be queried later in the callbacks.
Signed-off-by: Breno Leitao <[email protected]>
---
include/linux/io_uring.h | 1 +
io_uring/uring_cmd.c | 2 ++
2 files changed, 3 insertions(+)
diff --git a/include/linux/io_uring.h b/include/linux/io_uring.h
index 106cdc55ff3b..bc53b35966ed 100644
--- a/include/linux/io_uring.h
+++ b/include/linux/io_uring.h
@@ -20,6 +20,7 @@ enum io_uring_cmd_flags {
IO_URING_F_SQE128 = (1 << 8),
IO_URING_F_CQE32 = (1 << 9),
IO_URING_F_IOPOLL = (1 << 10),
+ IO_URING_F_COMPAT = (1 << 11),
};
struct io_uring_cmd {
diff --git a/io_uring/uring_cmd.c b/io_uring/uring_cmd.c
index 537795fddc87..60f843a357e0 100644
--- a/io_uring/uring_cmd.c
+++ b/io_uring/uring_cmd.c
@@ -128,6 +128,8 @@ int io_uring_cmd(struct io_kiocb *req, unsigned int issue_flags)
issue_flags |= IO_URING_F_SQE128;
if (ctx->flags & IORING_SETUP_CQE32)
issue_flags |= IO_URING_F_CQE32;
+ if (ctx->compat)
+ issue_flags |= IO_URING_F_COMPAT;
if (ctx->flags & IORING_SETUP_IOPOLL) {
if (!file->f_op->uring_cmd_iopoll)
return -EOPNOTSUPP;
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v5 4/8] selftests/net: Extract uring helpers to be reusable
2023-09-11 10:33 [PATCH v5 0/8] io_uring: Initial support for {s,g}etsockopt commands Breno Leitao
` (2 preceding siblings ...)
2023-09-11 10:34 ` [PATCH v5 3/8] io_uring/cmd: Pass compat mode in issue_flags Breno Leitao
@ 2023-09-11 10:34 ` Breno Leitao
2023-09-11 10:34 ` [PATCH v5 5/8] io_uring/cmd: return -EOPNOTSUPP if net is disabled Breno Leitao
` (3 subsequent siblings)
7 siblings, 0 replies; 14+ messages in thread
From: Breno Leitao @ 2023-09-11 10:34 UTC (permalink / raw)
To: sdf, axboe, asml.silence, willemdebruijn.kernel, kuba, martin.lau,
krisman, David S. Miller, Eric Dumazet, Paolo Abeni, Shuah Khan
Cc: bpf, linux-kernel, netdev, io-uring,
open list:KERNEL SELFTEST FRAMEWORK
Instead of defining basic io_uring functions in the test case, move them
to a common directory, so, other tests can use them.
This simplify the test code and reuse the common "mini" liburing
infrastructure. This is basically a copy of what we have in
io_uring_zerocopy_tx with some minor improvements.
A follow-up test will use the same helpers in a BPF sockopt test.
Signed-off-by: Breno Leitao <[email protected]>
---
tools/include/io_uring/mini_liburing.h | 292 ++++++++++++++++++
tools/testing/selftests/net/Makefile | 1 +
.../selftests/net/io_uring_zerocopy_tx.c | 268 +---------------
3 files changed, 295 insertions(+), 266 deletions(-)
create mode 100644 tools/include/io_uring/mini_liburing.h
diff --git a/tools/include/io_uring/mini_liburing.h b/tools/include/io_uring/mini_liburing.h
new file mode 100644
index 000000000000..e0e1e76def25
--- /dev/null
+++ b/tools/include/io_uring/mini_liburing.h
@@ -0,0 +1,292 @@
+/* SPDX-License-Identifier: MIT */
+
+#include <linux/io_uring.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+struct io_sq_ring {
+ unsigned int *head;
+ unsigned int *tail;
+ unsigned int *ring_mask;
+ unsigned int *ring_entries;
+ unsigned int *flags;
+ unsigned int *array;
+};
+
+struct io_cq_ring {
+ unsigned int *head;
+ unsigned int *tail;
+ unsigned int *ring_mask;
+ unsigned int *ring_entries;
+ struct io_uring_cqe *cqes;
+};
+
+struct io_uring_sq {
+ unsigned int *khead;
+ unsigned int *ktail;
+ unsigned int *kring_mask;
+ unsigned int *kring_entries;
+ unsigned int *kflags;
+ unsigned int *kdropped;
+ unsigned int *array;
+ struct io_uring_sqe *sqes;
+
+ unsigned int sqe_head;
+ unsigned int sqe_tail;
+
+ size_t ring_sz;
+};
+
+struct io_uring_cq {
+ unsigned int *khead;
+ unsigned int *ktail;
+ unsigned int *kring_mask;
+ unsigned int *kring_entries;
+ unsigned int *koverflow;
+ struct io_uring_cqe *cqes;
+
+ size_t ring_sz;
+};
+
+struct io_uring {
+ struct io_uring_sq sq;
+ struct io_uring_cq cq;
+ int ring_fd;
+};
+
+#if defined(__x86_64) || defined(__i386__)
+#define read_barrier() __asm__ __volatile__("":::"memory")
+#define write_barrier() __asm__ __volatile__("":::"memory")
+#else
+#define read_barrier() __sync_synchronize()
+#define write_barrier() __sync_synchronize()
+#endif
+
+static inline int io_uring_mmap(int fd, struct io_uring_params *p,
+ struct io_uring_sq *sq, struct io_uring_cq *cq)
+{
+ size_t size;
+ void *ptr;
+ int ret;
+
+ sq->ring_sz = p->sq_off.array + p->sq_entries * sizeof(unsigned int);
+ ptr = mmap(0, sq->ring_sz, PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_POPULATE, fd, IORING_OFF_SQ_RING);
+ if (ptr == MAP_FAILED)
+ return -errno;
+ sq->khead = ptr + p->sq_off.head;
+ sq->ktail = ptr + p->sq_off.tail;
+ sq->kring_mask = ptr + p->sq_off.ring_mask;
+ sq->kring_entries = ptr + p->sq_off.ring_entries;
+ sq->kflags = ptr + p->sq_off.flags;
+ sq->kdropped = ptr + p->sq_off.dropped;
+ sq->array = ptr + p->sq_off.array;
+
+ size = p->sq_entries * sizeof(struct io_uring_sqe);
+ sq->sqes = mmap(0, size, PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_POPULATE, fd, IORING_OFF_SQES);
+ if (sq->sqes == MAP_FAILED) {
+ ret = -errno;
+err:
+ munmap(sq->khead, sq->ring_sz);
+ return ret;
+ }
+
+ cq->ring_sz = p->cq_off.cqes + p->cq_entries * sizeof(struct io_uring_cqe);
+ ptr = mmap(0, cq->ring_sz, PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_POPULATE, fd, IORING_OFF_CQ_RING);
+ if (ptr == MAP_FAILED) {
+ ret = -errno;
+ munmap(sq->sqes, p->sq_entries * sizeof(struct io_uring_sqe));
+ goto err;
+ }
+ cq->khead = ptr + p->cq_off.head;
+ cq->ktail = ptr + p->cq_off.tail;
+ cq->kring_mask = ptr + p->cq_off.ring_mask;
+ cq->kring_entries = ptr + p->cq_off.ring_entries;
+ cq->koverflow = ptr + p->cq_off.overflow;
+ cq->cqes = ptr + p->cq_off.cqes;
+ return 0;
+}
+
+static inline int io_uring_setup(unsigned int entries,
+ struct io_uring_params *p)
+{
+ return syscall(__NR_io_uring_setup, entries, p);
+}
+
+static inline int io_uring_enter(int fd, unsigned int to_submit,
+ unsigned int min_complete,
+ unsigned int flags, sigset_t *sig)
+{
+ return syscall(__NR_io_uring_enter, fd, to_submit, min_complete,
+ flags, sig, _NSIG / 8);
+}
+
+static inline int io_uring_queue_init(unsigned int entries,
+ struct io_uring *ring,
+ unsigned int flags)
+{
+ struct io_uring_params p;
+ int fd, ret;
+
+ memset(ring, 0, sizeof(*ring));
+ memset(&p, 0, sizeof(p));
+ p.flags = flags;
+
+ fd = io_uring_setup(entries, &p);
+ if (fd < 0)
+ return fd;
+ ret = io_uring_mmap(fd, &p, &ring->sq, &ring->cq);
+ if (!ret)
+ ring->ring_fd = fd;
+ else
+ close(fd);
+ return ret;
+}
+
+/* Get a sqe */
+static inline struct io_uring_sqe *io_uring_get_sqe(struct io_uring *ring)
+{
+ struct io_uring_sq *sq = &ring->sq;
+
+ if (sq->sqe_tail + 1 - sq->sqe_head > *sq->kring_entries)
+ return NULL;
+ return &sq->sqes[sq->sqe_tail++ & *sq->kring_mask];
+}
+
+static inline int io_uring_wait_cqe(struct io_uring *ring,
+ struct io_uring_cqe **cqe_ptr)
+{
+ struct io_uring_cq *cq = &ring->cq;
+ const unsigned int mask = *cq->kring_mask;
+ unsigned int head = *cq->khead;
+ int ret;
+
+ *cqe_ptr = NULL;
+ do {
+ read_barrier();
+ if (head != *cq->ktail) {
+ *cqe_ptr = &cq->cqes[head & mask];
+ break;
+ }
+ ret = io_uring_enter(ring->ring_fd, 0, 1,
+ IORING_ENTER_GETEVENTS, NULL);
+ if (ret < 0)
+ return -errno;
+ } while (1);
+
+ return 0;
+}
+
+static inline int io_uring_submit(struct io_uring *ring)
+{
+ struct io_uring_sq *sq = &ring->sq;
+ const unsigned int mask = *sq->kring_mask;
+ unsigned int ktail, submitted, to_submit;
+ int ret;
+
+ read_barrier();
+ if (*sq->khead != *sq->ktail) {
+ submitted = *sq->kring_entries;
+ goto submit;
+ }
+ if (sq->sqe_head == sq->sqe_tail)
+ return 0;
+
+ ktail = *sq->ktail;
+ to_submit = sq->sqe_tail - sq->sqe_head;
+ for (submitted = 0; submitted < to_submit; submitted++) {
+ read_barrier();
+ sq->array[ktail++ & mask] = sq->sqe_head++ & mask;
+ }
+ if (!submitted)
+ return 0;
+
+ if (*sq->ktail != ktail) {
+ write_barrier();
+ *sq->ktail = ktail;
+ write_barrier();
+ }
+submit:
+ ret = io_uring_enter(ring->ring_fd, submitted, 0,
+ IORING_ENTER_GETEVENTS, NULL);
+ return ret < 0 ? -errno : ret;
+}
+
+static inline void io_uring_queue_exit(struct io_uring *ring)
+{
+ struct io_uring_sq *sq = &ring->sq;
+
+ munmap(sq->sqes, *sq->kring_entries * sizeof(struct io_uring_sqe));
+ munmap(sq->khead, sq->ring_sz);
+ close(ring->ring_fd);
+}
+
+/* Prepare and send the SQE */
+static inline void io_uring_prep_cmd(struct io_uring_sqe *sqe, int op,
+ int sockfd,
+ int level, int optname,
+ const void *optval,
+ const socklen_t optlen)
+{
+ memset(sqe, 0, sizeof(*sqe));
+ sqe->opcode = (__u8)IORING_OP_URING_CMD;
+ sqe->fd = sockfd;
+ sqe->cmd_op = op;
+
+ sqe->level = level;
+ sqe->optname = optname;
+ sqe->optval = (unsigned long long)optval;
+ sqe->optlen = (unsigned long long)optlen;
+}
+
+static inline void io_uring_prep_cmd_get(struct io_uring_sqe *sqe, int op,
+ int sockfd,
+ int level, int optname,
+ const void *optval,
+ const socklen_t *optlen)
+{
+ io_uring_prep_cmd(sqe, op, sockfd, level, optname, optval, 0);
+ sqe->optlen = (unsigned long long)optlen;
+}
+
+static inline int io_uring_register_buffers(struct io_uring *ring,
+ const struct iovec *iovecs,
+ unsigned int nr_iovecs)
+{
+ int ret;
+
+ ret = syscall(__NR_io_uring_register, ring->ring_fd,
+ IORING_REGISTER_BUFFERS, iovecs, nr_iovecs);
+ return (ret < 0) ? -errno : ret;
+}
+
+static inline void io_uring_prep_send(struct io_uring_sqe *sqe, int sockfd,
+ const void *buf, size_t len, int flags)
+{
+ memset(sqe, 0, sizeof(*sqe));
+ sqe->opcode = (__u8)IORING_OP_SEND;
+ sqe->fd = sockfd;
+ sqe->addr = (unsigned long)buf;
+ sqe->len = len;
+ sqe->msg_flags = (__u32)flags;
+}
+
+static inline void io_uring_prep_sendzc(struct io_uring_sqe *sqe, int sockfd,
+ const void *buf, size_t len, int flags,
+ unsigned int zc_flags)
+{
+ io_uring_prep_send(sqe, sockfd, buf, len, flags);
+ sqe->opcode = (__u8)IORING_OP_SEND_ZC;
+ sqe->ioprio = zc_flags;
+}
+
+static inline void io_uring_cqe_seen(struct io_uring *ring)
+{
+ *(&ring->cq)->khead += 1;
+ write_barrier();
+}
diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
index 8b017070960d..f8d99837b9dc 100644
--- a/tools/testing/selftests/net/Makefile
+++ b/tools/testing/selftests/net/Makefile
@@ -98,6 +98,7 @@ $(OUTPUT)/reuseport_bpf_numa: LDLIBS += -lnuma
$(OUTPUT)/tcp_mmap: LDLIBS += -lpthread -lcrypto
$(OUTPUT)/tcp_inq: LDLIBS += -lpthread
$(OUTPUT)/bind_bhash: LDLIBS += -lpthread
+$(OUTPUT)/io_uring_zerocopy_tx: CFLAGS += -I../../../include/
# Rules to generate bpf obj nat6to4.o
CLANG ?= clang
diff --git a/tools/testing/selftests/net/io_uring_zerocopy_tx.c b/tools/testing/selftests/net/io_uring_zerocopy_tx.c
index 154287740172..76e604e4810e 100644
--- a/tools/testing/selftests/net/io_uring_zerocopy_tx.c
+++ b/tools/testing/selftests/net/io_uring_zerocopy_tx.c
@@ -36,6 +36,8 @@
#include <sys/un.h>
#include <sys/wait.h>
+#include <io_uring/mini_liburing.h>
+
#define NOTIF_TAG 0xfffffffULL
#define NONZC_TAG 0
#define ZC_TAG 1
@@ -60,272 +62,6 @@ static struct sockaddr_storage cfg_dst_addr;
static char payload[IP_MAXPACKET] __attribute__((aligned(4096)));
-struct io_sq_ring {
- unsigned *head;
- unsigned *tail;
- unsigned *ring_mask;
- unsigned *ring_entries;
- unsigned *flags;
- unsigned *array;
-};
-
-struct io_cq_ring {
- unsigned *head;
- unsigned *tail;
- unsigned *ring_mask;
- unsigned *ring_entries;
- struct io_uring_cqe *cqes;
-};
-
-struct io_uring_sq {
- unsigned *khead;
- unsigned *ktail;
- unsigned *kring_mask;
- unsigned *kring_entries;
- unsigned *kflags;
- unsigned *kdropped;
- unsigned *array;
- struct io_uring_sqe *sqes;
-
- unsigned sqe_head;
- unsigned sqe_tail;
-
- size_t ring_sz;
-};
-
-struct io_uring_cq {
- unsigned *khead;
- unsigned *ktail;
- unsigned *kring_mask;
- unsigned *kring_entries;
- unsigned *koverflow;
- struct io_uring_cqe *cqes;
-
- size_t ring_sz;
-};
-
-struct io_uring {
- struct io_uring_sq sq;
- struct io_uring_cq cq;
- int ring_fd;
-};
-
-#ifdef __alpha__
-# ifndef __NR_io_uring_setup
-# define __NR_io_uring_setup 535
-# endif
-# ifndef __NR_io_uring_enter
-# define __NR_io_uring_enter 536
-# endif
-# ifndef __NR_io_uring_register
-# define __NR_io_uring_register 537
-# endif
-#else /* !__alpha__ */
-# ifndef __NR_io_uring_setup
-# define __NR_io_uring_setup 425
-# endif
-# ifndef __NR_io_uring_enter
-# define __NR_io_uring_enter 426
-# endif
-# ifndef __NR_io_uring_register
-# define __NR_io_uring_register 427
-# endif
-#endif
-
-#if defined(__x86_64) || defined(__i386__)
-#define read_barrier() __asm__ __volatile__("":::"memory")
-#define write_barrier() __asm__ __volatile__("":::"memory")
-#else
-
-#define read_barrier() __sync_synchronize()
-#define write_barrier() __sync_synchronize()
-#endif
-
-static int io_uring_setup(unsigned int entries, struct io_uring_params *p)
-{
- return syscall(__NR_io_uring_setup, entries, p);
-}
-
-static int io_uring_enter(int fd, unsigned int to_submit,
- unsigned int min_complete,
- unsigned int flags, sigset_t *sig)
-{
- return syscall(__NR_io_uring_enter, fd, to_submit, min_complete,
- flags, sig, _NSIG / 8);
-}
-
-static int io_uring_register_buffers(struct io_uring *ring,
- const struct iovec *iovecs,
- unsigned nr_iovecs)
-{
- int ret;
-
- ret = syscall(__NR_io_uring_register, ring->ring_fd,
- IORING_REGISTER_BUFFERS, iovecs, nr_iovecs);
- return (ret < 0) ? -errno : ret;
-}
-
-static int io_uring_mmap(int fd, struct io_uring_params *p,
- struct io_uring_sq *sq, struct io_uring_cq *cq)
-{
- size_t size;
- void *ptr;
- int ret;
-
- sq->ring_sz = p->sq_off.array + p->sq_entries * sizeof(unsigned);
- ptr = mmap(0, sq->ring_sz, PROT_READ | PROT_WRITE,
- MAP_SHARED | MAP_POPULATE, fd, IORING_OFF_SQ_RING);
- if (ptr == MAP_FAILED)
- return -errno;
- sq->khead = ptr + p->sq_off.head;
- sq->ktail = ptr + p->sq_off.tail;
- sq->kring_mask = ptr + p->sq_off.ring_mask;
- sq->kring_entries = ptr + p->sq_off.ring_entries;
- sq->kflags = ptr + p->sq_off.flags;
- sq->kdropped = ptr + p->sq_off.dropped;
- sq->array = ptr + p->sq_off.array;
-
- size = p->sq_entries * sizeof(struct io_uring_sqe);
- sq->sqes = mmap(0, size, PROT_READ | PROT_WRITE,
- MAP_SHARED | MAP_POPULATE, fd, IORING_OFF_SQES);
- if (sq->sqes == MAP_FAILED) {
- ret = -errno;
-err:
- munmap(sq->khead, sq->ring_sz);
- return ret;
- }
-
- cq->ring_sz = p->cq_off.cqes + p->cq_entries * sizeof(struct io_uring_cqe);
- ptr = mmap(0, cq->ring_sz, PROT_READ | PROT_WRITE,
- MAP_SHARED | MAP_POPULATE, fd, IORING_OFF_CQ_RING);
- if (ptr == MAP_FAILED) {
- ret = -errno;
- munmap(sq->sqes, p->sq_entries * sizeof(struct io_uring_sqe));
- goto err;
- }
- cq->khead = ptr + p->cq_off.head;
- cq->ktail = ptr + p->cq_off.tail;
- cq->kring_mask = ptr + p->cq_off.ring_mask;
- cq->kring_entries = ptr + p->cq_off.ring_entries;
- cq->koverflow = ptr + p->cq_off.overflow;
- cq->cqes = ptr + p->cq_off.cqes;
- return 0;
-}
-
-static int io_uring_queue_init(unsigned entries, struct io_uring *ring,
- unsigned flags)
-{
- struct io_uring_params p;
- int fd, ret;
-
- memset(ring, 0, sizeof(*ring));
- memset(&p, 0, sizeof(p));
- p.flags = flags;
-
- fd = io_uring_setup(entries, &p);
- if (fd < 0)
- return fd;
- ret = io_uring_mmap(fd, &p, &ring->sq, &ring->cq);
- if (!ret)
- ring->ring_fd = fd;
- else
- close(fd);
- return ret;
-}
-
-static int io_uring_submit(struct io_uring *ring)
-{
- struct io_uring_sq *sq = &ring->sq;
- const unsigned mask = *sq->kring_mask;
- unsigned ktail, submitted, to_submit;
- int ret;
-
- read_barrier();
- if (*sq->khead != *sq->ktail) {
- submitted = *sq->kring_entries;
- goto submit;
- }
- if (sq->sqe_head == sq->sqe_tail)
- return 0;
-
- ktail = *sq->ktail;
- to_submit = sq->sqe_tail - sq->sqe_head;
- for (submitted = 0; submitted < to_submit; submitted++) {
- read_barrier();
- sq->array[ktail++ & mask] = sq->sqe_head++ & mask;
- }
- if (!submitted)
- return 0;
-
- if (*sq->ktail != ktail) {
- write_barrier();
- *sq->ktail = ktail;
- write_barrier();
- }
-submit:
- ret = io_uring_enter(ring->ring_fd, submitted, 0,
- IORING_ENTER_GETEVENTS, NULL);
- return ret < 0 ? -errno : ret;
-}
-
-static inline void io_uring_prep_send(struct io_uring_sqe *sqe, int sockfd,
- const void *buf, size_t len, int flags)
-{
- memset(sqe, 0, sizeof(*sqe));
- sqe->opcode = (__u8) IORING_OP_SEND;
- sqe->fd = sockfd;
- sqe->addr = (unsigned long) buf;
- sqe->len = len;
- sqe->msg_flags = (__u32) flags;
-}
-
-static inline void io_uring_prep_sendzc(struct io_uring_sqe *sqe, int sockfd,
- const void *buf, size_t len, int flags,
- unsigned zc_flags)
-{
- io_uring_prep_send(sqe, sockfd, buf, len, flags);
- sqe->opcode = (__u8) IORING_OP_SEND_ZC;
- sqe->ioprio = zc_flags;
-}
-
-static struct io_uring_sqe *io_uring_get_sqe(struct io_uring *ring)
-{
- struct io_uring_sq *sq = &ring->sq;
-
- if (sq->sqe_tail + 1 - sq->sqe_head > *sq->kring_entries)
- return NULL;
- return &sq->sqes[sq->sqe_tail++ & *sq->kring_mask];
-}
-
-static int io_uring_wait_cqe(struct io_uring *ring, struct io_uring_cqe **cqe_ptr)
-{
- struct io_uring_cq *cq = &ring->cq;
- const unsigned mask = *cq->kring_mask;
- unsigned head = *cq->khead;
- int ret;
-
- *cqe_ptr = NULL;
- do {
- read_barrier();
- if (head != *cq->ktail) {
- *cqe_ptr = &cq->cqes[head & mask];
- break;
- }
- ret = io_uring_enter(ring->ring_fd, 0, 1,
- IORING_ENTER_GETEVENTS, NULL);
- if (ret < 0)
- return -errno;
- } while (1);
-
- return 0;
-}
-
-static inline void io_uring_cqe_seen(struct io_uring *ring)
-{
- *(&ring->cq)->khead += 1;
- write_barrier();
-}
-
static unsigned long gettimeofday_ms(void)
{
struct timeval tv;
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v5 5/8] io_uring/cmd: return -EOPNOTSUPP if net is disabled
2023-09-11 10:33 [PATCH v5 0/8] io_uring: Initial support for {s,g}etsockopt commands Breno Leitao
` (3 preceding siblings ...)
2023-09-11 10:34 ` [PATCH v5 4/8] selftests/net: Extract uring helpers to be reusable Breno Leitao
@ 2023-09-11 10:34 ` Breno Leitao
2023-09-11 15:53 ` Gabriel Krisman Bertazi
2023-09-11 10:34 ` [PATCH v5 6/8] io_uring/cmd: Introduce SOCKET_URING_OP_GETSOCKOPT Breno Leitao
` (2 subsequent siblings)
7 siblings, 1 reply; 14+ messages in thread
From: Breno Leitao @ 2023-09-11 10:34 UTC (permalink / raw)
To: sdf, axboe, asml.silence, willemdebruijn.kernel, kuba, martin.lau,
krisman
Cc: bpf, linux-kernel, netdev, io-uring, pabeni
Protect io_uring_cmd_sock() to be called if CONFIG_NET is not set. If
network is not enabled, but io_uring is, then we want to return
-EOPNOTSUPP for any possible socket operation.
This is helpful because io_uring_cmd_sock() can now call functions that
only exits if CONFIG_NET is enabled without having #ifdef CONFIG_NET
inside the function itself.
Signed-off-by: Breno Leitao <[email protected]>
---
io_uring/uring_cmd.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/io_uring/uring_cmd.c b/io_uring/uring_cmd.c
index 60f843a357e0..a7d6a7d112b7 100644
--- a/io_uring/uring_cmd.c
+++ b/io_uring/uring_cmd.c
@@ -167,6 +167,7 @@ int io_uring_cmd_import_fixed(u64 ubuf, unsigned long len, int rw,
}
EXPORT_SYMBOL_GPL(io_uring_cmd_import_fixed);
+#if defined(CONFIG_NET)
int io_uring_cmd_sock(struct io_uring_cmd *cmd, unsigned int issue_flags)
{
struct socket *sock = cmd->file->private_data;
@@ -193,3 +194,10 @@ int io_uring_cmd_sock(struct io_uring_cmd *cmd, unsigned int issue_flags)
}
}
EXPORT_SYMBOL_GPL(io_uring_cmd_sock);
+#else
+int io_uring_cmd_sock(struct io_uring_cmd *cmd, unsigned int issue_flags)
+{
+ return -EOPNOTSUPP;
+}
+#endif
+
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v5 6/8] io_uring/cmd: Introduce SOCKET_URING_OP_GETSOCKOPT
2023-09-11 10:33 [PATCH v5 0/8] io_uring: Initial support for {s,g}etsockopt commands Breno Leitao
` (4 preceding siblings ...)
2023-09-11 10:34 ` [PATCH v5 5/8] io_uring/cmd: return -EOPNOTSUPP if net is disabled Breno Leitao
@ 2023-09-11 10:34 ` Breno Leitao
2023-09-11 10:34 ` [PATCH v5 7/8] io_uring/cmd: Introduce SOCKET_URING_OP_SETSOCKOPT Breno Leitao
2023-09-11 10:34 ` [PATCH v5 8/8] selftests/bpf/sockopt: Add io_uring support Breno Leitao
7 siblings, 0 replies; 14+ messages in thread
From: Breno Leitao @ 2023-09-11 10:34 UTC (permalink / raw)
To: sdf, axboe, asml.silence, willemdebruijn.kernel, kuba, martin.lau,
krisman
Cc: bpf, linux-kernel, netdev, io-uring, pabeni
Add support for getsockopt command (SOCKET_URING_OP_GETSOCKOPT), where
level is SOL_SOCKET. This is similar to the getsockopt(2) system
call, and both parameters are pointers to userspace.
Important to say that userspace needs to keep the pointer alive until
the CQE is completed.
Reviewed-by: Gabriel Krisman Bertazi <[email protected]>
Signed-off-by: Breno Leitao <[email protected]>
---
include/uapi/linux/io_uring.h | 9 +++++++++
io_uring/uring_cmd.c | 15 +++++++++++++++
2 files changed, 24 insertions(+)
diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h
index 8e61f8b7c2ce..1c789ee6462d 100644
--- a/include/uapi/linux/io_uring.h
+++ b/include/uapi/linux/io_uring.h
@@ -43,6 +43,10 @@ struct io_uring_sqe {
union {
__u64 addr; /* pointer to buffer or iovecs */
__u64 splice_off_in;
+ struct {
+ __u32 level;
+ __u32 optname;
+ };
};
__u32 len; /* buffer size or number of iovecs */
union {
@@ -89,6 +93,10 @@ struct io_uring_sqe {
__u64 addr3;
__u64 __pad2[1];
};
+ struct {
+ __u64 optval;
+ __u64 optlen;
+ };
/*
* If the ring is initialized with IORING_SETUP_SQE128, then
* this field is used for 80 bytes of arbitrary command data
@@ -734,6 +742,7 @@ struct io_uring_recvmsg_out {
enum {
SOCKET_URING_OP_SIOCINQ = 0,
SOCKET_URING_OP_SIOCOUTQ,
+ SOCKET_URING_OP_GETSOCKOPT,
};
#ifdef __cplusplus
diff --git a/io_uring/uring_cmd.c b/io_uring/uring_cmd.c
index a7d6a7d112b7..2806330a021f 100644
--- a/io_uring/uring_cmd.c
+++ b/io_uring/uring_cmd.c
@@ -167,6 +167,19 @@ int io_uring_cmd_import_fixed(u64 ubuf, unsigned long len, int rw,
}
EXPORT_SYMBOL_GPL(io_uring_cmd_import_fixed);
+static inline int io_uring_cmd_getsockopt(struct socket *sock,
+ struct io_uring_cmd *cmd,
+ unsigned int issue_flags)
+{
+ void __user *optval = u64_to_user_ptr(READ_ONCE(cmd->sqe->optval));
+ int __user *optlen = u64_to_user_ptr(READ_ONCE(cmd->sqe->optlen));
+ bool compat = !!(issue_flags & IO_URING_F_COMPAT);
+ int optname = READ_ONCE(cmd->sqe->optname);
+ int level = READ_ONCE(cmd->sqe->level);
+
+ return do_sock_getsockopt(sock, compat, level, optname, optval, optlen);
+}
+
#if defined(CONFIG_NET)
int io_uring_cmd_sock(struct io_uring_cmd *cmd, unsigned int issue_flags)
{
@@ -189,6 +202,8 @@ int io_uring_cmd_sock(struct io_uring_cmd *cmd, unsigned int issue_flags)
if (ret)
return ret;
return arg;
+ case SOCKET_URING_OP_GETSOCKOPT:
+ return io_uring_cmd_getsockopt(sock, cmd, issue_flags);
default:
return -EOPNOTSUPP;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v5 7/8] io_uring/cmd: Introduce SOCKET_URING_OP_SETSOCKOPT
2023-09-11 10:33 [PATCH v5 0/8] io_uring: Initial support for {s,g}etsockopt commands Breno Leitao
` (5 preceding siblings ...)
2023-09-11 10:34 ` [PATCH v5 6/8] io_uring/cmd: Introduce SOCKET_URING_OP_GETSOCKOPT Breno Leitao
@ 2023-09-11 10:34 ` Breno Leitao
2023-09-11 10:34 ` [PATCH v5 8/8] selftests/bpf/sockopt: Add io_uring support Breno Leitao
7 siblings, 0 replies; 14+ messages in thread
From: Breno Leitao @ 2023-09-11 10:34 UTC (permalink / raw)
To: sdf, axboe, asml.silence, willemdebruijn.kernel, kuba, martin.lau,
krisman
Cc: bpf, linux-kernel, netdev, io-uring, pabeni
Add support for SOCKET_URING_OP_SETSOCKOPT. This new command is similar
to setsockopt(2). This implementation leverages the function
do_sock_setsockopt(), which is shared with the setsockopt() system call
path.
Important to say that userspace needs to keep the pointer's memory alive
until the operation is completed. I.e, the memory could not be
deallocated before the CQE is returned to userspace.
Reviewed-by: Gabriel Krisman Bertazi <[email protected]>
Signed-off-by: Breno Leitao <[email protected]>
---
include/uapi/linux/io_uring.h | 1 +
io_uring/uring_cmd.c | 16 ++++++++++++++++
2 files changed, 17 insertions(+)
diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h
index 1c789ee6462d..99cdb2c1e240 100644
--- a/include/uapi/linux/io_uring.h
+++ b/include/uapi/linux/io_uring.h
@@ -743,6 +743,7 @@ enum {
SOCKET_URING_OP_SIOCINQ = 0,
SOCKET_URING_OP_SIOCOUTQ,
SOCKET_URING_OP_GETSOCKOPT,
+ SOCKET_URING_OP_SETSOCKOPT,
};
#ifdef __cplusplus
diff --git a/io_uring/uring_cmd.c b/io_uring/uring_cmd.c
index 2806330a021f..7592af629b18 100644
--- a/io_uring/uring_cmd.c
+++ b/io_uring/uring_cmd.c
@@ -180,6 +180,20 @@ static inline int io_uring_cmd_getsockopt(struct socket *sock,
return do_sock_getsockopt(sock, compat, level, optname, optval, optlen);
}
+static inline int io_uring_cmd_setsockopt(struct socket *sock,
+ struct io_uring_cmd *cmd,
+ unsigned int issue_flags)
+{
+ void __user *optval = u64_to_user_ptr(READ_ONCE(cmd->sqe->optval));
+ int optlen = READ_ONCE(cmd->sqe->optlen);
+ bool compat = !!(issue_flags & IO_URING_F_COMPAT);
+ int optname = READ_ONCE(cmd->sqe->optname);
+ int level = READ_ONCE(cmd->sqe->level);
+
+ return do_sock_setsockopt(sock, compat, level, optname, optval,
+ optlen);
+}
+
#if defined(CONFIG_NET)
int io_uring_cmd_sock(struct io_uring_cmd *cmd, unsigned int issue_flags)
{
@@ -204,6 +218,8 @@ int io_uring_cmd_sock(struct io_uring_cmd *cmd, unsigned int issue_flags)
return arg;
case SOCKET_URING_OP_GETSOCKOPT:
return io_uring_cmd_getsockopt(sock, cmd, issue_flags);
+ case SOCKET_URING_OP_SETSOCKOPT:
+ return io_uring_cmd_setsockopt(sock, cmd, issue_flags);
default:
return -EOPNOTSUPP;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v5 8/8] selftests/bpf/sockopt: Add io_uring support
2023-09-11 10:33 [PATCH v5 0/8] io_uring: Initial support for {s,g}etsockopt commands Breno Leitao
` (6 preceding siblings ...)
2023-09-11 10:34 ` [PATCH v5 7/8] io_uring/cmd: Introduce SOCKET_URING_OP_SETSOCKOPT Breno Leitao
@ 2023-09-11 10:34 ` Breno Leitao
7 siblings, 0 replies; 14+ messages in thread
From: Breno Leitao @ 2023-09-11 10:34 UTC (permalink / raw)
To: sdf, axboe, asml.silence, willemdebruijn.kernel, kuba, martin.lau,
krisman, Andrii Nakryiko, Mykola Lysenko, Alexei Starovoitov,
Daniel Borkmann, Song Liu, Yonghong Song, John Fastabend,
KP Singh, Hao Luo, Jiri Olsa, Shuah Khan
Cc: bpf, linux-kernel, netdev, io-uring, pabeni, Wang Yufen,
Daniel Müller, open list:KERNEL SELFTEST FRAMEWORK
Expand the BPF sockopt test to use also check for io_uring
{g,s}etsockopt commands operations.
Create infrastructure to run io_uring tests using the mini_liburing
helpers, so, the {g,s}etsockopt operation could either be called from
system calls, or, via io_uring.
Add a 'use_io_uring' parameter to run_test(), to specify if the test
should be run using io_uring if the parameter is set, or via the regular
system calls if false.
Call *all* tests twice, using the regular io_uring path, and the new
io_uring path.
Signed-off-by: Breno Leitao <[email protected]>
---
.../selftests/bpf/prog_tests/sockopt.c | 95 +++++++++++++++++--
1 file changed, 89 insertions(+), 6 deletions(-)
diff --git a/tools/testing/selftests/bpf/prog_tests/sockopt.c b/tools/testing/selftests/bpf/prog_tests/sockopt.c
index 9e6a5e3ed4de..40fb4c315ad9 100644
--- a/tools/testing/selftests/bpf/prog_tests/sockopt.c
+++ b/tools/testing/selftests/bpf/prog_tests/sockopt.c
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
#include <test_progs.h>
+#include <io_uring/mini_liburing.h>
#include "cgroup_helpers.h"
static char bpf_log_buf[4096];
@@ -940,7 +941,85 @@ static int load_prog(const struct bpf_insn *insns,
return fd;
}
-static int run_test(int cgroup_fd, struct sockopt_test *test)
+/* Core function that handles io_uring ring initialization,
+ * sending SQE with sockopt command and waiting for the CQE.
+ */
+static int uring_sockopt(int op, int fd, int level, int optname,
+ const void *optval, socklen_t *optlen)
+{
+ struct io_uring_cqe *cqe;
+ struct io_uring_sqe *sqe;
+ struct io_uring ring;
+ int err;
+
+ err = io_uring_queue_init(1, &ring, 0);
+ if (!ASSERT_OK(err, "Initialize io_uring ring"))
+ return err;
+
+ sqe = io_uring_get_sqe(&ring);
+ if (!ASSERT_NEQ(sqe, NULL, "Get an SQE")) {
+ err = -1;
+ goto fail;
+ }
+
+ if (op == SOCKET_URING_OP_GETSOCKOPT)
+ io_uring_prep_cmd_get(sqe, op, fd, level, optname, optval,
+ optlen);
+ else
+ io_uring_prep_cmd(sqe, op, fd, level, optname, optval,
+ *optlen);
+
+ err = io_uring_submit(&ring);
+ if (!ASSERT_EQ(err, 1, "Submit SQE"))
+ goto fail;
+
+ err = io_uring_wait_cqe(&ring, &cqe);
+ if (!ASSERT_OK(err, "Wait for CQE"))
+ goto fail;
+
+ err = cqe->res;
+
+fail:
+ io_uring_queue_exit(&ring);
+
+ return err;
+}
+
+static int uring_setsockopt(int fd, int level, int optname, const void *optval,
+ socklen_t *optlen)
+{
+ return uring_sockopt(SOCKET_URING_OP_SETSOCKOPT, fd, level, optname,
+ optval, optlen);
+}
+
+static int uring_getsockopt(int fd, int level, int optname, void *optval,
+ socklen_t *optlen)
+{
+ return uring_sockopt(SOCKET_URING_OP_GETSOCKOPT, fd, level, optname,
+ optval, optlen);
+}
+
+/* Execute the setsocktopt operation */
+static int call_setsockopt(bool use_io_uring, int fd, int level, int optname,
+ const void *optval, socklen_t optlen)
+{
+ if (use_io_uring)
+ return uring_setsockopt(fd, level, optname, optval, &optlen);
+
+ return setsockopt(fd, level, optname, optval, optlen);
+}
+
+/* Execute the getsocktopt operation */
+static int call_getsockopt(bool use_io_uring, int fd, int level, int optname,
+ void *optval, socklen_t *optlen)
+{
+ if (use_io_uring)
+ return uring_getsockopt(fd, level, optname, optval, optlen);
+
+ return getsockopt(fd, level, optname, optval, optlen);
+}
+
+static int run_test(int cgroup_fd, struct sockopt_test *test, bool use_io_uring)
{
int sock_fd, err, prog_fd;
void *optval = NULL;
@@ -980,8 +1059,9 @@ static int run_test(int cgroup_fd, struct sockopt_test *test)
test->set_optlen = num_pages * sysconf(_SC_PAGESIZE) + remainder;
}
- err = setsockopt(sock_fd, test->set_level, test->set_optname,
- test->set_optval, test->set_optlen);
+ err = call_setsockopt(use_io_uring, sock_fd, test->set_level,
+ test->set_optname, test->set_optval,
+ test->set_optlen);
if (err) {
if (errno == EPERM && test->error == EPERM_SETSOCKOPT)
goto close_sock_fd;
@@ -1008,8 +1088,8 @@ static int run_test(int cgroup_fd, struct sockopt_test *test)
socklen_t expected_get_optlen = test->get_optlen_ret ?:
test->get_optlen;
- err = getsockopt(sock_fd, test->get_level, test->get_optname,
- optval, &optlen);
+ err = call_getsockopt(use_io_uring, sock_fd, test->get_level,
+ test->get_optname, optval, &optlen);
if (err) {
if (errno == EOPNOTSUPP && test->error == EOPNOTSUPP_GETSOCKOPT)
goto free_optval;
@@ -1063,7 +1143,10 @@ void test_sockopt(void)
if (!test__start_subtest(tests[i].descr))
continue;
- ASSERT_OK(run_test(cgroup_fd, &tests[i]), tests[i].descr);
+ ASSERT_OK(run_test(cgroup_fd, &tests[i], false),
+ tests[i].descr);
+ ASSERT_OK(run_test(cgroup_fd, &tests[i], true),
+ tests[i].descr);
}
close(cgroup_fd);
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v5 3/8] io_uring/cmd: Pass compat mode in issue_flags
2023-09-11 10:34 ` [PATCH v5 3/8] io_uring/cmd: Pass compat mode in issue_flags Breno Leitao
@ 2023-09-11 15:42 ` Gabriel Krisman Bertazi
0 siblings, 0 replies; 14+ messages in thread
From: Gabriel Krisman Bertazi @ 2023-09-11 15:42 UTC (permalink / raw)
To: Breno Leitao
Cc: sdf, axboe, asml.silence, willemdebruijn.kernel, kuba, martin.lau,
bpf, linux-kernel, netdev, io-uring, pabeni
Breno Leitao <[email protected]> writes:
> Create a new flag to track if the operation is running compat mode.
> This basically check the context->compat and pass it to the issue_flags,
> so, it could be queried later in the callbacks.
>
> Signed-off-by: Breno Leitao <[email protected]>
Reviewed-by: Gabriel Krisman Bertazi <[email protected]>
> ---
> include/linux/io_uring.h | 1 +
> io_uring/uring_cmd.c | 2 ++
> 2 files changed, 3 insertions(+)
>
> diff --git a/include/linux/io_uring.h b/include/linux/io_uring.h
> index 106cdc55ff3b..bc53b35966ed 100644
> --- a/include/linux/io_uring.h
> +++ b/include/linux/io_uring.h
> @@ -20,6 +20,7 @@ enum io_uring_cmd_flags {
> IO_URING_F_SQE128 = (1 << 8),
> IO_URING_F_CQE32 = (1 << 9),
> IO_URING_F_IOPOLL = (1 << 10),
> + IO_URING_F_COMPAT = (1 << 11),
> };
>
> struct io_uring_cmd {
> diff --git a/io_uring/uring_cmd.c b/io_uring/uring_cmd.c
> index 537795fddc87..60f843a357e0 100644
> --- a/io_uring/uring_cmd.c
> +++ b/io_uring/uring_cmd.c
> @@ -128,6 +128,8 @@ int io_uring_cmd(struct io_kiocb *req, unsigned int issue_flags)
> issue_flags |= IO_URING_F_SQE128;
> if (ctx->flags & IORING_SETUP_CQE32)
> issue_flags |= IO_URING_F_CQE32;
> + if (ctx->compat)
> + issue_flags |= IO_URING_F_COMPAT;
> if (ctx->flags & IORING_SETUP_IOPOLL) {
> if (!file->f_op->uring_cmd_iopoll)
> return -EOPNOTSUPP;
--
Gabriel Krisman Bertazi
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v5 5/8] io_uring/cmd: return -EOPNOTSUPP if net is disabled
2023-09-11 10:34 ` [PATCH v5 5/8] io_uring/cmd: return -EOPNOTSUPP if net is disabled Breno Leitao
@ 2023-09-11 15:53 ` Gabriel Krisman Bertazi
2023-09-11 16:46 ` Breno Leitao
0 siblings, 1 reply; 14+ messages in thread
From: Gabriel Krisman Bertazi @ 2023-09-11 15:53 UTC (permalink / raw)
To: Breno Leitao
Cc: sdf, axboe, asml.silence, willemdebruijn.kernel, kuba, martin.lau,
bpf, linux-kernel, netdev, io-uring, pabeni
Breno Leitao <[email protected]> writes:
> Protect io_uring_cmd_sock() to be called if CONFIG_NET is not set. If
> network is not enabled, but io_uring is, then we want to return
> -EOPNOTSUPP for any possible socket operation.
>
> This is helpful because io_uring_cmd_sock() can now call functions that
> only exits if CONFIG_NET is enabled without having #ifdef CONFIG_NET
> inside the function itself.
>
> Signed-off-by: Breno Leitao <[email protected]>
> ---
> io_uring/uring_cmd.c | 8 ++++++++
> 1 file changed, 8 insertions(+)
>
> diff --git a/io_uring/uring_cmd.c b/io_uring/uring_cmd.c
> index 60f843a357e0..a7d6a7d112b7 100644
> --- a/io_uring/uring_cmd.c
> +++ b/io_uring/uring_cmd.c
> @@ -167,6 +167,7 @@ int io_uring_cmd_import_fixed(u64 ubuf, unsigned long len, int rw,
> }
> EXPORT_SYMBOL_GPL(io_uring_cmd_import_fixed);
>
> +#if defined(CONFIG_NET)
> int io_uring_cmd_sock(struct io_uring_cmd *cmd, unsigned int issue_flags)
> {
> struct socket *sock = cmd->file->private_data;
> @@ -193,3 +194,10 @@ int io_uring_cmd_sock(struct io_uring_cmd *cmd, unsigned int issue_flags)
> }
> }
> EXPORT_SYMBOL_GPL(io_uring_cmd_sock);
> +#else
> +int io_uring_cmd_sock(struct io_uring_cmd *cmd, unsigned int issue_flags)
> +{
> + return -EOPNOTSUPP;
> +}
> +#endif
> +
Is net/socket.c even built without CONFIG_NET? if not, you don't even need
the alternative EOPNOTSUPP implementation.
--
Gabriel Krisman Bertazi
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v5 5/8] io_uring/cmd: return -EOPNOTSUPP if net is disabled
2023-09-11 15:53 ` Gabriel Krisman Bertazi
@ 2023-09-11 16:46 ` Breno Leitao
2023-09-12 0:20 ` Gabriel Krisman Bertazi
0 siblings, 1 reply; 14+ messages in thread
From: Breno Leitao @ 2023-09-11 16:46 UTC (permalink / raw)
To: Gabriel Krisman Bertazi
Cc: sdf, axboe, asml.silence, willemdebruijn.kernel, kuba, martin.lau,
bpf, linux-kernel, netdev, io-uring, pabeni
On Mon, Sep 11, 2023 at 11:53:58AM -0400, Gabriel Krisman Bertazi wrote:
> Breno Leitao <[email protected]> writes:
>
> > Protect io_uring_cmd_sock() to be called if CONFIG_NET is not set. If
> > network is not enabled, but io_uring is, then we want to return
> > -EOPNOTSUPP for any possible socket operation.
> >
> > This is helpful because io_uring_cmd_sock() can now call functions that
> > only exits if CONFIG_NET is enabled without having #ifdef CONFIG_NET
> > inside the function itself.
> >
> > Signed-off-by: Breno Leitao <[email protected]>
> > ---
> > io_uring/uring_cmd.c | 8 ++++++++
> > 1 file changed, 8 insertions(+)
> >
> > diff --git a/io_uring/uring_cmd.c b/io_uring/uring_cmd.c
> > index 60f843a357e0..a7d6a7d112b7 100644
> > --- a/io_uring/uring_cmd.c
> > +++ b/io_uring/uring_cmd.c
> > @@ -167,6 +167,7 @@ int io_uring_cmd_import_fixed(u64 ubuf, unsigned long len, int rw,
> > }
> > EXPORT_SYMBOL_GPL(io_uring_cmd_import_fixed);
> >
> > +#if defined(CONFIG_NET)
> > int io_uring_cmd_sock(struct io_uring_cmd *cmd, unsigned int issue_flags)
> > {
> > struct socket *sock = cmd->file->private_data;
> > @@ -193,3 +194,10 @@ int io_uring_cmd_sock(struct io_uring_cmd *cmd, unsigned int issue_flags)
> > }
> > }
> > EXPORT_SYMBOL_GPL(io_uring_cmd_sock);
> > +#else
> > +int io_uring_cmd_sock(struct io_uring_cmd *cmd, unsigned int issue_flags)
> > +{
> > + return -EOPNOTSUPP;
> > +}
> > +#endif
> > +
>
> Is net/socket.c even built without CONFIG_NET? if not, you don't even need
> the alternative EOPNOTSUPP implementation.
It seems so. net/socket.o is part of obj-y:
https://github.com/torvalds/linux/blob/master/net/Makefile#L9
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v5 5/8] io_uring/cmd: return -EOPNOTSUPP if net is disabled
2023-09-11 16:46 ` Breno Leitao
@ 2023-09-12 0:20 ` Gabriel Krisman Bertazi
0 siblings, 0 replies; 14+ messages in thread
From: Gabriel Krisman Bertazi @ 2023-09-12 0:20 UTC (permalink / raw)
To: Breno Leitao
Cc: sdf, axboe, asml.silence, willemdebruijn.kernel, kuba, martin.lau,
bpf, linux-kernel, netdev, io-uring, pabeni
Breno Leitao <[email protected]> writes:
> On Mon, Sep 11, 2023 at 11:53:58AM -0400, Gabriel Krisman Bertazi wrote:
>> Breno Leitao <[email protected]> writes:
>>
>> > Protect io_uring_cmd_sock() to be called if CONFIG_NET is not set. If
>> > network is not enabled, but io_uring is, then we want to return
>> > -EOPNOTSUPP for any possible socket operation.
>> >
>> > This is helpful because io_uring_cmd_sock() can now call functions that
>> > only exits if CONFIG_NET is enabled without having #ifdef CONFIG_NET
>> > inside the function itself.
>> >
>> > Signed-off-by: Breno Leitao <[email protected]>
>> > ---
>> > io_uring/uring_cmd.c | 8 ++++++++
>> > 1 file changed, 8 insertions(+)
>> >
>> > diff --git a/io_uring/uring_cmd.c b/io_uring/uring_cmd.c
>> > index 60f843a357e0..a7d6a7d112b7 100644
>> > --- a/io_uring/uring_cmd.c
>> > +++ b/io_uring/uring_cmd.c
>> > @@ -167,6 +167,7 @@ int io_uring_cmd_import_fixed(u64 ubuf, unsigned long len, int rw,
>> > }
>> > EXPORT_SYMBOL_GPL(io_uring_cmd_import_fixed);
>> >
>> > +#if defined(CONFIG_NET)
>> > int io_uring_cmd_sock(struct io_uring_cmd *cmd, unsigned int issue_flags)
>> > {
>> > struct socket *sock = cmd->file->private_data;
>> > @@ -193,3 +194,10 @@ int io_uring_cmd_sock(struct io_uring_cmd *cmd, unsigned int issue_flags)
>> > }
>> > }
>> > EXPORT_SYMBOL_GPL(io_uring_cmd_sock);
>> > +#else
>> > +int io_uring_cmd_sock(struct io_uring_cmd *cmd, unsigned int issue_flags)
>> > +{
>> > + return -EOPNOTSUPP;
>> > +}
>> > +#endif
>> > +
>>
>> Is net/socket.c even built without CONFIG_NET? if not, you don't even need
>> the alternative EOPNOTSUPP implementation.
>
> It seems so. net/socket.o is part of obj-y:
>
> https://github.com/torvalds/linux/blob/master/net/Makefile#L9
Yes. But also:
[0:cartola linux]$ grep 'net/' Kbuild
obj-$(CONFIG_NET) += net/
I doubled checked and it should build fine without it. Technically, you
also want to also guard the declaration in the header file, IMO, even if
it compiles fine. Also, there is an extra blank line warning when applying
the patch but, surprisingly, checkpatch.pl seems to miss it.
--
Gabriel Krisman Bertazi
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v5 2/8] net/socket: Break down __sys_getsockopt
2023-09-11 10:34 ` [PATCH v5 2/8] net/socket: Break down __sys_getsockopt Breno Leitao
@ 2023-09-12 9:37 ` Paolo Abeni
0 siblings, 0 replies; 14+ messages in thread
From: Paolo Abeni @ 2023-09-12 9:37 UTC (permalink / raw)
To: Breno Leitao, sdf, axboe, asml.silence, willemdebruijn.kernel,
kuba, martin.lau, krisman, David S. Miller, Eric Dumazet
Cc: bpf, linux-kernel, netdev, io-uring
On Mon, 2023-09-11 at 03:34 -0700, Breno Leitao wrote:
> Split __sys_getsockopt() into two functions by removing the core
> logic into a sub-function (do_sock_getsockopt()). This will avoid
> code duplication when executing the same operation in other callers, for
> instance.
>
> do_sock_getsockopt() will be called by io_uring getsockopt() command
> operation in the following patch.
>
> Suggested-by: Martin KaFai Lau <[email protected]>
> Signed-off-by: Breno Leitao <[email protected]>
> ---
> include/net/sock.h | 3 +++
> net/socket.c | 51 ++++++++++++++++++++++++++++------------------
> 2 files changed, 34 insertions(+), 20 deletions(-)
>
> diff --git a/include/net/sock.h b/include/net/sock.h
> index aa8fb54ad0af..fbd568a43d28 100644
> --- a/include/net/sock.h
> +++ b/include/net/sock.h
> @@ -1863,6 +1863,9 @@ int sock_setsockopt(struct socket *sock, int level, int op,
> sockptr_t optval, unsigned int optlen);
> int do_sock_setsockopt(struct socket *sock, bool compat, int level,
> int optname, char __user *user_optval, int optlen);
> +int do_sock_getsockopt(struct socket *sock, bool compat, int level,
> + int optname, char __user *user_optval,
> + int __user *user_optlen);
>
> int sk_getsockopt(struct sock *sk, int level, int optname,
> sockptr_t optval, sockptr_t optlen);
> diff --git a/net/socket.c b/net/socket.c
> index 360332e098d4..3ec779a56f79 100644
> --- a/net/socket.c
> +++ b/net/socket.c
> @@ -2333,28 +2333,17 @@ SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname,
> INDIRECT_CALLABLE_DECLARE(bool tcp_bpf_bypass_getsockopt(int level,
> int optname));
>
> -/*
> - * Get a socket option. Because we don't know the option lengths we have
> - * to pass a user mode parameter for the protocols to sort out.
> - */
> -int __sys_getsockopt(int fd, int level, int optname, char __user *optval,
> - int __user *optlen)
> +int do_sock_getsockopt(struct socket *sock, bool compat, int level,
> + int optname, char __user *optval,
> + int __user *optlen)
> {
> int max_optlen __maybe_unused;
> const struct proto_ops *ops;
> - int err, fput_needed;
> - struct socket *sock;
> -
> - sock = sockfd_lookup_light(fd, &err, &fput_needed);
> - if (!sock)
> - return err;
> + int err;
>
> err = security_socket_getsockopt(sock, level, optname);
> if (err)
> - goto out_put;
> -
> - if (!in_compat_syscall())
> - max_optlen = BPF_CGROUP_GETSOCKOPT_MAX_OPTLEN(optlen);
> + return err;
>
> ops = READ_ONCE(sock->ops);
> if (level == SOL_SOCKET)
> @@ -2362,14 +2351,36 @@ int __sys_getsockopt(int fd, int level, int optname, char __user *optval,
> else if (unlikely(!ops->getsockopt))
> err = -EOPNOTSUPP;
> else
> - err = ops->getsockopt(sock, level, optname, optval,
> - optlen);
> + err = ops->getsockopt(sock, level, optname, optval, optlen);
>
> - if (!in_compat_syscall())
> + if (!compat) {
> + max_optlen = BPF_CGROUP_GETSOCKOPT_MAX_OPTLEN(optlen);
> err = BPF_CGROUP_RUN_PROG_GETSOCKOPT(sock->sk, level, optname,
> optval, optlen, max_optlen,
> err);
> -out_put:
> + }
> +
> + return err;
> +}
> +EXPORT_SYMBOL(do_sock_getsockopt);
> +
> +/* Get a socket option. Because we don't know the option lengths we have
> + * to pass a user mode parameter for the protocols to sort out.
> + */
> +int __sys_getsockopt(int fd, int level, int optname, char __user *optval,
> + int __user *optlen)
> +{
> + int err, fput_needed;
> + bool compat = in_compat_syscall();
> + struct socket *sock;
Please respect the reverse x-mas tree order, thanks!
Paolo
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2023-09-12 9:38 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-09-11 10:33 [PATCH v5 0/8] io_uring: Initial support for {s,g}etsockopt commands Breno Leitao
2023-09-11 10:34 ` [PATCH v5 1/8] net/socket: Break down __sys_setsockopt Breno Leitao
2023-09-11 10:34 ` [PATCH v5 2/8] net/socket: Break down __sys_getsockopt Breno Leitao
2023-09-12 9:37 ` Paolo Abeni
2023-09-11 10:34 ` [PATCH v5 3/8] io_uring/cmd: Pass compat mode in issue_flags Breno Leitao
2023-09-11 15:42 ` Gabriel Krisman Bertazi
2023-09-11 10:34 ` [PATCH v5 4/8] selftests/net: Extract uring helpers to be reusable Breno Leitao
2023-09-11 10:34 ` [PATCH v5 5/8] io_uring/cmd: return -EOPNOTSUPP if net is disabled Breno Leitao
2023-09-11 15:53 ` Gabriel Krisman Bertazi
2023-09-11 16:46 ` Breno Leitao
2023-09-12 0:20 ` Gabriel Krisman Bertazi
2023-09-11 10:34 ` [PATCH v5 6/8] io_uring/cmd: Introduce SOCKET_URING_OP_GETSOCKOPT Breno Leitao
2023-09-11 10:34 ` [PATCH v5 7/8] io_uring/cmd: Introduce SOCKET_URING_OP_SETSOCKOPT Breno Leitao
2023-09-11 10:34 ` [PATCH v5 8/8] selftests/bpf/sockopt: Add io_uring support Breno Leitao
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox