diff options
author | Jens Axboe <axboe@kernel.dk> | 2020-01-08 17:59:24 -0700 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2020-01-20 17:04:04 -0700 |
commit | cebdb98617ae3e842c81c73758a185248b37cfd6 (patch) | |
tree | 68263acb7a3b3060ab3edd983c73ce9e6466260a /fs/io_uring.c | |
parent | f8748881b17dc56b3faa1d30c823f071c56593e5 (diff) | |
download | lwn-cebdb98617ae3e842c81c73758a185248b37cfd6.tar.gz lwn-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.c | 69 |
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; |