io_uring: add xattr support
v13 cover io_uring: add xattr support
This adds the xattr support to io_uring. The intent is to have a more complete support for file operations in io_uring.
This change adds support for the following functions to io_uring:
- fgetxattr
- fsetxattr
- getxattr
- setxattr
Patch 1: fs: split off setxattr_copy and do_setxattr function from setxattr
Split off the setup part of the setxattr function in the setxattr_copy function. Split off the processing part in do_setxattr.
Patch 2: fs: split off do_getxattr from getxattr
Split of the do_getxattr part from getxattr. This will allow it to be invoked it from io_uring.
Patch 3: io_uring: add fsetxattr and setxattr support
This adds new functions to support the fsetxattr and setxattr functions.
Patch 4: io_uring: add fgetxattr and getxattr support
This adds new functions to support the fgetxattr and getxattr functions.
There are two additional patches:
liburing: Add support for xattr api's.
This also includes the tests for the new code.
xfstests: Add support for io_uring xattr support.
Changes:
V13: - refreshed the code
- Review comments mentioned that the statx api in io_uring was not following the same pattern as the xattr api. This has been fixed by a previous patch (using the same pattern as this patch)
V12: - add union to xattr_ctx structure. The getxattr api requires
a pointer to value and the setxattr requires a const pointer to value (with a union this can be unified).
- use xattr_ctx structure in do_getxattr call.
V11: - removed the do_user_path_at_empty function and directly
call filename_lookup
- introduce __io_xattr_finish and io_xattr_finish functions to unify the cleanup code
- remove the older __io_setxattr_finish function
V10: - move do_user_path_at_empty definition to fs/internal.h
- introduce __io_setxattr_finish function
- introduce __io_getxattr_finish function
V9 : - keep kvalue in struct xattr_ctx
V8 : - introduce xattr_name struct as advised by Linus
- remove kname_sz field in xattr_ctx
V7 : - split off setxattr in two functions as recommeneded by
Christian.
V6 : - reverted addition of kname array to xattr_ctx structure
Adding the kname array increases the io_kiocb beyond 64 bytes (increases it to 224 bytes). We try hard to limit it to 64 bytes. Keeping the original interface also is a bit more efficient.
- addressed Pavel's reordering comment
- addressed Pavel's putname comment
- addressed Pavel's kvfree comment
- rebased on for-5.17/io_uring-getdents64
V5 : - add kname array to xattr_ctx structure
V4 : - rebased patch series
V3 : - remove req->file checks in prep functions
- change size parameter in do_xattr
V2 : - split off function do_user_path_empty instead of changing
the function signature of user_path_at
- Fix datatype size problem in do_getxattr
Stefan Roesch (4):
fs: split off setxattr_copy and do_setxattr function from setxattr
fs: split off do_getxattr from getxattr
io_uring: add fsetxattr and setxattr support
io_uring: add fgetxattr and getxattr support
fs/internal.h | 29 ++++ fs/io_uring.c | 294 ++++++++++++++++++++++++++++++++++ fs/xattr.c | 141 ++++++++++------ include/uapi/linux/io_uring.h | 8 +- 4 files changed, 426 insertions(+), 46 deletions(-)
base-commit: ad9c6ee642a61adae93dfa35582b5af16dc5173a
Signature · 1 line
2.30.2
PATCH v13 1/4 fs: split off setxattr_copy and do_setxattr function from setxattr
This splits of the setup part of the function setxattr in its own dedicated function called setxattr_copy. In addition it also exposes a new function called do_setxattr for making the setxattr call.
This makes it possible to call these two functions from io_uring in the processing of an xattr request.
--- fs/internal.h | 24 +++++++++++++++ fs/xattr.c | 82 ++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 82 insertions(+), 24 deletions(-)
fs/internal.h +24 -0
@@ -196,3 +196,27 @@ long splice_file_to_pipe(struct file *in,struct pipe_inode_info *opipe, loff_t *offset, size_t len, unsigned int flags); + +/* +* fs/xattr.c: +*/ +struct xattr_name { +char name[XATTR_NAME_MAX +1 ]; +}; + +struct xattr_ctx { +/* Value of attribute */ +union { +const void __user *cvalue; +void __user *value; + }; +void *kvalue; +size_t size; +/* Attribute name */ +struct xattr_name *kname; +unsigned int flags; +}; + +int setxattr_copy (const char __user *name,struct xattr_ctx *ctx); +int do_setxattr (struct user_namespace *mnt_userns,struct dentry *dentry, +struct xattr_ctx *ctx);
fs/xattr.c +58 -24
107 lines not on this page · raw message
Signature · 1 line
2.30.2
PATCH v13 2/4 fs: split off do_getxattr from getxattr
In reply to Stefan RoeschThis splits off do_getxattr function from the getxattr function. This will allow io_uring to call it from its io worker.
--- fs/internal.h | 5 +++++ fs/xattr.c | 59 +++++++++++++++++++++++++++++++++------------------ 2 files changed, 43 insertions(+), 21 deletions(-)
fs/internal.h +5 -0
@@ -217,6 +217,11 @@ struct xattr_ctx {unsigned int flags; }; + +ssize_t do_getxattr (struct user_namespace *mnt_userns, +struct dentry *d, +struct xattr_ctx *ctx); +int setxattr_copy (const char __user *name,struct xattr_ctx *ctx);int do_setxattr (struct user_namespace *mnt_userns,struct dentry *dentry,struct xattr_ctx *ctx);
fs/xattr.c +38 -21
81 lines not on this page · raw message
Signature · 1 line
2.30.2
PATCH v13 3/4 io_uring: add fsetxattr and setxattr support
In reply to Stefan RoeschThis adds support to io_uring for the fsetxattr and setxattr API.
--- fs/io_uring.c | 165 ++++++++++++++++++++++++++++++++++ include/uapi/linux/io_uring.h | 6 +- 2 files changed, 170 insertions(+), 1 deletion(-)
fs/io_uring.c +165 -0
@@ -82,6 +82,7 @@#include <linux/tracehook.h> #include <linux/audit.h> #include <linux/security.h> +#include <linux/xattr.h> #define CREATE_TRACE_POINTS #include <trace/events/io_uring.h>
@@ -755,6 +756,12 @@ struct io_async_rw {struct wait_page_queue wpq; }; +struct io_xattr { +struct file *file; +struct xattr_ctx ctx; +struct filename *filename; +}; +enum {REQ_F_FIXED_FILE_BIT =IOSQE_FIXED_FILE_BIT ,REQ_F_IO_DRAIN_BIT =IOSQE_IO_DRAIN_BIT ,
@@ -901,6 +908,7 @@ struct io_kiocb {struct io_symlink symlink;struct io_hardlink hardlink;struct io_msg msg; +struct io_xattr xattr; };u8 opcode;
@@ -1154,6 +1162,10 @@ static const struct io_op_def io_op_defs[] = { [IORING_OP_MSG_RING ] = { .needs_file =1 , }, + [IORING_OP_FSETXATTR ] = { + .needs_file =1 + }, + [IORING_OP_SETXATTR] = {}, };/* requests with any of those set should undergo io_disarm_next() */
@@ -4094,6 +4106,144 @@ static int io_renameat(struct io_kiocb *req, unsigned int issue_flags)return 0 ; } +static inline void __io_xattr_finish (struct io_kiocb *req) +{ +struct io_xattr *ix = &req->xattr; + +if (ix->filename) +putname (ix->filename); + +kfree (ix->ctx.kname); +kvfree (ix->ctx.kvalue); +} + +static void io_xattr_finish (struct io_kiocb *req,int ret) +{ + req->flags &= ~REQ_F_NEED_CLEANUP ; + +__io_xattr_finish (req); +if (ret <0 ) +req_set_fail (req); + +io_req_complete (req, ret); +} + +static int __io_setxattr_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 ; + name =u64_to_user_ptr (READ_ONCE (sqe->addr)); + ix->ctx.cvalue =u64_to_user_ptr (READ_ONCE (sqe->addr2)); + ix->ctx.kvalue =NULL ; + ix->ctx.size =READ_ONCE (sqe->len); + ix->ctx.flags =READ_ONCE (sqe->xattr_flags); + + ix->ctx.kname =kmalloc (sizeof (*ix->ctx.kname),GFP_KERNEL ); +if (!ix->ctx.kname) +return -ENOMEM ; + + ret =setxattr_copy (name, &ix->ctx); +if (ret) { +kfree (ix->ctx.kname); +return ret; + } + + req->flags |=REQ_F_NEED_CLEANUP ; +return 0 ; +} + +static int io_setxattr_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_setxattr_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_fsetxattr_prep (struct io_kiocb *req, +const struct io_uring_sqe *sqe) +{ +return __io_setxattr_prep (req, sqe); +} + +static int __io_setxattr (struct io_kiocb *req,unsigned int issue_flags, +struct path *path) +{ +struct io_xattr *ix = &req->xattr; +int ret; + + ret =mnt_want_write (path->mnt); +if (!ret) { + ret =do_setxattr (mnt_user_ns (path->mnt), path->dentry, &ix->ctx); +mnt_drop_write (path->mnt); + } + +return ret; +} + +static int io_fsetxattr (struct io_kiocb *req,unsigned int issue_flags) +{ +int ret; + +if (issue_flags &IO_URING_F_NONBLOCK ) +return -EAGAIN ; + + ret =__io_setxattr (req, issue_flags, &req->file->f_path); +io_xattr_finish (req, ret); + +return 0 ; +} + +static int io_setxattr (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 =filename_lookup (AT_FDCWD , ix->filename, lookup_flags, &path,NULL ); +if (!ret) { + ret =__io_setxattr (req, issue_flags, &path); +path_put (&path); +if (retry_estale (ret, lookup_flags)) { + lookup_flags |=LOOKUP_REVAL ; + goto retry; + } + } + +io_xattr_finish (req, ret); +return 0 ; +} +static int io_unlinkat_prep (struct io_kiocb *req,const struct io_uring_sqe *sqe) {
@@ -6985,6 +7135,10 @@ static int io_req_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)return io_linkat_prep (req, sqe);case IORING_OP_MSG_RING :return io_msg_ring_prep (req, sqe); +case IORING_OP_FSETXATTR : +return io_fsetxattr_prep (req, sqe); +case IORING_OP_SETXATTR : +return io_setxattr_prep (req, sqe); } printk_once(KERN_WARNING "io_uring: unhandled opcode %d\n",
@@ -7130,6 +7284,10 @@ static void io_clean_op(struct io_kiocb *req)if (req->statx.filename)putname (req->statx.filename);break ; +case IORING_OP_SETXATTR : +case IORING_OP_FSETXATTR : +__io_xattr_finish (req); +break ; } }if ((req->flags &REQ_F_POLLED ) && req->apoll) {
@@ -7275,6 +7433,12 @@ static int io_issue_sqe(struct io_kiocb *req, unsigned int issue_flags)case IORING_OP_MSG_RING : ret =io_msg_ring (req, issue_flags);break ; +case IORING_OP_FSETXATTR : + ret =io_fsetxattr (req, issue_flags); +break ; +case IORING_OP_SETXATTR : + ret =io_setxattr (req, issue_flags); +break ;default : ret = -EINVAL ;break ;
@@ -11927,6 +12091,7 @@ static int __init io_uring_init(void)BUILD_BUG_SQE_ELEM (42 , __u16, personality);BUILD_BUG_SQE_ELEM (44 , __s32, splice_fd_in);BUILD_BUG_SQE_ELEM (44 , __u32, file_index); +BUILD_BUG_SQE_ELEM (48 , __u64, addr3);BUILD_BUG_ON (sizeof (struct io_uring_files_update ) !=sizeof (struct io_uring_rsrc_update ));
include/uapi/linux/io_uring.h +5 -1
@@ -45,6 +45,7 @@ struct io_uring_sqe {__u32 rename_flags;__u32 unlink_flags;__u32 hardlink_flags; +__u32 xattr_flags; };__u64 user_data;/* data to be passed back at completion time */ /* pack this to avoid bogus arm OABI complaints */
@@ -60,7 +61,8 @@ struct io_uring_sqe {__s32 splice_fd_in;__u32 file_index; }; -__u64 __pad2[2 ]; +__u64 addr3; +__u64 __pad2[1 ]; };enum {
@@ -145,6 +147,8 @@ enum {IORING_OP_SYMLINKAT ,IORING_OP_LINKAT ,IORING_OP_MSG_RING , +IORING_OP_FSETXATTR , +IORING_OP_SETXATTR ,/* this goes last, obviously */ IORING_OP_LAST,
Signature · 1 line
2.30.2
PATCH v13 4/4 io_uring: add fgetxattr and getxattr support
In reply to Stefan RoeschThis adds support to io_uring for the fgetxattr and getxattr API.
--- fs/io_uring.c | 129 ++++++++++++++++++++++++++++++++++ include/uapi/linux/io_uring.h | 2 + 2 files changed, 131 insertions(+)
fs/io_uring.c +129 -0
@@ -1166,6 +1166,10 @@ static const struct io_op_def io_op_defs[] = { .needs_file = 1 }, [IORING_OP_SETXATTR] = {}, + [IORING_OP_FGETXATTR ] = { + .needs_file =1 + }, + [IORING_OP_GETXATTR] = {}, };/* requests with any of those set should undergo io_disarm_next() */
@@ -4128,6 +4132,119 @@ static void io_xattr_finish(struct io_kiocb *req, int ret)io_req_complete (req, ret); } +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->ctx.kvalue =NULL ; + name =u64_to_user_ptr (READ_ONCE (sqe->addr)); + ix->ctx.cvalue =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 ; + + ix->ctx.kname =kmalloc (sizeof (*ix->ctx.kname),GFP_KERNEL ); +if (!ix->ctx.kname) +return -ENOMEM ; + + ret =strncpy_from_user (ix->ctx.kname->name, name, +sizeof (ix->ctx.kname->name)); +if (!ret || ret ==sizeof (ix->ctx.kname->name)) + ret = -ERANGE ; +if (ret <0 ) { +kfree (ix->ctx.kname); +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); + +io_xattr_finish (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 =filename_lookup (AT_FDCWD , ix->filename, lookup_flags, &path,NULL ); +if (!ret) { + ret =do_getxattr (mnt_user_ns (path.mnt), + path.dentry, + &ix->ctx); + +path_put (&path); +if (retry_estale (ret, lookup_flags)) { + lookup_flags |=LOOKUP_REVAL ; + goto retry; + } + } + +io_xattr_finish (req, ret); +return 0 ; +} +static int __io_setxattr_prep (struct io_kiocb *req,const struct io_uring_sqe *sqe) {
@@ -7139,6 +7256,10 @@ static int io_req_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)return io_fsetxattr_prep (req, sqe);case IORING_OP_SETXATTR :return io_setxattr_prep (req, sqe); +case IORING_OP_FGETXATTR : +return io_fgetxattr_prep (req, sqe); +case IORING_OP_GETXATTR : +return io_getxattr_prep (req, sqe); } printk_once(KERN_WARNING "io_uring: unhandled opcode %d\n",
@@ -7286,6 +7407,8 @@ static void io_clean_op(struct io_kiocb *req)break ;case IORING_OP_SETXATTR :case IORING_OP_FSETXATTR : +case IORING_OP_GETXATTR : +case IORING_OP_FGETXATTR :__io_xattr_finish (req);break ; }
@@ -7439,6 +7562,12 @@ static int io_issue_sqe(struct io_kiocb *req, unsigned int issue_flags)case IORING_OP_SETXATTR : ret =io_setxattr (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 ;default : ret = -EINVAL ;break ;
include/uapi/linux/io_uring.h +2 -0
@@ -149,6 +149,8 @@ enum {IORING_OP_MSG_RING ,IORING_OP_FSETXATTR ,IORING_OP_SETXATTR , +IORING_OP_FGETXATTR , +IORING_OP_GETXATTR ,/* this goes last, obviously */ IORING_OP_LAST,
Signature · 1 line
2.30.2
Re: [PATCH v13 4/4] io_uring: add fgetxattr and getxattr support
Quoted 4 lines · Stefan Roesch
This adds support to
io_uringfor the fgetxattr and getxattr API.Signed-off-by Stefan Roesch <[email protected]>---
Looks good to me,
Quoted 10 lines · Stefan Roesch
This adds the xattr support to
io_uring. The intent is to have a more complete support for file operations inio_uring.This change adds support for the following functions to
io_uring:
- fgetxattr
- fsetxattr
- getxattr
- setxattr[...]
Applied, thanks!
[1/4] fs: split off setxattr_copy and do_setxattr function from setxattr
commit: bbe6239e931bbb57983dcf94eacc8aaa757d26b0
[2/4] fs: split off do_getxattr from getxattr
commit: 9c8ebeb51e866b9d0fa16fa628797d7e9483a6fc
[3/4] io_uring: add fsetxattr and setxattr support
commit: 7c0773d493344a03e40a71c66fbe080c1fd87acb
[4/4] io_uring: add fgetxattr and getxattr support
commit: b2fdcc6667b89e4da68b5543b641e809145432f8Best regards,
Signature · 1 line
Jens Axboe