io_uring/net: add IORING_ACCEPT_DONTWAIT flag
authorJens Axboe <axboe@kernel.dk>
Tue, 7 May 2024 20:06:15 +0000 (14:06 -0600)
committerJens Axboe <axboe@kernel.dk>
Thu, 9 May 2024 18:22:03 +0000 (12:22 -0600)
This allows the caller to perform a non-blocking attempt, similarly to
how recvmsg has MSG_DONTWAIT. If set, and we get -EAGAIN on a connection
attempt, propagate the result to userspace rather than arm poll and
wait for a retry.

Suggested-by: Norman Maurer <norman_maurer@apple.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
include/uapi/linux/io_uring.h
io_uring/net.c

index f093cb2300d96ebde02073431d09c118aaafd415..4a645d15516f2000ee32a31551569d8dd98a89a5 100644 (file)
@@ -379,6 +379,7 @@ enum io_uring_op {
  * accept flags stored in sqe->ioprio
  */
 #define IORING_ACCEPT_MULTISHOT        (1U << 0)
+#define IORING_ACCEPT_DONTWAIT (1U << 1)
 
 /*
  * IORING_OP_MSG_RING command types, stored in sqe->addr
index b0bf8471ecb77f824e24fdc011326a2153f37844..7861bc8fe8b1d71cf7352efbf653bc4003641b81 100644 (file)
@@ -28,6 +28,7 @@ struct io_accept {
        struct sockaddr __user          *addr;
        int __user                      *addr_len;
        int                             flags;
+       int                             iou_flags;
        u32                             file_slot;
        unsigned long                   nofile;
 };
@@ -1489,7 +1490,6 @@ void io_sendrecv_fail(struct io_kiocb *req)
 int io_accept_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 {
        struct io_accept *accept = io_kiocb_to_cmd(req, struct io_accept);
-       unsigned flags;
 
        if (sqe->len || sqe->buf_index)
                return -EINVAL;
@@ -1498,15 +1498,15 @@ int io_accept_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
        accept->addr_len = u64_to_user_ptr(READ_ONCE(sqe->addr2));
        accept->flags = READ_ONCE(sqe->accept_flags);
        accept->nofile = rlimit(RLIMIT_NOFILE);
-       flags = READ_ONCE(sqe->ioprio);
-       if (flags & ~IORING_ACCEPT_MULTISHOT)
+       accept->iou_flags = READ_ONCE(sqe->ioprio);
+       if (accept->iou_flags & ~(IORING_ACCEPT_MULTISHOT | IORING_ACCEPT_DONTWAIT))
                return -EINVAL;
 
        accept->file_slot = READ_ONCE(sqe->file_index);
        if (accept->file_slot) {
                if (accept->flags & SOCK_CLOEXEC)
                        return -EINVAL;
-               if (flags & IORING_ACCEPT_MULTISHOT &&
+               if (accept->iou_flags & IORING_ACCEPT_MULTISHOT &&
                    accept->file_slot != IORING_FILE_INDEX_ALLOC)
                        return -EINVAL;
        }
@@ -1514,8 +1514,10 @@ int io_accept_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
                return -EINVAL;
        if (SOCK_NONBLOCK != O_NONBLOCK && (accept->flags & SOCK_NONBLOCK))
                accept->flags = (accept->flags & ~SOCK_NONBLOCK) | O_NONBLOCK;
-       if (flags & IORING_ACCEPT_MULTISHOT)
+       if (accept->iou_flags & IORING_ACCEPT_MULTISHOT)
                req->flags |= REQ_F_APOLL_MULTISHOT;
+       if (accept->iou_flags & IORING_ACCEPT_DONTWAIT)
+               req->flags |= REQ_F_NOWAIT;
        return 0;
 }
 
@@ -1540,7 +1542,8 @@ retry:
                if (!fixed)
                        put_unused_fd(fd);
                ret = PTR_ERR(file);
-               if (ret == -EAGAIN && force_nonblock) {
+               if (ret == -EAGAIN && force_nonblock &&
+                   !(accept->iou_flags & IORING_ACCEPT_DONTWAIT)) {
                        /*
                         * if it's multishot and polled, we don't need to
                         * return EAGAIN to arm the poll infra since it