@@ -287,9 +287,9 @@ static int io_uring_alloc_huge(unsigned entries, struct io_uring_params *p,
return (int) mem_used;
}
-static int __io_uring_queue_init_params(unsigned entries, struct io_uring *ring,
- struct io_uring_params *p, void *buf,
- size_t buf_size)
+int __io_uring_queue_init_params(unsigned entries, struct io_uring *ring,
+ struct io_uring_params *p, void *buf,
+ size_t buf_size)
{
int fd, ret = 0;
unsigned *sq_array;
@@ -357,6 +357,24 @@ static int __io_uring_queue_init_params(unsigned entries, struct io_uring *ring,
return ret;
}
+static int io_uring_queue_init_try_nosqarr(unsigned entries, struct io_uring *ring,
+ struct io_uring_params *p, void *buf,
+ size_t buf_size)
+{
+ unsigned flags = p->flags;
+ int ret;
+
+ p->flags |= IORING_SETUP_NO_SQARRAY;
+ ret = __io_uring_queue_init_params(entries, ring, p, buf, buf_size);
+
+ /* don't fallback if explicitly asked for NOSQARRAY */
+ if (ret != -EINVAL || (flags & IORING_SETUP_NO_SQARRAY))
+ return ret;
+
+ p->flags = flags;
+ return __io_uring_queue_init_params(entries, ring, p, buf, buf_size);
+}
+
/*
* Like io_uring_queue_init_params(), except it allows the application to pass
* in a pre-allocated memory range that is used for the shared data between
@@ -375,7 +393,7 @@ int io_uring_queue_init_mem(unsigned entries, struct io_uring *ring,
{
/* should already be set... */
p->flags |= IORING_SETUP_NO_MMAP;
- return __io_uring_queue_init_params(entries, ring, p, buf, buf_size);
+ return io_uring_queue_init_try_nosqarr(entries, ring, p, buf, buf_size);
}
int io_uring_queue_init_params(unsigned entries, struct io_uring *ring,
@@ -383,7 +401,7 @@ int io_uring_queue_init_params(unsigned entries, struct io_uring *ring,
{
int ret;
- ret = __io_uring_queue_init_params(entries, ring, p, NULL, 0);
+ ret = io_uring_queue_init_try_nosqarr(entries, ring, p, NULL, 0);
return ret >= 0 ? 0 : ret;
}
@@ -45,7 +45,7 @@ int main(int argc, char **argv)
return T_EXIT_SKIP;
memset(¶ms, 0, sizeof(params));
- ret = io_uring_queue_init_params(4, &io_uring, ¶ms);
+ ret = t_io_uring_init_sqarray(4, &io_uring, ¶ms);
if (ret) {
fprintf(stderr, "io_uring_init_failed: %d\n", ret);
return T_EXIT_FAIL;
@@ -87,6 +87,19 @@ bool t_probe_defer_taskrun(void);
unsigned __io_uring_flush_sq(struct io_uring *ring);
+int __io_uring_queue_init_params(unsigned entries, struct io_uring *ring,
+ struct io_uring_params *p, void *buf,
+ size_t buf_size);
+
+static inline int t_io_uring_init_sqarray(unsigned entries, struct io_uring *ring,
+ struct io_uring_params *p)
+{
+ int ret;
+
+ ret = __io_uring_queue_init_params(entries, ring, p, NULL, 0);
+ return ret >= 0 ? 0 : ret;
+}
+
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
void t_error(int status, int errnum, const char *format, ...);
@@ -183,13 +183,16 @@ int main(int argc, char **argv)
unsigned ktail, mask, index;
unsigned sq_entries;
unsigned completed, dropped;
+ struct io_uring_params p;
if (argc > 1)
return T_EXIT_SKIP;
- ret = io_uring_queue_init(IORING_MAX_ENTRIES, &ring, 0);
+ memset(&p, 0, sizeof(p));
+ ret = t_io_uring_init_sqarray(IORING_MAX_ENTRIES, &ring, &p);
if (ret == -ENOMEM)
- ret = io_uring_queue_init(IORING_MAX_ENTRIES_FALLBACK, &ring, 0);
+ ret = t_io_uring_init_sqarray(IORING_MAX_ENTRIES_FALLBACK,
+ &ring, &p);
if (ret < 0) {
perror("io_uring_queue_init");
exit(T_EXIT_FAIL);
We have never exposed sq_array to users, so we can safely add IORING_SETUP_NO_SQARRAY to all rings. If the kernel is too old and it fails, we'll retry creating a ring without it. Signed-off-by: Pavel Begunkov <asml.silence@gmail.com> --- src/setup.c | 28 +++++++++++++++++++++++----- test/accept-reuse.c | 2 +- test/helpers.h | 13 +++++++++++++ test/io_uring_enter.c | 7 +++++-- 4 files changed, 42 insertions(+), 8 deletions(-)