io_uring: allow allocated fixed files for openat/openat2
authorJens Axboe <axboe@kernel.dk>
Sat, 7 May 2022 20:18:44 +0000 (14:18 -0600)
committerJens Axboe <axboe@kernel.dk>
Fri, 13 May 2022 12:28:42 +0000 (06:28 -0600)
If the application passes in IORING_FILE_INDEX_ALLOC as the file_slot,
then that's a hint to allocate a fixed file descriptor rather than have
one be passed in directly.

This can be useful for having io_uring manage the direct descriptor space.

Normal open direct requests will complete with 0 for success, and < 0
in case of error. If io_uring is asked to allocated the direct descriptor,
then the direct descriptor is returned in case of success.

Reviewed-by: Hao Xu <howeyxu@tencent.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
fs/io_uring.c
include/uapi/linux/io_uring.h

index 8c40411..f448264 100644 (file)
@@ -4697,7 +4697,7 @@ static int io_openat2_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
        return __io_openat_prep(req, sqe);
 }
 
-static int __maybe_unused io_file_bitmap_get(struct io_ring_ctx *ctx)
+static int io_file_bitmap_get(struct io_ring_ctx *ctx)
 {
        struct io_file_table *table = &ctx->file_table;
        unsigned long nr = ctx->nr_user_files;
@@ -4722,6 +4722,36 @@ static int __maybe_unused io_file_bitmap_get(struct io_ring_ctx *ctx)
        return -ENFILE;
 }
 
+static int io_fixed_fd_install(struct io_kiocb *req, unsigned int issue_flags,
+                              struct file *file, unsigned int file_slot)
+{
+       bool alloc_slot = file_slot == IORING_FILE_INDEX_ALLOC;
+       struct io_ring_ctx *ctx = req->ctx;
+       int ret;
+
+       if (alloc_slot) {
+               io_ring_submit_lock(ctx, issue_flags);
+               ret = io_file_bitmap_get(ctx);
+               if (unlikely(ret < 0)) {
+                       io_ring_submit_unlock(ctx, issue_flags);
+                       return ret;
+               }
+
+               file_slot = ret;
+       } else {
+               file_slot--;
+       }
+
+       ret = io_install_fixed_file(req, file, issue_flags, file_slot);
+       if (alloc_slot) {
+               io_ring_submit_unlock(ctx, issue_flags);
+               if (!ret)
+                       return file_slot;
+       }
+
+       return ret;
+}
+
 static int io_openat2(struct io_kiocb *req, unsigned int issue_flags)
 {
        struct open_flags op;
@@ -4777,8 +4807,8 @@ static int io_openat2(struct io_kiocb *req, unsigned int issue_flags)
        if (!fixed)
                fd_install(ret, file);
        else
-               ret = io_install_fixed_file(req, file, issue_flags,
-                                           req->open.file_slot - 1);
+               ret = io_fixed_fd_install(req, issue_flags, file,
+                                               req->open.file_slot);
 err:
        putname(req->open.filename);
        req->flags &= ~REQ_F_NEED_CLEANUP;
index 06621a2..b7f02a5 100644 (file)
@@ -63,6 +63,15 @@ struct io_uring_sqe {
        __u64   __pad2[2];
 };
 
+/*
+ * If sqe->file_index is set to this for opcodes that instantiate a new
+ * direct descriptor (like openat/openat2/accept), then io_uring will allocate
+ * an available direct descriptor instead of having the application pass one
+ * in. The picked direct descriptor will be returned in cqe->res, or -ENFILE
+ * if the space is full.
+ */
+#define IORING_FILE_INDEX_ALLOC                (~0U)
+
 enum {
        IOSQE_FIXED_FILE_BIT,
        IOSQE_IO_DRAIN_BIT,