io_uring: add xattr support
v11 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.
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 | 28 ++++ fs/io_uring.c | 298 ++++++++++++++++++++++++++++++++++ fs/xattr.c | 114 +++++++++---- include/uapi/linux/io_uring.h | 8 +- 4 files changed, 411 insertions(+), 37 deletions(-)
base-commit: b4518682080d3a1cdd6ea45a54ff6772b8b2797a
Signature · 1 line
2.30.2
PATCH v11 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 | 21 +++++++++++++ fs/xattr.c | 82 ++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 79 insertions(+), 24 deletions(-)
fs/internal.h +21 -0
@@ -202,3 +202,24 @@ struct linux_dirent64;int vfs_getdents (struct file *file,struct linux_dirent64 __user *dirent,unsigned int count,loff_t *pos); + +/* +* fs/xattr.c: +*/ +struct xattr_name { +char name[XATTR_NAME_MAX +1 ]; +}; + +struct xattr_ctx { +/* Value of attribute */ +const 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 v11 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 | 7 +++++++ fs/xattr.c | 32 ++++++++++++++++++++------------ 2 files changed, 27 insertions(+), 12 deletions(-)
fs/internal.h +7 -0
@@ -220,6 +220,13 @@ struct xattr_ctx {unsigned int flags; }; + +ssize_t do_getxattr (struct user_namespace *mnt_userns, +struct dentry *d, +const char *kname, +void __user *value, +size_t size); +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 +20 -12
@@ -675,19 +675,12 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name,/* * Extended attribute GET operations */ -static ssize_t -getxattr (struct user_namespace *mnt_userns,struct dentry *d, -const char __user *name,void __user *value,size_t size) +ssize_t +do_getxattr (struct user_namespace *mnt_userns,struct dentry *d, +const char *kname,void __user *value,size_t size) { -ssize_t error;void *kvalue =NULL ; -char kname[XATTR_NAME_MAX +1 ]; - - error =strncpy_from_user (kname, name,sizeof (kname)); -if (error ==0 || error ==sizeof (kname)) - error = -ERANGE ; -if (error <0 ) -return error; +ssize_t error;if (size) {if (size >XATTR_SIZE_MAX )
@@ -711,10 +704,25 @@ getxattr(struct user_namespace *mnt_userns, struct dentry *d, }kvfree (kvalue); -return error; } +static ssize_t +getxattr (struct user_namespace *mnt_userns,struct dentry *d, +const char __user *name,void __user *value,size_t size) +{ +ssize_t error; +struct xattr_name kname; + + error =strncpy_from_user (kname.name, name,sizeof (kname.name)); +if (error ==0 || error ==sizeof (kname.name)) + error = -ERANGE ; +if (error <0 ) +return error; + +return do_getxattr (mnt_userns, d, kname.name, value, size); +} +static ssize_t path_getxattr (const char __user *pathname,const char __user *name,void __user *value,size_t size,unsigned int lookup_flags)
Signature · 1 line
2.30.2
Re: [PATCH v11 2/4] fs: split off do_getxattr from getxattr
Quoted 70 lines · Stefan Roesch
This splits off
do_getxattrfunction from the getxattr function. This will allowio_uringto call it from its io worker.Signed-off-by Stefan Roesch <[email protected]>--- fs/internal.h | 7 +++++++ fs/xattr.c | 32 ++++++++++++++++++++------------ 2 files changed, 27 insertions(+), 12 deletions(-)fs/internal.h +7
-0@@ -220,6 +220,13 @@ struct xattr_ctx {unsigned int flags; }; + +ssize_t do_getxattr (struct user_namespace *mnt_userns, +struct dentry *d, +const char *kname, +void __user *value, +size_t size); +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 +9
-12@@ -675,19 +675,12 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name,/* * Extended attribute GET operations */ -static ssize_t -getxattr (struct user_namespace *mnt_userns,struct dentry *d, -const char __user *name,void __user *value,size_t size) +ssize_t +do_getxattr (struct user_namespace *mnt_userns,struct dentry *d, +const char *kname,void __user *value,size_t size) { -ssize_t error;void *kvalue =NULL ; -char kname[XATTR_NAME_MAX +1 ]; - - error =strncpy_from_user (kname, name,sizeof (kname)); -if (error ==0 || error ==sizeof (kname)) - error = -ERANGE ; -if (error <0 ) -return error; +ssize_t error;if (size) {if (size >XATTR_SIZE_MAX )@@ -711,10 +704,25 @@ getxattr(struct user_namespace *mnt_userns, struct dentry *d, }kvfree (kvalue); -return error; } +static ssize_t +getxattr (struct user_namespace *mnt_userns,struct dentry *d, +const char __user *name,void __user *value,size_t size) +{ +ssize_t error;
fs/xattr.c getxattr(struct user_namespace *mnt_userns, struct dentry *d, · line 724
Quoted 10 lines
fs/xattr.c +10
-0+struct xattr_name kname; + + error =strncpy_from_user (kname.name, name,sizeof (kname.name)); +if (error ==0 || error ==sizeof (kname.name)) + error = -ERANGE ; +if (error <0 ) +return error; + +return do_getxattr (mnt_userns, d, kname.name, value, size); +}
Fwiw, this could have the same signature as do_setxattr(). So sm along the lines of (completely untested):
Subject: [PATCH] UNTESTED
--- fs/internal.h | 8 ++------ fs/xattr.c | 36 ++++++++++++++++++++++-------------- 2 files changed, 24 insertions(+), 20 deletions(-)
fs/internal.h +2 -6
@@ -220,12 +220,8 @@ struct xattr_ctx {unsigned int flags; }; - -ssize_t do_getxattr (struct user_namespace *mnt_userns, -struct dentry *d, -const char *kname, -void __user *value, -size_t size); +ssize_t do_getxattr (struct user_namespace *mnt_userns,struct dentry *dentry, +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,
fs/xattr.c +22 -14
@@ -675,35 +675,34 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name,/* * Extended attribute GET operations */ -ssize_t -do_getxattr (struct user_namespace *mnt_userns,struct dentry *d, -const char *kname,void __user *value,size_t size) +ssize_t do_getxattr (struct user_namespace *mnt_userns,struct dentry *dentry, +struct xattr_ctx *ctx) + { -void *kvalue =NULL ;ssize_t error; +char *kname = ctx->kname.name; -if (size) { -if (size >XATTR_SIZE_MAX ) - size =XATTR_SIZE_MAX ; - kvalue =kvzalloc (size,GFP_KERNEL ); -if (!kvalue) +if (ctx->size) { +if (ctx->size >XATTR_SIZE_MAX ) + ctx->size =XATTR_SIZE_MAX ; + ctx->kvalue =kvzalloc (ctx->size,GFP_KERNEL ); +if (!ctx->kvalue)return -ENOMEM ; } - error =vfs_getxattr (mnt_userns, d, kname, kvalue, size); + error =vfs_getxattr (mnt_userns, d, kname, ctx->kvalue, ctx->size);if (error >0 ) {if ((strcmp (kname,XATTR_NAME_POSIX_ACL_ACCESS ) ==0 ) || (strcmp (kname,XATTR_NAME_POSIX_ACL_DEFAULT ) ==0 ))posix_acl_fix_xattr_to_user (mnt_userns, kvalue, error); -if (size &©_to_user (value, kvalue, error)) +if (ctx->size &©_to_user (value, kvalue, error)) error = -EFAULT ; - }else if (error == -ERANGE && size >=XATTR_SIZE_MAX ) { + }else if (error == -ERANGE && ctx->size >=XATTR_SIZE_MAX ) {/* The file system tried to returned a value bigger than XATTR_SIZE_MAX bytes. Not possible. */ error = -E2BIG ; } -kvfree (kvalue);return error; }
@@ -713,6 +712,12 @@ getxattr(struct user_namespace *mnt_userns, struct dentry *d, {ssize_t error;struct xattr_name kname; +struct xattr_ctx ctx = { + .value = value, + .kvalue =NULL , + .size = size, + .kname = &kname, + }; error =strncpy_from_user (kname.name, name,sizeof (kname.name));if (error ==0 || error ==sizeof (kname.name))
@@ -720,7 +725,10 @@ getxattr(struct user_namespace *mnt_userns, struct dentry *d,if (error <0 )return error; -return do_getxattr (mnt_userns, d, kname.name, value, size); + error =do_getxattr (mnt_userns, d, &ctx); + +kvfree (ctx.kvalue); +return error; } static ssize_t path_getxattr(const char __user *pathname,
Signature · 1 line
2.32.0
Re: [PATCH v11 2/4] fs: split off do_getxattr from getxattr
Quoted 76 lines · Christian Brauner
Quoted 75 lines · Stefan Roesch
This splits off
do_getxattrfunction from the getxattr function. This will allowio_uringto call it from its io worker.Signed-off-by Stefan Roesch <[email protected]>--- fs/internal.h | 7 +++++++ fs/xattr.c | 32 ++++++++++++++++++++------------ 2 files changed, 27 insertions(+), 12 deletions(-)fs/internal.h +7
-0@@ -220,6 +220,13 @@ struct xattr_ctx {unsigned int flags; }; + +ssize_t do_getxattr (struct user_namespace *mnt_userns, +struct dentry *d, +const char *kname, +void __user *value, +size_t size); +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 +14
-12@@ -675,19 +675,12 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name,/* * Extended attribute GET operations */ -static ssize_t -getxattr (struct user_namespace *mnt_userns,struct dentry *d, -const char __user *name,void __user *value,size_t size) +ssize_t +do_getxattr (struct user_namespace *mnt_userns,struct dentry *d, +const char *kname,void __user *value,size_t size) { -ssize_t error;void *kvalue =NULL ; -char kname[XATTR_NAME_MAX +1 ]; - - error =strncpy_from_user (kname, name,sizeof (kname)); -if (error ==0 || error ==sizeof (kname)) - error = -ERANGE ; -if (error <0 ) -return error; +ssize_t error;if (size) {if (size >XATTR_SIZE_MAX )@@ -711,10 +704,25 @@ getxattr(struct user_namespace *mnt_userns, struct dentry *d, }kvfree (kvalue); -return error; } +static ssize_t +getxattr (struct user_namespace *mnt_userns,struct dentry *d, +const char __user *name,void __user *value,size_t size) +{ +ssize_t error; +struct xattr_name kname; + + error =strncpy_from_user (kname.name, name,sizeof (kname.name)); +if (error ==0 || error ==sizeof (kname.name)) + error = -ERANGE ;
Quoted 9 lines
fs/xattr.c getxattr(struct user_namespace *mnt_userns, struct dentry *d, · line 724
Quoted 5 lines
fs/xattr.c +5
-0+if (error <0 ) +return error; + +return do_getxattr (mnt_userns, d, kname.name, value, size); +}Fwiw, this could have the same signature as
do_setxattr(). So sm along the lines of (completely untested):
Christian, I made changes similar to the ones you recommended. However I needed to introduce a union in the xattr_ctx structure. For the setxattr function we require a const pointer and for getxattr function we only require a pointer.
In addition it also needs changes in io_uring.c to pass in the context.
v12 has these changes.
Quoted 103 lines
Subject: [PATCH] UNTESTED
--- fs/internal.h | 8 ++------ fs/xattr.c | 36 ++++++++++++++++++++++-------------- 2 files changed, 24 insertions(+), 20 deletions(-)fs/internal.h +2
-6@@ -220,12 +220,8 @@ struct xattr_ctx {unsigned int flags; }; - -ssize_t do_getxattr (struct user_namespace *mnt_userns, -struct dentry *d, -const char *kname, -void __user *value, -size_t size); +ssize_t do_getxattr (struct user_namespace *mnt_userns,struct dentry *dentry, +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,fs/xattr.c +22
-14@@ -675,35 +675,34 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name,/* * Extended attribute GET operations */ -ssize_t -do_getxattr (struct user_namespace *mnt_userns,struct dentry *d, -const char *kname,void __user *value,size_t size) +ssize_t do_getxattr (struct user_namespace *mnt_userns,struct dentry *dentry, +struct xattr_ctx *ctx) + { -void *kvalue =NULL ;ssize_t error; +char *kname = ctx->kname.name; -if (size) { -if (size >XATTR_SIZE_MAX ) - size =XATTR_SIZE_MAX ; - kvalue =kvzalloc (size,GFP_KERNEL ); -if (!kvalue) +if (ctx->size) { +if (ctx->size >XATTR_SIZE_MAX ) + ctx->size =XATTR_SIZE_MAX ; + ctx->kvalue =kvzalloc (ctx->size,GFP_KERNEL ); +if (!ctx->kvalue)return -ENOMEM ; } - error =vfs_getxattr (mnt_userns, d, kname, kvalue, size); + error =vfs_getxattr (mnt_userns, d, kname, ctx->kvalue, ctx->size);if (error >0 ) {if ((strcmp (kname,XATTR_NAME_POSIX_ACL_ACCESS ) ==0 ) || (strcmp (kname,XATTR_NAME_POSIX_ACL_DEFAULT ) ==0 ))posix_acl_fix_xattr_to_user (mnt_userns, kvalue, error); -if (size &©_to_user (value, kvalue, error)) +if (ctx->size &©_to_user (value, kvalue, error)) error = -EFAULT ; - }else if (error == -ERANGE && size >=XATTR_SIZE_MAX ) { + }else if (error == -ERANGE && ctx->size >=XATTR_SIZE_MAX ) {/* The file system tried to returned a value bigger than XATTR_SIZE_MAX bytes. Not possible. */ error = -E2BIG ; } -kvfree (kvalue);return error; }@@ -713,6 +712,12 @@ getxattr(struct user_namespace *mnt_userns, struct dentry *d, {ssize_t error;struct xattr_name kname; +struct xattr_ctx ctx = { + .value = value, + .kvalue =NULL , + .size = size, + .kname = &kname, + }; error =strncpy_from_user (kname.name, name,sizeof (kname.name));if (error ==0 || error ==sizeof (kname.name))@@ -720,7 +725,10 @@ getxattr(struct user_namespace *mnt_userns, struct dentry *d,if (error <0 )return error; -return do_getxattr (mnt_userns, d, kname.name, value, size); + error =do_getxattr (mnt_userns, d, &ctx); + +kvfree (ctx.kvalue); +return error; } static ssize_t path_getxattr(const char __user *pathname,
PATCH v11 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/audit.h> #include <linux/security.h> #include <linux/atomic-ref.h> +#include <linux/xattr.h> #define CREATE_TRACE_POINTS #include <trace/events/io_uring.h>
@@ -726,6 +727,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 ,
@@ -866,6 +873,7 @@ struct io_kiocb {struct io_symlink symlink;struct io_hardlink hardlink;struct io_getdents getdents; +struct io_xattr xattr; };u8 opcode;
@@ -1118,6 +1126,10 @@ static const struct io_op_def io_op_defs[] = { [IORING_OP_GETDENTS ] = { .needs_file =1 , }, + [IORING_OP_FSETXATTR ] = { + .needs_file =1 + }, + [IORING_OP_SETXATTR] = {}, };/* requests with any of those set should undergo io_disarm_next() */
@@ -3887,6 +3899,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.value =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) {
@@ -6623,6 +6773,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_GETDENTS :return io_getdents_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",
@@ -6764,6 +6918,10 @@ static void io_clean_op(struct io_kiocb *req)putname (req->hardlink.oldpath);putname (req->hardlink.newpath);break ; +case IORING_OP_SETXATTR : +case IORING_OP_FSETXATTR : +__io_xattr_finish (req); +break ; } }if ((req->flags &REQ_F_POLLED ) && req->apoll) {
@@ -6909,6 +7067,12 @@ static int io_issue_sqe(struct io_kiocb *req, unsigned int issue_flags)case IORING_OP_GETDENTS : ret =io_getdents (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 ;
@@ -11277,6 +11441,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 {
@@ -144,6 +146,8 @@ enum {IORING_OP_SYMLINKAT ,IORING_OP_LINKAT ,IORING_OP_GETDENTS , +IORING_OP_FSETXATTR , +IORING_OP_SETXATTR ,/* this goes last, obviously */ IORING_OP_LAST,
Signature · 1 line
2.30.2
PATCH v11 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 | 133 ++++++++++++++++++++++++++++++++++ include/uapi/linux/io_uring.h | 2 + 2 files changed, 135 insertions(+)
fs/io_uring.c +133 -0
@@ -1130,6 +1130,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() */
@@ -3921,6 +3925,123 @@ 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.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 ; + + 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.kname->name, + (void __user *)ix->ctx.value, + ix->ctx.size); + +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.kname->name, + (void __user *)ix->ctx.value, + ix->ctx.size); + +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) {
@@ -6777,6 +6898,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",
@@ -6920,6 +7045,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 ; }
@@ -7073,6 +7200,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
@@ -148,6 +148,8 @@ enum {IORING_OP_GETDENTS ,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