All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 0/5] io_uring: add xattr support
@ 2021-12-21 16:49 Stefan Roesch
  2021-12-21 16:49 ` [PATCH v5 1/5] fs: split off do_user_path_at_empty from user_path_at_empty() Stefan Roesch
                   ` (4 more replies)
  0 siblings, 5 replies; 11+ messages in thread
From: Stefan Roesch @ 2021-12-21 16:49 UTC (permalink / raw)
  To: io-uring, linux-fsdevel, kernel-team; +Cc: torvalds, shr

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 do_user_path_at_empty from user_path_at_empty()
  This splits off a new function do_user_path_at_empty from
  user_path_at_empty that is based on filename and not on a
  user-specified string.

Patch 2: fs: split off setxattr_setup function from setxattr
  Split off the setup part of the setxattr function.

Patch 3: 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 4: io_uring: add fsetxattr and setxattr support
  This adds new functions to support the fsetxattr and setxattr
  functions.

Patch 5: 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.

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 (5):
  fs: split off do_user_path_at_empty from user_path_at_empty()
  fs: split off setxattr_setup 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                 |  22 +++
 fs/io_uring.c                 | 301 ++++++++++++++++++++++++++++++++++
 fs/namei.c                    |  10 +-
 fs/xattr.c                    | 105 +++++++-----
 include/linux/namei.h         |   2 +
 include/uapi/linux/io_uring.h |   8 +-
 6 files changed, 408 insertions(+), 40 deletions(-)


base-commit: d09358c3d161dcea8f02eae1281bc996819cc769
-- 
2.30.2


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v5 1/5] fs: split off do_user_path_at_empty from user_path_at_empty()
  2021-12-21 16:49 [PATCH v5 0/5] io_uring: add xattr support Stefan Roesch
@ 2021-12-21 16:49 ` Stefan Roesch
  2021-12-21 16:49 ` [PATCH v5 2/5] fs: split off setxattr_setup function from setxattr Stefan Roesch
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 11+ messages in thread
From: Stefan Roesch @ 2021-12-21 16:49 UTC (permalink / raw)
  To: io-uring, linux-fsdevel, kernel-team; +Cc: torvalds, 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 <shr@fb.com>
---
 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

* [PATCH v5 2/5] fs: split off setxattr_setup function from setxattr
  2021-12-21 16:49 [PATCH v5 0/5] io_uring: add xattr support Stefan Roesch
  2021-12-21 16:49 ` [PATCH v5 1/5] fs: split off do_user_path_at_empty from user_path_at_empty() Stefan Roesch
@ 2021-12-21 16:49 ` Stefan Roesch
  2021-12-21 16:49 ` [PATCH v5 3/5] fs: split off do_getxattr from getxattr Stefan Roesch
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 11+ messages in thread
From: Stefan Roesch @ 2021-12-21 16:49 UTC (permalink / raw)
  To: io-uring, linux-fsdevel, kernel-team; +Cc: torvalds, shr

This splits of the setup part of the function
setxattr in its own dedicated function called
setxattr_setup.

This makes it possible to call this function
from io_uring in the pre-processing of an
xattr request.

Signed-off-by: Stefan Roesch <shr@fb.com>
---
 fs/internal.h | 16 +++++++++++
 fs/xattr.c    | 74 +++++++++++++++++++++++++++++++++------------------
 2 files changed, 64 insertions(+), 26 deletions(-)

diff --git a/fs/internal.h b/fs/internal.h
index 7979ff8d168c..d13b9f13df09 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -194,3 +194,19 @@ 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_ctx {
+	/* Value of attribute */
+	const void __user *value;
+	size_t size;
+	/* Attribute name */
+	char kname[XATTR_NAME_MAX + 1];
+	unsigned int flags;
+};
+
+void *setxattr_setup(struct user_namespace *mnt_userns,
+		     const char __user *name,
+		     struct xattr_ctx *data);
diff --git a/fs/xattr.c b/fs/xattr.c
index 5c8c5175b385..a4b59523bd0e 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,63 @@ 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)
+
+void *setxattr_setup(struct user_namespace *mnt_userns, const char __user *name,
+		struct xattr_ctx *ctx)
 {
-	int error;
 	void *kvalue = NULL;
-	char kname[XATTR_NAME_MAX + 1];
+	int error;
 
-	if (flags & ~(XATTR_CREATE|XATTR_REPLACE))
-		return -EINVAL;
+	if (ctx->flags & ~(XATTR_CREATE|XATTR_REPLACE))
+		return ERR_PTR(-EINVAL);
 
-	error = strncpy_from_user(kname, name, sizeof(kname));
-	if (error == 0 || error == sizeof(kname))
-		error = -ERANGE;
+	error = strncpy_from_user(ctx->kname, name, sizeof(ctx->kname));
+	if (error == 0 || error == sizeof(ctx->kname))
+		return  ERR_PTR(-ERANGE);
 	if (error < 0)
-		return error;
+		return ERR_PTR(error);
 
-	if (size) {
-		if (size > XATTR_SIZE_MAX)
-			return -E2BIG;
-		kvalue = kvmalloc(size, GFP_KERNEL);
+	if (ctx->size) {
+		if (ctx->size > XATTR_SIZE_MAX)
+			return ERR_PTR(-E2BIG);
+
+		kvalue = kvmalloc(ctx->size, GFP_KERNEL);
 		if (!kvalue)
-			return -ENOMEM;
-		if (copy_from_user(kvalue, value, size)) {
-			error = -EFAULT;
-			goto out;
+			return ERR_PTR(-ENOMEM);
+
+		if (copy_from_user(kvalue, ctx->value, ctx->size)) {
+			kvfree(kvalue);
+			return ERR_PTR(-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);
+
+		if ((strcmp(ctx->kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
+		    (strcmp(ctx->kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
+			posix_acl_fix_xattr_from_user(mnt_userns, kvalue, ctx->size);
 	}
 
-	error = vfs_setxattr(mnt_userns, d, kname, kvalue, size, flags);
-out:
-	kvfree(kvalue);
+	return kvalue;
+}
 
+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_ctx ctx = {
+		.value    = value,
+		.size     = size,
+		.flags    = flags,
+	};
+	void *kvalue;
+	int error;
+
+	kvalue = setxattr_setup(mnt_userns, name, &ctx);
+	if (IS_ERR(kvalue))
+		return PTR_ERR(kvalue);
+
+	error = vfs_setxattr(mnt_userns, d, ctx.kname, kvalue, size, flags);
+
+	kvfree(kvalue);
 	return error;
 }
 
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v5 3/5] fs: split off do_getxattr from getxattr
  2021-12-21 16:49 [PATCH v5 0/5] io_uring: add xattr support Stefan Roesch
  2021-12-21 16:49 ` [PATCH v5 1/5] fs: split off do_user_path_at_empty from user_path_at_empty() Stefan Roesch
  2021-12-21 16:49 ` [PATCH v5 2/5] fs: split off setxattr_setup function from setxattr Stefan Roesch
@ 2021-12-21 16:49 ` Stefan Roesch
  2021-12-21 17:22   ` Linus Torvalds
  2021-12-21 16:49 ` [PATCH v5 4/5] io_uring: add fsetxattr and setxattr support Stefan Roesch
  2021-12-21 16:49 ` [PATCH v5 5/5] io_uring: add fgetxattr and getxattr support Stefan Roesch
  4 siblings, 1 reply; 11+ messages in thread
From: Stefan Roesch @ 2021-12-21 16:49 UTC (permalink / raw)
  To: io-uring, linux-fsdevel, kernel-team; +Cc: torvalds, 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 <shr@fb.com>
---
 fs/internal.h |  6 ++++++
 fs/xattr.c    | 31 ++++++++++++++++++++-----------
 2 files changed, 26 insertions(+), 11 deletions(-)

diff --git a/fs/internal.h b/fs/internal.h
index d13b9f13df09..efd2c4f7a536 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -207,6 +207,12 @@ 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);
+
 void *setxattr_setup(struct user_namespace *mnt_userns,
 		     const char __user *name,
 		     struct xattr_ctx *data);
diff --git a/fs/xattr.c b/fs/xattr.c
index a4b59523bd0e..1d9795bc8be6 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -663,19 +663,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)
@@ -703,6 +696,22 @@ getxattr(struct user_namespace *mnt_userns, struct dentry *d,
 	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;
+	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;
+
+	return do_getxattr(mnt_userns, d, kname, 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 v5 4/5] io_uring: add fsetxattr and setxattr support
  2021-12-21 16:49 [PATCH v5 0/5] io_uring: add xattr support Stefan Roesch
                   ` (2 preceding siblings ...)
  2021-12-21 16:49 ` [PATCH v5 3/5] fs: split off do_getxattr from getxattr Stefan Roesch
@ 2021-12-21 16:49 ` Stefan Roesch
  2021-12-21 16:49 ` [PATCH v5 5/5] io_uring: add fgetxattr and getxattr support Stefan Roesch
  4 siblings, 0 replies; 11+ messages in thread
From: Stefan Roesch @ 2021-12-21 16:49 UTC (permalink / raw)
  To: io-uring, linux-fsdevel, kernel-team; +Cc: torvalds, shr

This adds support to io_uring for the fsetxattr and setxattr API.

Signed-off-by: Stefan Roesch <shr@fb.com>
---
 fs/io_uring.c                 | 159 ++++++++++++++++++++++++++++++++++
 include/uapi/linux/io_uring.h |   6 +-
 2 files changed, 164 insertions(+), 1 deletion(-)

diff --git a/fs/io_uring.c b/fs/io_uring.c
index 5092dfe56da6..9f56a2e3bc32 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>
@@ -719,6 +720,13 @@ struct io_async_rw {
 	struct wait_page_queue		wpq;
 };
 
+struct io_xattr {
+	struct file			*file;
+	struct xattr_ctx		ctx;
+	void				*value;
+	struct filename			*filename;
+};
+
 enum {
 	REQ_F_FIXED_FILE_BIT	= IOSQE_FIXED_FILE_BIT,
 	REQ_F_IO_DRAIN_BIT	= IOSQE_IO_DRAIN_BIT,
@@ -858,6 +866,7 @@ struct io_kiocb {
 		struct io_mkdir		mkdir;
 		struct io_symlink	symlink;
 		struct io_hardlink	hardlink;
+		struct io_xattr		xattr;
 	};
 
 	u8				opcode;
@@ -1107,6 +1116,10 @@ static const struct io_op_def io_op_defs[] = {
 	[IORING_OP_MKDIRAT] = {},
 	[IORING_OP_SYMLINKAT] = {},
 	[IORING_OP_LINKAT] = {},
+	[IORING_OP_FSETXATTR] = {
+		.needs_file = 1
+	},
+	[IORING_OP_SETXATTR] = {},
 };
 
 /* requests with any of those set should undergo io_disarm_next() */
@@ -3876,6 +3889,133 @@ 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 user_namespace *user_ns)
+{
+	struct io_xattr *ix = &req->xattr;
+	const char __user *name;
+	void *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.size = READ_ONCE(sqe->len);
+	ix->ctx.flags = READ_ONCE(sqe->xattr_flags);
+
+	ret = setxattr_setup(user_ns, name, &ix->ctx);
+	if (IS_ERR(ret))
+		return PTR_ERR(ret);
+
+	ix->value = 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, current_user_ns());
+	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, file_mnt_user_ns(req->file));
+}
+
+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 = vfs_setxattr(mnt_user_ns(path->mnt), path->dentry,
+				ix->ctx.kname, ix->value, ix->ctx.size,
+				ix->ctx.flags);
+		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;
+	if (ix->value)
+		kvfree(ix->value);
+	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);
+	putname(ix->filename);
+	if (!ret) {
+		ret = __io_setxattr(req, issue_flags, &path);
+		path_put(&path);
+		if (retry_estale(ret, lookup_flags)) {
+			lookup_flags |= LOOKUP_REVAL;
+			goto retry;
+		}
+	}
+
+	req->flags &= ~REQ_F_NEED_CLEANUP;
+	if (ix->value)
+		kvfree(ix->value);
+	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)
 {
@@ -6574,6 +6714,10 @@ static int io_req_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 		return io_symlinkat_prep(req, sqe);
 	case IORING_OP_LINKAT:
 		return io_linkat_prep(req, sqe);
+	case IORING_OP_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",
@@ -6715,6 +6859,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:
+			if (req->xattr.value)
+				kvfree(req->xattr.value);
+			break;
 		}
 	}
 	if ((req->flags & REQ_F_POLLED) && req->apoll) {
@@ -6857,6 +7009,12 @@ static int io_issue_sqe(struct io_kiocb *req, unsigned int issue_flags)
 	case IORING_OP_LINKAT:
 		ret = io_linkat(req, issue_flags);
 		break;
+	case IORING_OP_FSETXATTR:
+		ret = io_fsetxattr(req, issue_flags);
+		break;
+	case IORING_OP_SETXATTR:
+		ret = io_setxattr(req, issue_flags);
+		break;
 	default:
 		ret = -EINVAL;
 		break;
@@ -11225,6 +11383,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 787f491f0d2a..dbf473900da2 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 {
@@ -143,6 +145,8 @@ enum {
 	IORING_OP_MKDIRAT,
 	IORING_OP_SYMLINKAT,
 	IORING_OP_LINKAT,
+	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

* [PATCH v5 5/5] io_uring: add fgetxattr and getxattr support
  2021-12-21 16:49 [PATCH v5 0/5] io_uring: add xattr support Stefan Roesch
                   ` (3 preceding siblings ...)
  2021-12-21 16:49 ` [PATCH v5 4/5] io_uring: add fsetxattr and setxattr support Stefan Roesch
@ 2021-12-21 16:49 ` Stefan Roesch
  4 siblings, 0 replies; 11+ messages in thread
From: Stefan Roesch @ 2021-12-21 16:49 UTC (permalink / raw)
  To: io-uring, linux-fsdevel, kernel-team; +Cc: torvalds, shr

This adds support to io_uring for the fgetxattr and getxattr API.

Signed-off-by: Stefan Roesch <shr@fb.com>
---
 fs/io_uring.c                 | 142 ++++++++++++++++++++++++++++++++++
 include/uapi/linux/io_uring.h |   2 +
 2 files changed, 144 insertions(+)

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


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH v5 3/5] fs: split off do_getxattr from getxattr
  2021-12-21 16:49 ` [PATCH v5 3/5] fs: split off do_getxattr from getxattr Stefan Roesch
@ 2021-12-21 17:22   ` Linus Torvalds
  2021-12-21 19:15     ` Stefan Roesch
  0 siblings, 1 reply; 11+ messages in thread
From: Linus Torvalds @ 2021-12-21 17:22 UTC (permalink / raw)
  To: Stefan Roesch; +Cc: io-uring, linux-fsdevel, Kernel Team

On Tue, Dec 21, 2021 at 8:50 AM Stefan Roesch <shr@fb.com> wrote:
>
> This splits off do_getxattr function from the getxattr
> function. This will allow io_uring to call it from its
> io worker.

Hmm.

My reaction to this one is

 "Why isn't do_getxattr() using 'struct xattr_ctx' for its context?"

As far as I can tell, that's *exactly* what it wants, and it would be
logical to match up with the setxattr side.

Yeah, yeah, setxattr has a 'const void __user *value' while getxattr
obviously has just a 'void __user *value'. But if the cost of having a
unified interface is that you lose the 'const' part for the setxattr,
I think that's still a good thing.

Yes? No? Comments?

              Linus

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v5 3/5] fs: split off do_getxattr from getxattr
  2021-12-21 17:22   ` Linus Torvalds
@ 2021-12-21 19:15     ` Stefan Roesch
  2021-12-21 19:18       ` Linus Torvalds
  0 siblings, 1 reply; 11+ messages in thread
From: Stefan Roesch @ 2021-12-21 19:15 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: io-uring, linux-fsdevel, Kernel Team



On 12/21/21 9:22 AM, Linus Torvalds wrote:
> On Tue, Dec 21, 2021 at 8:50 AM Stefan Roesch <shr@fb.com> wrote:
>>
>> This splits off do_getxattr function from the getxattr
>> function. This will allow io_uring to call it from its
>> io worker.
> 
> Hmm.
> 
> My reaction to this one is
> 
>  "Why isn't do_getxattr() using 'struct xattr_ctx' for its context?"
> 
> As far as I can tell, that's *exactly* what it wants, and it would be
> logical to match up with the setxattr side.
> 
> Yeah, yeah, setxattr has a 'const void __user *value' while getxattr
> obviously has just a 'void __user *value'. But if the cost of having a
> unified interface is that you lose the 'const' part for the setxattr,
> I think that's still a good thing.
> 
> Yes? No? Comments?

Linus, if we remove the constness, then we either need to cast away the constness (the system call
is defined as const) or change the definition of the system call.


> 
>               Linus
> 

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v5 3/5] fs: split off do_getxattr from getxattr
  2021-12-21 19:15     ` Stefan Roesch
@ 2021-12-21 19:18       ` Linus Torvalds
  2021-12-21 21:59         ` Stefan Roesch
  0 siblings, 1 reply; 11+ messages in thread
From: Linus Torvalds @ 2021-12-21 19:18 UTC (permalink / raw)
  To: Stefan Roesch; +Cc: io-uring, linux-fsdevel, Kernel Team

On Tue, Dec 21, 2021 at 11:15 AM Stefan Roesch <shr@fb.com> wrote:
>
> Linus, if we remove the constness, then we either need to cast away the constness (the system call
> is defined as const) or change the definition of the system call.

You could also do it as

        union {
                const void __user *setxattr_value;
                void __user *getxattr_value;
        };

if you wanted to..

                 Linus

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v5 3/5] fs: split off do_getxattr from getxattr
  2021-12-21 19:18       ` Linus Torvalds
@ 2021-12-21 21:59         ` Stefan Roesch
  2021-12-21 22:57           ` Jens Axboe
  0 siblings, 1 reply; 11+ messages in thread
From: Stefan Roesch @ 2021-12-21 21:59 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: io-uring, linux-fsdevel, Kernel Team, Pavel Begunkov



On 12/21/21 11:18 AM, Linus Torvalds wrote:
> On Tue, Dec 21, 2021 at 11:15 AM Stefan Roesch <shr@fb.com> wrote:
>>
>> Linus, if we remove the constness, then we either need to cast away the constness (the system call
>> is defined as const) or change the definition of the system call.
> 
> You could also do it as
> 
>         union {
>                 const void __user *setxattr_value;
>                 void __user *getxattr_value;
>         };
>

Pavel brought up a very good point. By adding the kname array into the 
xarray_ctx we increase the size of io_xattr structure too much. In addition
this will also increase the size of the io_kiocb structure. The original
solution did not increase the size.

Per opcode we limit the storage space to 64 bytes. However the array itself
requires 256 bytes.
 
> if you wanted to..
> 
>                  Linus
> 

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v5 3/5] fs: split off do_getxattr from getxattr
  2021-12-21 21:59         ` Stefan Roesch
@ 2021-12-21 22:57           ` Jens Axboe
  0 siblings, 0 replies; 11+ messages in thread
From: Jens Axboe @ 2021-12-21 22:57 UTC (permalink / raw)
  To: Stefan Roesch, Linus Torvalds
  Cc: io-uring, linux-fsdevel, Kernel Team, Pavel Begunkov

On 12/21/21 2:59 PM, Stefan Roesch wrote:
> 
> 
> On 12/21/21 11:18 AM, Linus Torvalds wrote:
>> On Tue, Dec 21, 2021 at 11:15 AM Stefan Roesch <shr@fb.com> wrote:
>>>
>>> Linus, if we remove the constness, then we either need to cast away the constness (the system call
>>> is defined as const) or change the definition of the system call.
>>
>> You could also do it as
>>
>>         union {
>>                 const void __user *setxattr_value;
>>                 void __user *getxattr_value;
>>         };
>>
> 
> Pavel brought up a very good point. By adding the kname array into the
> xarray_ctx we increase the size of io_xattr structure too much. In
> addition this will also increase the size of the io_kiocb structure.
> The original solution did not increase the size.
> 
> Per opcode we limit the storage space to 64 bytes. However the array
> itself requires 256 bytes.

Just to expand on that a bit - part of struct io_kiocb is per-command
data, and we try pretty hard to keep that at 64-bytes as that's the
largest one we currently have. If we add the array to the io_xattr
structure, then that will increase the whole io_kiocb from 224 bytes to
more than twice that.

So there are really two options here:

1) The xattr_ctx structure goes into the async data that a command has
   to allocate for deferred execution. This isn't a _huge_ deal as we
   have to defer the xattr commands for now anyway, as the VFS doesn't
   support a nonblocking version of that yet. But it would still be nice
   not to have to do that.

2) We keep the original interface that Stefan proposed, leaving the
   xattr_ctx bits embedded as they fit fine like that.

#2 would be a bit more efficient, but I don't feel that strongly about
it for this particular case.

Comments?

-- 
Jens Axboe


^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2021-12-21 22:58 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-21 16:49 [PATCH v5 0/5] io_uring: add xattr support Stefan Roesch
2021-12-21 16:49 ` [PATCH v5 1/5] fs: split off do_user_path_at_empty from user_path_at_empty() Stefan Roesch
2021-12-21 16:49 ` [PATCH v5 2/5] fs: split off setxattr_setup function from setxattr Stefan Roesch
2021-12-21 16:49 ` [PATCH v5 3/5] fs: split off do_getxattr from getxattr Stefan Roesch
2021-12-21 17:22   ` Linus Torvalds
2021-12-21 19:15     ` Stefan Roesch
2021-12-21 19:18       ` Linus Torvalds
2021-12-21 21:59         ` Stefan Roesch
2021-12-21 22:57           ` Jens Axboe
2021-12-21 16:49 ` [PATCH v5 4/5] io_uring: add fsetxattr and setxattr support Stefan Roesch
2021-12-21 16:49 ` [PATCH v5 5/5] io_uring: add fgetxattr and getxattr support Stefan Roesch

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.