io_uring: add support for IORING_OP_OPENAT2
authorJens Axboe <axboe@kernel.dk>
Thu, 9 Jan 2020 00:59:24 +0000 (17:59 -0700)
committerJens Axboe <axboe@kernel.dk>
Tue, 21 Jan 2020 00:04:04 +0000 (17:04 -0700)
Add support for the new openat2(2) system call. It's trivial to do, as
we can have openat(2) just be wrapped around it.

Suggested-by: Stefan Metzmacher <metze@samba.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
fs/io_uring.c
include/uapi/linux/io_uring.h

index 3a57ea98fe3ae92c1491bd0a4f005f3a9d375645..0b30b0cf8af5d6de955cd3a2c11238a94be57398 100644 (file)
@@ -707,6 +707,11 @@ static const struct io_op_def io_op_defs[] = {
                .needs_file             = 1,
                .unbound_nonreg_file    = 1,
        },
+       {
+               /* IORING_OP_OPENAT2 */
+               .needs_file             = 1,
+               .fd_non_neg             = 1,
+       },
 };
 
 static void io_wq_submit_work(struct io_wq_work **workptr);
@@ -2487,11 +2492,46 @@ static int io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
        return 0;
 }
 
-static int io_openat(struct io_kiocb *req, struct io_kiocb **nxt,
-                    bool force_nonblock)
+static int io_openat2_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct open_how __user *how;
+       const char __user *fname;
+       size_t len;
+       int ret;
+
+       if (sqe->ioprio || sqe->buf_index)
+               return -EINVAL;
+
+       req->open.dfd = READ_ONCE(sqe->fd);
+       fname = u64_to_user_ptr(READ_ONCE(sqe->addr));
+       how = u64_to_user_ptr(READ_ONCE(sqe->addr2));
+       len = READ_ONCE(sqe->len);
+
+       if (len < OPEN_HOW_SIZE_VER0)
+               return -EINVAL;
+
+       ret = copy_struct_from_user(&req->open.how, sizeof(req->open.how), how,
+                                       len);
+       if (ret)
+               return ret;
+
+       if (!(req->open.how.flags & O_PATH) && force_o_largefile())
+               req->open.how.flags |= O_LARGEFILE;
+
+       req->open.filename = getname(fname);
+       if (IS_ERR(req->open.filename)) {
+               ret = PTR_ERR(req->open.filename);
+               req->open.filename = NULL;
+               return ret;
+       }
+
+       return 0;
+}
+
+static int io_openat2(struct io_kiocb *req, struct io_kiocb **nxt,
+                     bool force_nonblock)
 {
        struct open_flags op;
-       struct open_how how;
        struct file *file;
        int ret;
 
@@ -2500,12 +2540,11 @@ static int io_openat(struct io_kiocb *req, struct io_kiocb **nxt,
                return -EAGAIN;
        }
 
-       how = build_open_how(req->open.how.flags, req->open.how.mode);
-       ret = build_open_flags(&how, &op);
+       ret = build_open_flags(&req->open.how, &op);
        if (ret)
                goto err;
 
-       ret = get_unused_fd_flags(how.flags);
+       ret = get_unused_fd_flags(req->open.how.flags);
        if (ret < 0)
                goto err;
 
@@ -2526,6 +2565,13 @@ err:
        return 0;
 }
 
+static int io_openat(struct io_kiocb *req, struct io_kiocb **nxt,
+                    bool force_nonblock)
+{
+       req->open.how = build_open_how(req->open.how.flags, req->open.how.mode);
+       return io_openat2(req, nxt, force_nonblock);
+}
+
 static int io_madvise_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 {
 #if defined(CONFIG_ADVISE_SYSCALLS) && defined(CONFIG_MMU)
@@ -3984,6 +4030,9 @@ static int io_req_defer_prep(struct io_kiocb *req,
        case IORING_OP_MADVISE:
                ret = io_madvise_prep(req, sqe);
                break;
+       case IORING_OP_OPENAT2:
+               ret = io_openat2_prep(req, sqe);
+               break;
        default:
                printk_once(KERN_WARNING "io_uring: unhandled opcode %d\n",
                                req->opcode);
@@ -4204,6 +4253,14 @@ static int io_issue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
                }
                ret = io_madvise(req, nxt, force_nonblock);
                break;
+       case IORING_OP_OPENAT2:
+               if (sqe) {
+                       ret = io_openat2_prep(req, sqe);
+                       if (ret)
+                               break;
+               }
+               ret = io_openat2(req, nxt, force_nonblock);
+               break;
        default:
                ret = -EINVAL;
                break;
index 66772a90a7f2dd55a5a77725026554321728c047..fea7da1828514bc944d6f117d4484ce794173bf6 100644 (file)
@@ -92,6 +92,7 @@ enum {
        IORING_OP_MADVISE,
        IORING_OP_SEND,
        IORING_OP_RECV,
+       IORING_OP_OPENAT2,
 
        /* this goes last, obviously */
        IORING_OP_LAST,