This adds support to io_uring for the fgetxattr and getxattr API. Signed-off-by: Stefan Roesch <shr@xxxxxx> --- fs/io_uring.c | 142 ++++++++++++++++++++++++++++++++++ include/uapi/linux/io_uring.h | 2 + 2 files changed, 144 insertions(+) diff --git a/fs/io_uring.c b/fs/io_uring.c index 9f56a2e3bc32..cd9fb60ecf72 100644 --- a/fs/io_uring.c +++ b/fs/io_uring.c @@ -1116,6 +1116,10 @@ static const struct io_op_def io_op_defs[] = { [IORING_OP_MKDIRAT] = {}, [IORING_OP_SYMLINKAT] = {}, [IORING_OP_LINKAT] = {}, + [IORING_OP_FGETXATTR] = { + .needs_file = 1 + }, + [IORING_OP_GETXATTR] = {}, [IORING_OP_FSETXATTR] = { .needs_file = 1 }, @@ -3889,6 +3893,125 @@ static int io_renameat(struct io_kiocb *req, unsigned int issue_flags) return 0; } +static int __io_getxattr_prep(struct io_kiocb *req, + const struct io_uring_sqe *sqe) +{ + struct io_xattr *ix = &req->xattr; + const char __user *name; + int ret; + + if (unlikely(req->ctx->flags & IORING_SETUP_IOPOLL)) + return -EINVAL; + if (unlikely(sqe->ioprio)) + return -EINVAL; + if (unlikely(req->flags & REQ_F_FIXED_FILE)) + return -EBADF; + + ix->filename = NULL; + ix->value = NULL; + name = u64_to_user_ptr(READ_ONCE(sqe->addr)); + ix->ctx.value = u64_to_user_ptr(READ_ONCE(sqe->addr2)); + ix->ctx.size = READ_ONCE(sqe->len); + ix->ctx.flags = READ_ONCE(sqe->xattr_flags); + + if (ix->ctx.flags) + return -EINVAL; + + ret = strncpy_from_user(ix->ctx.kname, name, sizeof(ix->ctx.kname)); + if (!ret || ret == sizeof(ix->ctx.kname)) + ret = -ERANGE; + if (ret < 0) + return ret; + + req->flags |= REQ_F_NEED_CLEANUP; + return 0; +} + +static int io_fgetxattr_prep(struct io_kiocb *req, + const struct io_uring_sqe *sqe) +{ + return __io_getxattr_prep(req, sqe); +} + +static int io_getxattr_prep(struct io_kiocb *req, + const struct io_uring_sqe *sqe) +{ + struct io_xattr *ix = &req->xattr; + const char __user *path; + int ret; + + ret = __io_getxattr_prep(req, sqe); + if (ret) + return ret; + + path = u64_to_user_ptr(READ_ONCE(sqe->addr3)); + + ix->filename = getname_flags(path, LOOKUP_FOLLOW, NULL); + if (IS_ERR(ix->filename)) { + ret = PTR_ERR(ix->filename); + ix->filename = NULL; + } + + return ret; +} + +static int io_fgetxattr(struct io_kiocb *req, unsigned int issue_flags) +{ + struct io_xattr *ix = &req->xattr; + int ret; + + if (issue_flags & IO_URING_F_NONBLOCK) + return -EAGAIN; + + ret = do_getxattr(mnt_user_ns(req->file->f_path.mnt), + req->file->f_path.dentry, + ix->ctx.kname, + (void __user *)ix->ctx.value, + ix->ctx.size); + + req->flags &= ~REQ_F_NEED_CLEANUP; + if (ret < 0) + req_set_fail(req); + + io_req_complete(req, ret); + return 0; +} + +static int io_getxattr(struct io_kiocb *req, unsigned int issue_flags) +{ + struct io_xattr *ix = &req->xattr; + unsigned int lookup_flags = LOOKUP_FOLLOW; + struct path path; + int ret; + + if (issue_flags & IO_URING_F_NONBLOCK) + return -EAGAIN; + +retry: + ret = do_user_path_at_empty(AT_FDCWD, ix->filename, lookup_flags, &path); + putname(ix->filename); + if (!ret) { + ret = do_getxattr(mnt_user_ns(path.mnt), + path.dentry, + ix->ctx.kname, + (void __user *)ix->ctx.value, + ix->ctx.size); + + path_put(&path); + if (retry_estale(ret, lookup_flags)) { + lookup_flags |= LOOKUP_REVAL; + goto retry; + } + } + + req->flags &= ~REQ_F_NEED_CLEANUP; + if (ret < 0) + req_set_fail(req); + + io_req_complete(req, ret); + return 0; +} + static int __io_setxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe, struct user_namespace *user_ns) @@ -6714,6 +6837,10 @@ static int io_req_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) return io_symlinkat_prep(req, sqe); case IORING_OP_LINKAT: return io_linkat_prep(req, sqe); + case IORING_OP_FGETXATTR: + return io_fgetxattr_prep(req, sqe); + case IORING_OP_GETXATTR: + return io_getxattr_prep(req, sqe); case IORING_OP_FSETXATTR: return io_fsetxattr_prep(req, sqe); case IORING_OP_SETXATTR: @@ -6859,6 +6986,15 @@ static void io_clean_op(struct io_kiocb *req) putname(req->hardlink.oldpath); putname(req->hardlink.newpath); break; + + case IORING_OP_GETXATTR: + if (req->xattr.filename) + putname(req->xattr.filename); + break; + + case IORING_OP_FGETXATTR: + break; + case IORING_OP_SETXATTR: if (req->xattr.filename) putname(req->xattr.filename); @@ -7009,6 +7145,12 @@ static int io_issue_sqe(struct io_kiocb *req, unsigned int issue_flags) case IORING_OP_LINKAT: ret = io_linkat(req, issue_flags); break; + case IORING_OP_FGETXATTR: + ret = io_fgetxattr(req, issue_flags); + break; + case IORING_OP_GETXATTR: + ret = io_getxattr(req, issue_flags); + break; case IORING_OP_FSETXATTR: ret = io_fsetxattr(req, issue_flags); break; diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h index dbf473900da2..cd9160272308 100644 --- a/include/uapi/linux/io_uring.h +++ b/include/uapi/linux/io_uring.h @@ -145,7 +145,9 @@ enum { IORING_OP_MKDIRAT, IORING_OP_SYMLINKAT, IORING_OP_LINKAT, + IORING_OP_FGETXATTR, IORING_OP_FSETXATTR, + IORING_OP_GETXATTR, IORING_OP_SETXATTR, /* this goes last, obviously */ -- 2.30.2