summaryrefslogtreecommitdiffstats
path: root/fs/io_uring.c
diff options
context:
space:
mode:
authorJens Axboe <axboe@kernel.dk>2020-01-09 01:59:24 +0100
committerJens Axboe <axboe@kernel.dk>2020-01-21 01:04:04 +0100
commitcebdb98617ae3e842c81c73758a185248b37cfd6 (patch)
tree68263acb7a3b3060ab3edd983c73ce9e6466260a /fs/io_uring.c
parentio_uring: remove 'fname' from io_open structure (diff)
downloadlinux-cebdb98617ae3e842c81c73758a185248b37cfd6.tar.xz
linux-cebdb98617ae3e842c81c73758a185248b37cfd6.zip
io_uring: add support for IORING_OP_OPENAT2
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>
Diffstat (limited to 'fs/io_uring.c')
-rw-r--r--fs/io_uring.c69
1 files changed, 63 insertions, 6 deletions
diff --git a/fs/io_uring.c b/fs/io_uring.c
index 3a57ea98fe3a..0b30b0cf8af5 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -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;