io_uring: add support for sharing kernel io-wq workqueue for-5.6/io_uring-vfs-shared-wq
authorJens Axboe <axboe@kernel.dk>
Thu, 23 Jan 2020 22:59:43 +0000 (15:59 -0700)
committerJens Axboe <axboe@kernel.dk>
Fri, 24 Jan 2020 17:06:59 +0000 (10:06 -0700)
An id field is added to io_uring_params, which always returns the ID of
the io-wq backend that is associated with an io_uring context. If an 'id'
is provided and IORING_SETUP_SHARED is set in the creation flags, then
we attempt to attach to an existing io-wq instead of setting up a new one.

This allows creation of "sibling" io_urings, where we prefer to keep the
SQ/CQ private, but want to share the async backend to minimize the amount
of overhead associated with having multiple rings that belong to the same
backend.

Signed-off-by: Jens Axboe <axboe@kernel.dk>
fs/io_uring.c
include/uapi/linux/io_uring.h

index 9f73586dcfb87787907e2fccfcba539698838154..3dad12906db3faded56fea1c2d245b651ecf1b85 100644 (file)
@@ -5673,7 +5673,7 @@ static int io_sq_offload_start(struct io_ring_ctx *ctx,
 {
        struct io_wq_data data;
        unsigned concurrency;
-       int ret;
+       int ret, id;
 
        init_waitqueue_head(&ctx->sqo_wait);
        mmgrab(current->mm);
@@ -5724,13 +5724,23 @@ static int io_sq_offload_start(struct io_ring_ctx *ctx,
 
        /* Do QD, or 4 * CPUS, whatever is smallest */
        concurrency = min(ctx->sq_entries, 4 * num_online_cpus());
-       ctx->io_wq = io_wq_create(concurrency, &data);
+
+       id = 0;
+       if (ctx->flags & IORING_SETUP_ATTACH_WQ) {
+               id = p->id;
+               if (!id) {
+                       ret = -EINVAL;
+                       goto err;
+               }
+       }
+       ctx->io_wq = io_wq_create_id(concurrency, &data, id);
        if (IS_ERR(ctx->io_wq)) {
                ret = PTR_ERR(ctx->io_wq);
                ctx->io_wq = NULL;
                goto err;
        }
 
+       p->id = io_wq_id(ctx->io_wq);
        return 0;
 err:
        io_finish_async(ctx);
@@ -6554,7 +6564,11 @@ static long io_uring_setup(u32 entries, struct io_uring_params __user *params)
 
        if (p.flags & ~(IORING_SETUP_IOPOLL | IORING_SETUP_SQPOLL |
                        IORING_SETUP_SQ_AFF | IORING_SETUP_CQSIZE |
-                       IORING_SETUP_CLAMP))
+                       IORING_SETUP_CLAMP | IORING_SETUP_ATTACH_WQ))
+               return -EINVAL;
+
+       /* id isn't valid without ATTACH_WQ being set */
+       if (!(p.flags & IORING_SETUP_ATTACH_WQ) && p.id)
                return -EINVAL;
 
        ret = io_uring_create(entries, &p);
index 57d05cc5e27159cb9ff93ee204907deca9b262d5..f66e53c74a3d203938320eaf8481e5b792f75e07 100644 (file)
@@ -75,6 +75,7 @@ enum {
 #define IORING_SETUP_SQ_AFF    (1U << 2)       /* sq_thread_cpu is valid */
 #define IORING_SETUP_CQSIZE    (1U << 3)       /* app defines CQ size */
 #define IORING_SETUP_CLAMP     (1U << 4)       /* clamp SQ/CQ ring sizes */
+#define IORING_SETUP_ATTACH_WQ (1U << 5)       /* attach to existing wq */
 
 enum {
        IORING_OP_NOP,
@@ -183,7 +184,8 @@ struct io_uring_params {
        __u32 sq_thread_cpu;
        __u32 sq_thread_idle;
        __u32 features;
-       __u32 resv[4];
+       __u32 id;
+       __u32 resv[3];
        struct io_sqring_offsets sq_off;
        struct io_cqring_offsets cq_off;
 };