io_uring: accept directly into fixed file table
[linux-2.6-microblaze.git] / fs / io_uring.c
index ad0a615..e321cb0 100644 (file)
@@ -515,6 +515,7 @@ struct io_accept {
        struct sockaddr __user          *addr;
        int __user                      *addr_len;
        int                             flags;
+       u32                             file_slot;
        unsigned long                   nofile;
 };
 
@@ -4803,7 +4804,7 @@ static int io_accept_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 
        if (unlikely(req->ctx->flags & IORING_SETUP_IOPOLL))
                return -EINVAL;
-       if (sqe->ioprio || sqe->len || sqe->buf_index || sqe->splice_fd_in)
+       if (sqe->ioprio || sqe->len || sqe->buf_index)
                return -EINVAL;
 
        accept->addr = u64_to_user_ptr(READ_ONCE(sqe->addr));
@@ -4811,6 +4812,10 @@ static int io_accept_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
        accept->flags = READ_ONCE(sqe->accept_flags);
        accept->nofile = rlimit(RLIMIT_NOFILE);
 
+       accept->file_slot = READ_ONCE(sqe->file_index);
+       if (accept->file_slot && ((req->open.how.flags & O_CLOEXEC) ||
+                                 (accept->flags & SOCK_CLOEXEC)))
+               return -EINVAL;
        if (accept->flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
                return -EINVAL;
        if (SOCK_NONBLOCK != O_NONBLOCK && (accept->flags & SOCK_NONBLOCK))
@@ -4823,28 +4828,35 @@ static int io_accept(struct io_kiocb *req, unsigned int issue_flags)
        struct io_accept *accept = &req->accept;
        bool force_nonblock = issue_flags & IO_URING_F_NONBLOCK;
        unsigned int file_flags = force_nonblock ? O_NONBLOCK : 0;
+       bool fixed = !!accept->file_slot;
        struct file *file;
        int ret, fd;
 
        if (req->file->f_flags & O_NONBLOCK)
                req->flags |= REQ_F_NOWAIT;
 
-       fd = __get_unused_fd_flags(accept->flags, accept->nofile);
-       if (unlikely(fd < 0))
-               return fd;
-
+       if (!fixed) {
+               fd = __get_unused_fd_flags(accept->flags, accept->nofile);
+               if (unlikely(fd < 0))
+                       return fd;
+       }
        file = do_accept(req->file, file_flags, accept->addr, accept->addr_len,
                         accept->flags);
        if (IS_ERR(file)) {
+               if (!fixed)
+                       put_unused_fd(fd);
                ret = PTR_ERR(file);
                if (ret == -EAGAIN && force_nonblock)
                        return -EAGAIN;
                if (ret == -ERESTARTSYS)
                        ret = -EINTR;
                req_set_fail(req);
-       } else {
+       } else if (!fixed) {
                fd_install(fd, file);
                ret = fd;
+       } else {
+               ret = io_install_fixed_file(req, file, issue_flags,
+                                           accept->file_slot - 1);
        }
        __io_req_complete(req, issue_flags, ret, 0);
        return 0;