* [PATCH v9 1/5] fs: split off do_user_path_at_empty from user_path_at_empty()
2021-12-28 18:41 [PATCH v9 0/5] io_uring: add xattr support Stefan Roesch
@ 2021-12-28 18:41 ` Stefan Roesch
2021-12-29 14:31 ` Christian Brauner
2021-12-28 18:41 ` [PATCH v9 2/5] fs: split off setxattr_copy and do_setxattr function from setxattr Stefan Roesch
` (3 subsequent siblings)
4 siblings, 1 reply; 11+ messages in thread
From: Stefan Roesch @ 2021-12-28 18:41 UTC (permalink / raw)
To: io-uring, linux-fsdevel, kernel-team; +Cc: torvalds, christian.brauner, shr
This splits off a do_user_path_at_empty function from the
user_path_at_empty_function. This is required so it can be
called from io_uring.
Signed-off-by: Stefan Roesch <[email protected]>
Acked-by: Christian Brauner <[email protected]>
---
fs/namei.c | 10 ++++++++--
include/linux/namei.h | 2 ++
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index 1f9d2187c765..d988e241b32c 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2794,12 +2794,18 @@ int path_pts(struct path *path)
}
#endif
+int do_user_path_at_empty(int dfd, struct filename *filename, unsigned int flags,
+ struct path *path)
+{
+ return filename_lookup(dfd, filename, flags, path, NULL);
+}
+
int user_path_at_empty(int dfd, const char __user *name, unsigned flags,
- struct path *path, int *empty)
+ struct path *path, int *empty)
{
struct filename *filename = getname_flags(name, flags, empty);
- int ret = filename_lookup(dfd, filename, flags, path, NULL);
+ int ret = do_user_path_at_empty(dfd, filename, flags, path);
putname(filename);
return ret;
}
diff --git a/include/linux/namei.h b/include/linux/namei.h
index e89329bb3134..8f3ef38c057b 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -49,6 +49,8 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT};
extern int path_pts(struct path *path);
+extern int do_user_path_at_empty(int dfd, struct filename *filename,
+ unsigned int flags, struct path *path);
extern int user_path_at_empty(int, const char __user *, unsigned, struct path *, int *empty);
static inline int user_path_at(int dfd, const char __user *name, unsigned flags,
--
2.30.2
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v9 1/5] fs: split off do_user_path_at_empty from user_path_at_empty()
2021-12-28 18:41 ` [PATCH v9 1/5] fs: split off do_user_path_at_empty from user_path_at_empty() Stefan Roesch
@ 2021-12-29 14:31 ` Christian Brauner
2021-12-29 20:34 ` Stefan Roesch
0 siblings, 1 reply; 11+ messages in thread
From: Christian Brauner @ 2021-12-29 14:31 UTC (permalink / raw)
To: Stefan Roesch; +Cc: io-uring, linux-fsdevel, kernel-team, torvalds
On Tue, Dec 28, 2021 at 10:41:41AM -0800, Stefan Roesch wrote:
> This splits off a do_user_path_at_empty function from the
> user_path_at_empty_function. This is required so it can be
> called from io_uring.
>
> Signed-off-by: Stefan Roesch <[email protected]>
> Acked-by: Christian Brauner <[email protected]>
> ---
> fs/namei.c | 10 ++++++++--
> include/linux/namei.h | 2 ++
> 2 files changed, 10 insertions(+), 2 deletions(-)
>
> diff --git a/fs/namei.c b/fs/namei.c
> index 1f9d2187c765..d988e241b32c 100644
> --- a/fs/namei.c
> +++ b/fs/namei.c
> @@ -2794,12 +2794,18 @@ int path_pts(struct path *path)
> }
> #endif
>
> +int do_user_path_at_empty(int dfd, struct filename *filename, unsigned int flags,
> + struct path *path)
> +{
> + return filename_lookup(dfd, filename, flags, path, NULL);
> +}
> +
> int user_path_at_empty(int dfd, const char __user *name, unsigned flags,
> - struct path *path, int *empty)
> + struct path *path, int *empty)
> {
> struct filename *filename = getname_flags(name, flags, empty);
> - int ret = filename_lookup(dfd, filename, flags, path, NULL);
>
> + int ret = do_user_path_at_empty(dfd, filename, flags, path);
> putname(filename);
> return ret;
> }
> diff --git a/include/linux/namei.h b/include/linux/namei.h
> index e89329bb3134..8f3ef38c057b 100644
> --- a/include/linux/namei.h
> +++ b/include/linux/namei.h
> @@ -49,6 +49,8 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT};
>
> extern int path_pts(struct path *path);
>
> +extern int do_user_path_at_empty(int dfd, struct filename *filename,
> + unsigned int flags, struct path *path);
Sorry, just seeing this now but this wants to live in internal.h not in
namei.h similar to all the other io_uring specific exports we added over
the last releases. There's no need to make this a kernel-wide thing if
we can avoid it, imho. With that changed:
Acked-by: Christian Brauner <[email protected]>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v9 1/5] fs: split off do_user_path_at_empty from user_path_at_empty()
2021-12-29 14:31 ` Christian Brauner
@ 2021-12-29 20:34 ` Stefan Roesch
0 siblings, 0 replies; 11+ messages in thread
From: Stefan Roesch @ 2021-12-29 20:34 UTC (permalink / raw)
To: Christian Brauner; +Cc: io-uring, linux-fsdevel, kernel-team, torvalds
On 12/29/21 6:31 AM, Christian Brauner wrote:
> On Tue, Dec 28, 2021 at 10:41:41AM -0800, Stefan Roesch wrote:
>> This splits off a do_user_path_at_empty function from the
>> user_path_at_empty_function. This is required so it can be
>> called from io_uring.
>>
>> Signed-off-by: Stefan Roesch <[email protected]>
>> Acked-by: Christian Brauner <[email protected]>
>> ---
>> fs/namei.c | 10 ++++++++--
>> include/linux/namei.h | 2 ++
>> 2 files changed, 10 insertions(+), 2 deletions(-)
>>
>> diff --git a/fs/namei.c b/fs/namei.c
>> index 1f9d2187c765..d988e241b32c 100644
>> --- a/fs/namei.c
>> +++ b/fs/namei.c
>> @@ -2794,12 +2794,18 @@ int path_pts(struct path *path)
>> }
>> #endif
>>
>> +int do_user_path_at_empty(int dfd, struct filename *filename, unsigned int flags,
>> + struct path *path)
>> +{
>> + return filename_lookup(dfd, filename, flags, path, NULL);
>> +}
>> +
>> int user_path_at_empty(int dfd, const char __user *name, unsigned flags,
>> - struct path *path, int *empty)
>> + struct path *path, int *empty)
>> {
>> struct filename *filename = getname_flags(name, flags, empty);
>> - int ret = filename_lookup(dfd, filename, flags, path, NULL);
>>
>> + int ret = do_user_path_at_empty(dfd, filename, flags, path);
>> putname(filename);
>> return ret;
>> }
>> diff --git a/include/linux/namei.h b/include/linux/namei.h
>> index e89329bb3134..8f3ef38c057b 100644
>> --- a/include/linux/namei.h
>> +++ b/include/linux/namei.h
>> @@ -49,6 +49,8 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT};
>>
>> extern int path_pts(struct path *path);
>>
>> +extern int do_user_path_at_empty(int dfd, struct filename *filename,
>> + unsigned int flags, struct path *path);
>
> Sorry, just seeing this now but this wants to live in internal.h not in
> namei.h similar to all the other io_uring specific exports we added over
> the last releases. There's no need to make this a kernel-wide thing if
> we can avoid it, imho. With that changed:
> Acked-by: Christian Brauner <[email protected]>
I moved the declaration to fs/internal.h.
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v9 2/5] fs: split off setxattr_copy and do_setxattr function from setxattr
2021-12-28 18:41 [PATCH v9 0/5] io_uring: add xattr support Stefan Roesch
2021-12-28 18:41 ` [PATCH v9 1/5] fs: split off do_user_path_at_empty from user_path_at_empty() Stefan Roesch
@ 2021-12-28 18:41 ` Stefan Roesch
2021-12-29 14:48 ` Christian Brauner
2021-12-28 18:41 ` [PATCH v9 3/5] fs: split off do_getxattr from getxattr Stefan Roesch
` (2 subsequent siblings)
4 siblings, 1 reply; 11+ messages in thread
From: Stefan Roesch @ 2021-12-28 18:41 UTC (permalink / raw)
To: io-uring, linux-fsdevel, kernel-team; +Cc: torvalds, christian.brauner, shr
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.
Signed-off-by: Stefan Roesch <[email protected]>
---
fs/internal.h | 21 +++++++++++++
fs/xattr.c | 82 ++++++++++++++++++++++++++++++++++++---------------
2 files changed, 80 insertions(+), 23 deletions(-)
diff --git a/fs/internal.h b/fs/internal.h
index 432ea3ce76ec..00c98b0cd634 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -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);
diff --git a/fs/xattr.c b/fs/xattr.c
index 5c8c5175b385..923ba944d20e 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -25,6 +25,8 @@
#include <linux/uaccess.h>
+#include "internal.h"
+
static const char *
strcmp_prefix(const char *a, const char *a_prefix)
{
@@ -539,43 +541,77 @@ EXPORT_SYMBOL_GPL(vfs_removexattr);
/*
* Extended attribute SET operations
*/
-static long
-setxattr(struct user_namespace *mnt_userns, struct dentry *d,
- const char __user *name, const void __user *value, size_t size,
- int flags)
+
+int setxattr_copy(const char __user *name, struct xattr_ctx *ctx)
{
int error;
- void *kvalue = NULL;
- char kname[XATTR_NAME_MAX + 1];
- if (flags & ~(XATTR_CREATE|XATTR_REPLACE))
+ if (ctx->flags & ~(XATTR_CREATE|XATTR_REPLACE))
return -EINVAL;
- error = strncpy_from_user(kname, name, sizeof(kname));
- if (error == 0 || error == sizeof(kname))
- error = -ERANGE;
+ error = strncpy_from_user(ctx->kname->name, name,
+ sizeof(ctx->kname->name));
+ if (error == 0 || error == sizeof(ctx->kname->name))
+ return -ERANGE;
if (error < 0)
return error;
- if (size) {
- if (size > XATTR_SIZE_MAX)
+ if (ctx->size) {
+ if (ctx->size > XATTR_SIZE_MAX)
return -E2BIG;
- kvalue = kvmalloc(size, GFP_KERNEL);
- if (!kvalue)
+
+ ctx->kvalue = kvmalloc(ctx->size, GFP_KERNEL);
+ if (!ctx->kvalue)
return -ENOMEM;
- if (copy_from_user(kvalue, value, size)) {
- error = -EFAULT;
- goto out;
+
+ if (copy_from_user(ctx->kvalue, ctx->value, ctx->size)) {
+ kvfree(ctx->kvalue);
+ return -EFAULT;
}
- if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
- (strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
- posix_acl_fix_xattr_from_user(mnt_userns, kvalue, size);
}
- error = vfs_setxattr(mnt_userns, d, kname, kvalue, size, flags);
-out:
- kvfree(kvalue);
+ return 0;
+}
+
+static void setxattr_convert(struct user_namespace *mnt_userns,
+ struct xattr_ctx *ctx)
+{
+ if (ctx->size &&
+ ((strcmp(ctx->kname->name, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
+ (strcmp(ctx->kname->name, XATTR_NAME_POSIX_ACL_DEFAULT) == 0)))
+ posix_acl_fix_xattr_from_user(mnt_userns, ctx->kvalue, ctx->size);
+}
+
+int do_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
+ struct xattr_ctx *ctx)
+{
+ setxattr_convert(mnt_userns, ctx);
+ return vfs_setxattr(mnt_userns, dentry, ctx->kname->name,
+ ctx->kvalue, ctx->size, ctx->flags);
+}
+
+static long
+setxattr(struct user_namespace *mnt_userns, struct dentry *d,
+ const char __user *name, const void __user *value, size_t size,
+ int flags)
+{
+ struct xattr_name kname;
+ struct xattr_ctx ctx = {
+ .value = value,
+ .kvalue = NULL,
+ .size = size,
+ .kname = &kname,
+ .flags = flags,
+ };
+ int error;
+
+ error = setxattr_copy(name, &ctx);
+ if (error)
+ return error;
+
+ error = do_setxattr(mnt_userns, d, &ctx);
+ kvfree(ctx.kvalue);
return error;
}
--
2.30.2
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v9 2/5] fs: split off setxattr_copy and do_setxattr function from setxattr
2021-12-28 18:41 ` [PATCH v9 2/5] fs: split off setxattr_copy and do_setxattr function from setxattr Stefan Roesch
@ 2021-12-29 14:48 ` Christian Brauner
0 siblings, 0 replies; 11+ messages in thread
From: Christian Brauner @ 2021-12-29 14:48 UTC (permalink / raw)
To: Stefan Roesch; +Cc: io-uring, linux-fsdevel, kernel-team, torvalds
On Tue, Dec 28, 2021 at 10:41:42AM -0800, Stefan Roesch wrote:
> 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.
>
> Signed-off-by: Stefan Roesch <[email protected]>
> ---
(One completely optional thing below.)
Looks good,
Acked-by: Christian Brauner <[email protected]>
> fs/internal.h | 21 +++++++++++++
> fs/xattr.c | 82 ++++++++++++++++++++++++++++++++++++---------------
> 2 files changed, 80 insertions(+), 23 deletions(-)
>
> diff --git a/fs/internal.h b/fs/internal.h
> index 432ea3ce76ec..00c98b0cd634 100644
> --- a/fs/internal.h
> +++ b/fs/internal.h
> @@ -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];
> +};
Fwiw, one additional idea is to implement this similar to struct
filename and have it keep the __user name together with the kernel name:
struct xattr_name {
const __user char *uname; /* original userland pointer */
char name[XATTR_NAME_MAX + 1];
};
and then sm like:
From 3d85d31eb65f007e48e838fce776f16811732fc0 Mon Sep 17 00:00:00 2001
From: Christian Brauner <[email protected]>
Date: Wed, 29 Dec 2021 15:43:46 +0100
Subject: [PATCH] UNTESTED
---
fs/internal.h | 3 ++-
fs/io_uring.c | 18 ++++++++----------
fs/xattr.c | 20 +++++++++++---------
3 files changed, 21 insertions(+), 20 deletions(-)
diff --git a/fs/internal.h b/fs/internal.h
index 942b2005a2be..bb97042ebd04 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -207,7 +207,8 @@ int vfs_getdents(struct file *file, struct linux_dirent64 __user *dirent,
* fs/xattr.c:
*/
struct xattr_name {
- char name[XATTR_NAME_MAX + 1];
+ const char __user *uname;
+ char kname[XATTR_NAME_MAX + 1];
};
struct xattr_ctx {
diff --git a/fs/io_uring.c b/fs/io_uring.c
index c88916b8cccc..55ad854d3c64 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -3916,7 +3916,6 @@ 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))
@@ -3928,7 +3927,7 @@ static int __io_getxattr_prep(struct io_kiocb *req,
ix->filename = NULL;
ix->ctx.kvalue = NULL;
- name = u64_to_user_ptr(READ_ONCE(sqe->addr));
+ ix->ctx.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);
@@ -3940,9 +3939,9 @@ static int __io_getxattr_prep(struct io_kiocb *req,
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 = strncpy_from_user(ix->ctx.kname->kname, ix->ctx.name,
+ sizeof(ix->ctx.kname->kname));
+ if (!ret || ret == sizeof(ix->ctx.kname->kname))
ret = -ERANGE;
if (ret < 0) {
kfree(ix->ctx.kname);
@@ -3991,7 +3990,7 @@ static int io_fgetxattr(struct io_kiocb *req, unsigned int issue_flags)
ret = do_getxattr(mnt_user_ns(req->file->f_path.mnt),
req->file->f_path.dentry,
- ix->ctx.kname->name,
+ ix->ctx.kname->kname,
(void __user *)ix->ctx.value,
ix->ctx.size);
@@ -4019,7 +4018,7 @@ static int io_getxattr(struct io_kiocb *req, unsigned int issue_flags)
if (!ret) {
ret = do_getxattr(mnt_user_ns(path.mnt),
path.dentry,
- ix->ctx.kname->name,
+ ix->ctx.kname->kname,
(void __user *)ix->ctx.value,
ix->ctx.size);
@@ -4044,7 +4043,6 @@ 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))
@@ -4055,7 +4053,7 @@ static int __io_setxattr_prep(struct io_kiocb *req,
return -EBADF;
ix->filename = NULL;
- name = u64_to_user_ptr(READ_ONCE(sqe->addr));
+ ix->ctx.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);
@@ -4065,7 +4063,7 @@ static int __io_setxattr_prep(struct io_kiocb *req,
if (!ix->ctx.kname)
return -ENOMEM;
- ret = setxattr_copy(name, &ix->ctx);
+ ret = setxattr_copy(&ix->ctx);
if (ret) {
kfree(ix->ctx.kname);
return ret;
diff --git a/fs/xattr.c b/fs/xattr.c
index 3b6d683d07b9..27c64bb0ca65 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -542,16 +542,16 @@ EXPORT_SYMBOL_GPL(vfs_removexattr);
* Extended attribute SET operations
*/
-int setxattr_copy(const char __user *name, struct xattr_ctx *ctx)
+int setxattr_copy(struct xattr_ctx *ctx)
{
int error;
if (ctx->flags & ~(XATTR_CREATE|XATTR_REPLACE))
return -EINVAL;
- error = strncpy_from_user(ctx->kname->name, name,
- sizeof(ctx->kname->name));
- if (error == 0 || error == sizeof(ctx->kname->name))
+ error = strncpy_from_user(ctx->kname->kname, ctx->kname->name,
+ sizeof(ctx->kname->kname));
+ if (error == 0 || error == sizeof(ctx->kname->kname))
return -ERANGE;
if (error < 0)
return error;
@@ -577,8 +577,8 @@ static void setxattr_convert(struct user_namespace *mnt_userns,
struct xattr_ctx *ctx)
{
if (ctx->size &&
- ((strcmp(ctx->kname->name, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
- (strcmp(ctx->kname->name, XATTR_NAME_POSIX_ACL_DEFAULT) == 0)))
+ ((strcmp(ctx->kname->kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
+ (strcmp(ctx->kname->kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0)))
posix_acl_fix_xattr_from_user(mnt_userns, ctx->kvalue, ctx->size);
}
@@ -586,7 +586,7 @@ int do_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
struct xattr_ctx *ctx)
{
setxattr_convert(mnt_userns, ctx);
- return vfs_setxattr(mnt_userns, dentry, ctx->kname->name,
+ return vfs_setxattr(mnt_userns, dentry, ctx->kname->kname,
ctx->kvalue, ctx->size, ctx->flags);
}
@@ -595,7 +595,9 @@ setxattr(struct user_namespace *mnt_userns, struct dentry *d,
const char __user *name, const void __user *value, size_t size,
int flags)
{
- struct xattr_name kname;
+ struct xattr_name kname = {
+ .uname = name;
+ };
struct xattr_ctx ctx = {
.value = value,
.kvalue = NULL,
@@ -605,7 +607,7 @@ setxattr(struct user_namespace *mnt_userns, struct dentry *d,
};
int error;
- error = setxattr_copy(name, &ctx);
+ error = setxattr_copy(&ctx);
if (error)
return error;
--
2.30.2
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v9 3/5] fs: split off do_getxattr from getxattr
2021-12-28 18:41 [PATCH v9 0/5] io_uring: add xattr support Stefan Roesch
2021-12-28 18:41 ` [PATCH v9 1/5] fs: split off do_user_path_at_empty from user_path_at_empty() Stefan Roesch
2021-12-28 18:41 ` [PATCH v9 2/5] fs: split off setxattr_copy and do_setxattr function from setxattr Stefan Roesch
@ 2021-12-28 18:41 ` Stefan Roesch
2021-12-28 18:41 ` [PATCH v9 4/5] io_uring: add fsetxattr and setxattr support Stefan Roesch
2021-12-28 18:41 ` [PATCH v9 5/5] io_uring: add fgetxattr and getxattr support Stefan Roesch
4 siblings, 0 replies; 11+ messages in thread
From: Stefan Roesch @ 2021-12-28 18:41 UTC (permalink / raw)
To: io-uring, linux-fsdevel, kernel-team; +Cc: torvalds, christian.brauner, shr
This splits off do_getxattr function from the getxattr
function. This will allow io_uring to call it from its
io worker.
Signed-off-by: Stefan Roesch <[email protected]>
Acked-by: Christian Brauner <[email protected]>
---
fs/internal.h | 7 +++++++
fs/xattr.c | 32 ++++++++++++++++++++------------
2 files changed, 27 insertions(+), 12 deletions(-)
diff --git a/fs/internal.h b/fs/internal.h
index 00c98b0cd634..942b2005a2be 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -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);
diff --git a/fs/xattr.c b/fs/xattr.c
index 923ba944d20e..3b6d683d07b9 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -677,19 +677,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)
@@ -713,10 +706,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)
--
2.30.2
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v9 4/5] io_uring: add fsetxattr and setxattr support
2021-12-28 18:41 [PATCH v9 0/5] io_uring: add xattr support Stefan Roesch
` (2 preceding siblings ...)
2021-12-28 18:41 ` [PATCH v9 3/5] fs: split off do_getxattr from getxattr Stefan Roesch
@ 2021-12-28 18:41 ` Stefan Roesch
2021-12-29 14:51 ` Christian Brauner
2021-12-28 18:41 ` [PATCH v9 5/5] io_uring: add fgetxattr and getxattr support Stefan Roesch
4 siblings, 1 reply; 11+ messages in thread
From: Stefan Roesch @ 2021-12-28 18:41 UTC (permalink / raw)
To: io-uring, linux-fsdevel, kernel-team; +Cc: torvalds, christian.brauner, shr
This adds support to io_uring for the fsetxattr and setxattr API.
Signed-off-by: Stefan Roesch <[email protected]>
---
fs/io_uring.c | 165 ++++++++++++++++++++++++++++++++++
include/uapi/linux/io_uring.h | 6 +-
2 files changed, 170 insertions(+), 1 deletion(-)
diff --git a/fs/io_uring.c b/fs/io_uring.c
index c8258c784116..2a0138a2876a 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -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,140 @@ static int io_renameat(struct io_kiocb *req, unsigned int issue_flags)
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 *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)
+{
+ struct io_xattr *ix = &req->xattr;
+ int ret;
+
+ if (issue_flags & IO_URING_F_NONBLOCK)
+ return -EAGAIN;
+
+ ret = __io_setxattr(req, issue_flags, &req->file->f_path);
+
+ req->flags &= ~REQ_F_NEED_CLEANUP;
+ kfree(ix->ctx.kname);
+
+ if (ix->ctx.kvalue)
+ kvfree(ix->ctx.kvalue);
+ if (ret < 0)
+ req_set_fail(req);
+
+ io_req_complete(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 = do_user_path_at_empty(AT_FDCWD, ix->filename, lookup_flags, &path);
+ if (!ret) {
+ ret = __io_setxattr(req, issue_flags, &path);
+ path_put(&path);
+ if (retry_estale(ret, lookup_flags)) {
+ lookup_flags |= LOOKUP_REVAL;
+ goto retry;
+ }
+ }
+ putname(ix->filename);
+
+ req->flags &= ~REQ_F_NEED_CLEANUP;
+ kfree(ix->ctx.kname);
+
+ if (ix->ctx.kvalue)
+ kvfree(ix->ctx.kvalue);
+ if (ret < 0)
+ req_set_fail(req);
+
+ io_req_complete(req, ret);
+ return 0;
+}
+
static int io_unlinkat_prep(struct io_kiocb *req,
const struct io_uring_sqe *sqe)
{
@@ -6623,6 +6769,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 +6914,14 @@ static void io_clean_op(struct io_kiocb *req)
putname(req->hardlink.oldpath);
putname(req->hardlink.newpath);
break;
+ case IORING_OP_SETXATTR:
+ if (req->xattr.filename)
+ putname(req->xattr.filename);
+ fallthrough;
+ case IORING_OP_FSETXATTR:
+ kfree(req->xattr.ctx.kname);
+ kvfree(req->xattr.ctx.kvalue);
+ 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));
diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h
index 57dc88db5793..c62a8bec8cd4 100644
--- a/include/uapi/linux/io_uring.h
+++ b/include/uapi/linux/io_uring.h
@@ -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,
--
2.30.2
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v9 4/5] io_uring: add fsetxattr and setxattr support
2021-12-28 18:41 ` [PATCH v9 4/5] io_uring: add fsetxattr and setxattr support Stefan Roesch
@ 2021-12-29 14:51 ` Christian Brauner
2021-12-29 20:35 ` Stefan Roesch
0 siblings, 1 reply; 11+ messages in thread
From: Christian Brauner @ 2021-12-29 14:51 UTC (permalink / raw)
To: Stefan Roesch; +Cc: io-uring, linux-fsdevel, kernel-team, torvalds
On Tue, Dec 28, 2021 at 10:41:44AM -0800, Stefan Roesch wrote:
> This adds support to io_uring for the fsetxattr and setxattr API.
>
> Signed-off-by: Stefan Roesch <[email protected]>
> ---
> fs/io_uring.c | 165 ++++++++++++++++++++++++++++++++++
> include/uapi/linux/io_uring.h | 6 +-
> 2 files changed, 170 insertions(+), 1 deletion(-)
>
> diff --git a/fs/io_uring.c b/fs/io_uring.c
> index c8258c784116..2a0138a2876a 100644
> --- a/fs/io_uring.c
> +++ b/fs/io_uring.c
> @@ -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,140 @@ static int io_renameat(struct io_kiocb *req, unsigned int issue_flags)
> 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 *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)
> +{
> + struct io_xattr *ix = &req->xattr;
> + int ret;
> +
> + if (issue_flags & IO_URING_F_NONBLOCK)
> + return -EAGAIN;
> +
> + ret = __io_setxattr(req, issue_flags, &req->file->f_path);
> +
> + req->flags &= ~REQ_F_NEED_CLEANUP;
> + kfree(ix->ctx.kname);
> +
> + if (ix->ctx.kvalue)
> + kvfree(ix->ctx.kvalue);
> + if (ret < 0)
> + req_set_fail(req);
> +
> + io_req_complete(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 = do_user_path_at_empty(AT_FDCWD, ix->filename, lookup_flags, &path);
> + if (!ret) {
> + ret = __io_setxattr(req, issue_flags, &path);
> + path_put(&path);
> + if (retry_estale(ret, lookup_flags)) {
> + lookup_flags |= LOOKUP_REVAL;
> + goto retry;
> + }
> + }
> + putname(ix->filename);
> +
> + req->flags &= ~REQ_F_NEED_CLEANUP;
> + kfree(ix->ctx.kname);
> +
> + if (ix->ctx.kvalue)
> + kvfree(ix->ctx.kvalue);
> + if (ret < 0)
> + req_set_fail(req);
> +
> + io_req_complete(req, ret);
> + return 0;
> +}
(One suggestin below.)
Looks good,
Acked-by: Christian Brauner <[email protected]>
You could minimize the redudancy by implementing a simple helper
callable from both io_fsetxattr() and io_setxattr() if you think it's
worth with. So sm like:
From 2f837aa2a19b5cd8e73fffb9b87b6e6b22c5cae7 Mon Sep 17 00:00:00 2001
From: Christian Brauner <[email protected]>
Date: Wed, 29 Dec 2021 15:22:34 +0100
Subject: [PATCH] UNTESTED
---
fs/io_uring.c | 36 +++++++++++++++++-------------------
1 file changed, 17 insertions(+), 19 deletions(-)
diff --git a/fs/io_uring.c b/fs/io_uring.c
index 7204b8d593e4..c88916b8cccc 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -4118,6 +4118,21 @@ static int __io_setxattr(struct io_kiocb *req, unsigned int issue_flags,
return ret;
}
+static void __io_setxattr_finish(struct io_kiocb *req, int ret)
+{
+ struct xattr_ctx *ctx = &req->xattr.ctx;
+
+ req->flags &= ~REQ_F_NEED_CLEANUP;
+
+ kfree(ctx->kname);
+ if (ctx->kvalue)
+ kvfree(ctx->kvalue);
+
+ if (ret < 0)
+ req_set_fail(req);
+
+ io_req_complete(req, ret);
+}
+
static int io_fsetxattr(struct io_kiocb *req, unsigned int issue_flags)
{
struct io_xattr *ix = &req->xattr;
@@ -4127,16 +4142,7 @@ static int io_fsetxattr(struct io_kiocb *req, unsigned int issue_flags)
return -EAGAIN;
ret = __io_setxattr(req, issue_flags, &req->file->f_path);
-
- req->flags &= ~REQ_F_NEED_CLEANUP;
- kfree(ix->ctx.kname);
-
- if (ix->ctx.kvalue)
- kvfree(ix->ctx.kvalue);
- if (ret < 0)
- req_set_fail(req);
-
- io_req_complete(req, ret);
+ __io_setxattr_finish(req, ret);
return 0;
}
@@ -4162,15 +4168,7 @@ static int io_setxattr(struct io_kiocb *req, unsigned int issue_flags)
}
putname(ix->filename);
- req->flags &= ~REQ_F_NEED_CLEANUP;
- kfree(ix->ctx.kname);
-
- if (ix->ctx.kvalue)
- kvfree(ix->ctx.kvalue);
- if (ret < 0)
- req_set_fail(req);
-
- io_req_complete(req, ret);
+ __io_setxattr_finish(req, ret);
return 0;
}
--
2.30.2
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v9 4/5] io_uring: add fsetxattr and setxattr support
2021-12-29 14:51 ` Christian Brauner
@ 2021-12-29 20:35 ` Stefan Roesch
0 siblings, 0 replies; 11+ messages in thread
From: Stefan Roesch @ 2021-12-29 20:35 UTC (permalink / raw)
To: Christian Brauner; +Cc: io-uring, linux-fsdevel, kernel-team, torvalds
On 12/29/21 6:51 AM, Christian Brauner wrote:
> On Tue, Dec 28, 2021 at 10:41:44AM -0800, Stefan Roesch wrote:
>> This adds support to io_uring for the fsetxattr and setxattr API.
>>
>> Signed-off-by: Stefan Roesch <[email protected]>
>> ---
>> fs/io_uring.c | 165 ++++++++++++++++++++++++++++++++++
>> include/uapi/linux/io_uring.h | 6 +-
>> 2 files changed, 170 insertions(+), 1 deletion(-)
>>
>> diff --git a/fs/io_uring.c b/fs/io_uring.c
>> index c8258c784116..2a0138a2876a 100644
>> --- a/fs/io_uring.c
>> +++ b/fs/io_uring.c
>> @@ -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,140 @@ static int io_renameat(struct io_kiocb *req, unsigned int issue_flags)
>> 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 *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)
>> +{
>> + struct io_xattr *ix = &req->xattr;
>> + int ret;
>> +
>> + if (issue_flags & IO_URING_F_NONBLOCK)
>> + return -EAGAIN;
>> +
>> + ret = __io_setxattr(req, issue_flags, &req->file->f_path);
>> +
>> + req->flags &= ~REQ_F_NEED_CLEANUP;
>> + kfree(ix->ctx.kname);
>> +
>> + if (ix->ctx.kvalue)
>> + kvfree(ix->ctx.kvalue);
>> + if (ret < 0)
>> + req_set_fail(req);
>> +
>> + io_req_complete(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 = do_user_path_at_empty(AT_FDCWD, ix->filename, lookup_flags, &path);
>> + if (!ret) {
>> + ret = __io_setxattr(req, issue_flags, &path);
>> + path_put(&path);
>> + if (retry_estale(ret, lookup_flags)) {
>> + lookup_flags |= LOOKUP_REVAL;
>> + goto retry;
>> + }
>> + }
>> + putname(ix->filename);
>> +
>> + req->flags &= ~REQ_F_NEED_CLEANUP;
>> + kfree(ix->ctx.kname);
>> +
>> + if (ix->ctx.kvalue)
>> + kvfree(ix->ctx.kvalue);
>> + if (ret < 0)
>> + req_set_fail(req);
>> +
>> + io_req_complete(req, ret);
>> + return 0;
>> +}
>
> (One suggestin below.)
>
> Looks good,
> Acked-by: Christian Brauner <[email protected]>
>
> You could minimize the redudancy by implementing a simple helper
> callable from both io_fsetxattr() and io_setxattr() if you think it's
> worth with. So sm like:
>
> From 2f837aa2a19b5cd8e73fffb9b87b6e6b22c5cae7 Mon Sep 17 00:00:00 2001
> From: Christian Brauner <[email protected]>
> Date: Wed, 29 Dec 2021 15:22:34 +0100
> Subject: [PATCH] UNTESTED
>
I added the helper function. I made a similar change for the get case.
> ---
> fs/io_uring.c | 36 +++++++++++++++++-------------------
> 1 file changed, 17 insertions(+), 19 deletions(-)
>
> diff --git a/fs/io_uring.c b/fs/io_uring.c
> index 7204b8d593e4..c88916b8cccc 100644
> --- a/fs/io_uring.c
> +++ b/fs/io_uring.c
> @@ -4118,6 +4118,21 @@ static int __io_setxattr(struct io_kiocb *req, unsigned int issue_flags,
> return ret;
> }
>
> +static void __io_setxattr_finish(struct io_kiocb *req, int ret)
> +{
> + struct xattr_ctx *ctx = &req->xattr.ctx;
> +
> + req->flags &= ~REQ_F_NEED_CLEANUP;
> +
> + kfree(ctx->kname);
> + if (ctx->kvalue)
> + kvfree(ctx->kvalue);
> +
> + if (ret < 0)
> + req_set_fail(req);
> +
> + io_req_complete(req, ret);
> +}
> +
> static int io_fsetxattr(struct io_kiocb *req, unsigned int issue_flags)
> {
> struct io_xattr *ix = &req->xattr;
> @@ -4127,16 +4142,7 @@ static int io_fsetxattr(struct io_kiocb *req, unsigned int issue_flags)
> return -EAGAIN;
>
> ret = __io_setxattr(req, issue_flags, &req->file->f_path);
> -
> - req->flags &= ~REQ_F_NEED_CLEANUP;
> - kfree(ix->ctx.kname);
> -
> - if (ix->ctx.kvalue)
> - kvfree(ix->ctx.kvalue);
> - if (ret < 0)
> - req_set_fail(req);
> -
> - io_req_complete(req, ret);
> + __io_setxattr_finish(req, ret);
> return 0;
> }
>
> @@ -4162,15 +4168,7 @@ static int io_setxattr(struct io_kiocb *req, unsigned int issue_flags)
> }
> putname(ix->filename);
>
> - req->flags &= ~REQ_F_NEED_CLEANUP;
> - kfree(ix->ctx.kname);
> -
> - if (ix->ctx.kvalue)
> - kvfree(ix->ctx.kvalue);
> - if (ret < 0)
> - req_set_fail(req);
> -
> - io_req_complete(req, ret);
> + __io_setxattr_finish(req, ret);
> return 0;
> }
>
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v9 5/5] io_uring: add fgetxattr and getxattr support
2021-12-28 18:41 [PATCH v9 0/5] io_uring: add xattr support Stefan Roesch
` (3 preceding siblings ...)
2021-12-28 18:41 ` [PATCH v9 4/5] io_uring: add fsetxattr and setxattr support Stefan Roesch
@ 2021-12-28 18:41 ` Stefan Roesch
4 siblings, 0 replies; 11+ messages in thread
From: Stefan Roesch @ 2021-12-28 18:41 UTC (permalink / raw)
To: io-uring, linux-fsdevel, kernel-team; +Cc: torvalds, christian.brauner, shr
This adds support to io_uring for the fgetxattr and getxattr API.
Signed-off-by: Stefan Roesch <[email protected]>
---
fs/io_uring.c | 149 ++++++++++++++++++++++++++++++++++
include/uapi/linux/io_uring.h | 2 +
2 files changed, 151 insertions(+)
diff --git a/fs/io_uring.c b/fs/io_uring.c
index 2a0138a2876a..5b8370a62547 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -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() */
@@ -3899,6 +3903,134 @@ 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->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);
+
+ req->flags &= ~REQ_F_NEED_CLEANUP;
+ kfree(ix->ctx.kname);
+ 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);
+ 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;
+ }
+ }
+ putname(ix->filename);
+
+ req->flags &= ~REQ_F_NEED_CLEANUP;
+ kfree(ix->ctx.kname);
+ 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)
{
@@ -6773,6 +6905,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",
@@ -6922,6 +7058,13 @@ static void io_clean_op(struct io_kiocb *req)
kfree(req->xattr.ctx.kname);
kvfree(req->xattr.ctx.kvalue);
break;
+ case IORING_OP_GETXATTR:
+ if (req->xattr.filename)
+ putname(req->xattr.filename);
+ fallthrough;
+ case IORING_OP_FGETXATTR:
+ kfree(req->xattr.ctx.kname);
+ break;
}
}
if ((req->flags & REQ_F_POLLED) && req->apoll) {
@@ -7073,6 +7216,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;
diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h
index c62a8bec8cd4..efc7ac9b3a6b 100644
--- a/include/uapi/linux/io_uring.h
+++ b/include/uapi/linux/io_uring.h
@@ -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,
--
2.30.2
^ permalink raw reply related [flat|nested] 11+ messages in thread