io_uring: enable EPOLLEXCLUSIVE for accept poll
authorDylan Yudaken <dylany@fb.com>
Fri, 25 Mar 2022 09:37:55 +0000 (02:37 -0700)
committerJens Axboe <axboe@kernel.dk>
Fri, 25 Mar 2022 12:30:23 +0000 (06:30 -0600)
When polling sockets for accept, use EPOLLEXCLUSIVE. This is helpful
when multiple accept SQEs are submitted.

For O_NONBLOCK sockets multiple queued SQEs would previously have all
completed at once, but most with -EAGAIN as the result. Now only one
wakes up and completes.

For sockets without O_NONBLOCK there is no user facing change, but
internally the extra requests would previously be queued onto a worker
thread as they would wake up with no connection waiting, and be
punted. Now they do not wake up unnecessarily.

Co-developed-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Dylan Yudaken <dylany@fb.com>
Link: https://lore.kernel.org/r/20220325093755.4123343-1-dylany@fb.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
fs/io_uring.c

index bb40c80fd9ca1bbcea15d379637c114476a7f248..e72f58e2d06deac952d9d8ba586ee1d15c89db02 100644 (file)
@@ -967,6 +967,7 @@ struct io_op_def {
        /* set if opcode supports polled "wait" */
        unsigned                pollin : 1;
        unsigned                pollout : 1;
+       unsigned                poll_exclusive : 1;
        /* op supports buffer selection */
        unsigned                buffer_select : 1;
        /* do prep async if is going to be punted */
@@ -1061,6 +1062,7 @@ static const struct io_op_def io_op_defs[] = {
                .needs_file             = 1,
                .unbound_nonreg_file    = 1,
                .pollin                 = 1,
+               .poll_exclusive         = 1,
        },
        [IORING_OP_ASYNC_CANCEL] = {
                .audit_skip             = 1,
@@ -6280,7 +6282,8 @@ static int io_arm_poll_handler(struct io_kiocb *req, unsigned issue_flags)
        } else {
                mask |= POLLOUT | POLLWRNORM;
        }
-
+       if (def->poll_exclusive)
+               mask |= EPOLLEXCLUSIVE;
        if (!(issue_flags & IO_URING_F_UNLOCKED) &&
            !list_empty(&ctx->apoll_cache)) {
                apoll = list_first_entry(&ctx->apoll_cache, struct async_poll,