All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v7 0/5] io_uring: add xattr support
@ 2021-12-23 19:56 Stefan Roesch
  2021-12-23 19:56 ` [PATCH v7 1/5] fs: split off do_user_path_at_empty from user_path_at_empty() Stefan Roesch
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Stefan Roesch @ 2021-12-23 19:56 UTC (permalink / raw)
  To: io-uring, linux-fsdevel, kernel-team; +Cc: torvalds, christian.brauner, 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_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 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.


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 (5):
  fs: split off do_user_path_at_empty from user_path_at_empty()
  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                 |  25 +++
 fs/io_uring.c                 | 315 ++++++++++++++++++++++++++++++++++
 fs/namei.c                    |  10 +-
 fs/xattr.c                    | 119 +++++++++----
 include/linux/namei.h         |   2 +
 include/uapi/linux/io_uring.h |   8 +-
 6 files changed, 442 insertions(+), 37 deletions(-)


base-commit: b4518682080d3a1cdd6ea45a54ff6772b8b2797a
-- 
2.30.2


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

* [PATCH v7 1/5] fs: split off do_user_path_at_empty from user_path_at_empty()
  2021-12-23 19:56 [PATCH v7 0/5] io_uring: add xattr support Stefan Roesch
@ 2021-12-23 19:56 ` Stefan Roesch
  2021-12-23 19:56 ` [PATCH v7 2/5] fs: split off setxattr_copy and do_setxattr function from setxattr Stefan Roesch
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Stefan Roesch @ 2021-12-23 19:56 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 <shr@fb.com>
Acked-by: Christian Brauner <christian.brauner@ubuntu.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] 8+ messages in thread

* [PATCH v7 2/5] fs: split off setxattr_copy and do_setxattr function from setxattr
  2021-12-23 19:56 [PATCH v7 0/5] io_uring: add xattr support Stefan Roesch
  2021-12-23 19:56 ` [PATCH v7 1/5] fs: split off do_user_path_at_empty from user_path_at_empty() Stefan Roesch
@ 2021-12-23 19:56 ` Stefan Roesch
  2021-12-23 20:11   ` Linus Torvalds
  2021-12-23 19:56 ` [PATCH v7 3/5] fs: split off do_getxattr from getxattr Stefan Roesch
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 8+ messages in thread
From: Stefan Roesch @ 2021-12-23 19:56 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 <shr@fb.com>
---
 fs/internal.h | 19 +++++++++++
 fs/xattr.c    | 87 ++++++++++++++++++++++++++++++++++++++-------------
 2 files changed, 84 insertions(+), 22 deletions(-)

diff --git a/fs/internal.h b/fs/internal.h
index 432ea3ce76ec..28b9f947f26e 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -202,3 +202,22 @@ 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_ctx {
+	/* Value of attribute */
+	const void __user *value;
+	size_t size;
+	/* Attribute name */
+	char *kname;
+	int kname_sz;
+	unsigned int flags;
+};
+
+
+int setxattr_copy(const char __user *name, struct xattr_ctx *ctx,
+		void **xattr_val);
+int do_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
+		struct xattr_ctx *ctx, void *xattr_val);
diff --git a/fs/xattr.c b/fs/xattr.c
index 5c8c5175b385..fbe6c2b7ec47 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,84 @@ 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,
+		void **xattr_val)
 {
-	int error;
 	void *kvalue = NULL;
-	char kname[XATTR_NAME_MAX + 1];
+	int error;
 
-	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, ctx->kname_sz);
+	if (error == 0 || error == ctx->kname_sz)
+		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);
+
+		kvalue = kvmalloc(ctx->size, GFP_KERNEL);
 		if (!kvalue)
 			return -ENOMEM;
-		if (copy_from_user(kvalue, value, size)) {
-			error = -EFAULT;
-			goto out;
+
+		if (copy_from_user(kvalue, ctx->value, ctx->size)) {
+			kvfree(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);
+	*xattr_val = kvalue;
+	return 0;
+}
+
+static void setxattr_convert(struct user_namespace *mnt_userns,
+			struct xattr_ctx *ctx, void *xattr_value)
+{
+	if (ctx->size &&
+		((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, xattr_value, ctx->size);
+}
+
+int do_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
+		struct xattr_ctx *ctx, void *xattr_value)
+{
+	int error;
+
+	setxattr_convert(mnt_userns, ctx, xattr_value);
+	error = vfs_setxattr(mnt_userns, dentry, ctx->kname,
+			xattr_value, ctx->size, ctx->flags);
+
+	return error;
+}
+
+static long
+setxattr(struct user_namespace *mnt_userns, struct dentry *d,
+	const char __user *name, const void __user *value, size_t size,
+	int flags)
+{
+	char kname[XATTR_NAME_MAX + 1];
+	struct xattr_ctx ctx = {
+		.value    = value,
+		.size     = size,
+		.kname    = kname,
+		.kname_sz = sizeof(kname),
+		.flags    = flags,
+	};
+	void *xattr_value = NULL;
+	int error;
+
+	error = setxattr_copy(name, &ctx, &xattr_value);
+	if (error)
+		return error;
+
+	error = do_setxattr(mnt_userns, d, &ctx, xattr_value);
 
+	kvfree(xattr_value);
 	return error;
 }
 
-- 
2.30.2


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

* [PATCH v7 3/5] fs: split off do_getxattr from getxattr
  2021-12-23 19:56 [PATCH v7 0/5] io_uring: add xattr support Stefan Roesch
  2021-12-23 19:56 ` [PATCH v7 1/5] fs: split off do_user_path_at_empty from user_path_at_empty() Stefan Roesch
  2021-12-23 19:56 ` [PATCH v7 2/5] fs: split off setxattr_copy and do_setxattr function from setxattr Stefan Roesch
@ 2021-12-23 19:56 ` Stefan Roesch
  2021-12-23 19:56 ` [PATCH v7 4/5] io_uring: add fsetxattr and setxattr support Stefan Roesch
  2021-12-23 19:56 ` [PATCH v7 5/5] io_uring: add fgetxattr and getxattr support Stefan Roesch
  4 siblings, 0 replies; 8+ messages in thread
From: Stefan Roesch @ 2021-12-23 19:56 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 <shr@fb.com>
Acked-by: Christian Brauner <christian.brauner@ubuntu.com>
---
 fs/internal.h |  6 ++++++
 fs/xattr.c    | 32 ++++++++++++++++++++------------
 2 files changed, 26 insertions(+), 12 deletions(-)

diff --git a/fs/internal.h b/fs/internal.h
index 28b9f947f26e..d33e7a63a9c0 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -217,6 +217,12 @@ struct xattr_ctx {
 };
 
 
+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,
 		void **xattr_val);
 int do_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
diff --git a/fs/xattr.c b/fs/xattr.c
index fbe6c2b7ec47..cd36eeebf0c0 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -684,19 +684,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)
@@ -720,10 +713,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;
+	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] 8+ messages in thread

* [PATCH v7 4/5] io_uring: add fsetxattr and setxattr support
  2021-12-23 19:56 [PATCH v7 0/5] io_uring: add xattr support Stefan Roesch
                   ` (2 preceding siblings ...)
  2021-12-23 19:56 ` [PATCH v7 3/5] fs: split off do_getxattr from getxattr Stefan Roesch
@ 2021-12-23 19:56 ` Stefan Roesch
  2021-12-23 19:56 ` [PATCH v7 5/5] io_uring: add fgetxattr and getxattr support Stefan Roesch
  4 siblings, 0 replies; 8+ messages in thread
From: Stefan Roesch @ 2021-12-23 19:56 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 <shr@fb.com>
---
 fs/io_uring.c                 | 167 ++++++++++++++++++++++++++++++++++
 include/uapi/linux/io_uring.h |   6 +-
 2 files changed, 172 insertions(+), 1 deletion(-)

diff --git a/fs/io_uring.c b/fs/io_uring.c
index c8258c784116..d26afce61321 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,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,
@@ -866,6 +874,7 @@ struct io_kiocb {
 		struct io_symlink	symlink;
 		struct io_hardlink	hardlink;
 		struct io_getdents	getdents;
+		struct io_xattr		xattr;
 	};
 
 	u8				opcode;
@@ -1118,6 +1127,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 +3900,141 @@ 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.size = READ_ONCE(sqe->len);
+	ix->ctx.flags = READ_ONCE(sqe->xattr_flags);
+
+	ix->ctx.kname = kmalloc(XATTR_NAME_MAX + 1, GFP_KERNEL);
+	if (!ix->ctx.kname)
+		return -ENOMEM;
+	ix->ctx.kname_sz = XATTR_NAME_MAX + 1;
+
+	ret = setxattr_copy(name, &ix->ctx, &ix->value);
+	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, ix->value);
+		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->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);
+	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->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)
 {
@@ -6623,6 +6771,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 +6916,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.value);
+			break;
 		}
 	}
 	if ((req->flags & REQ_F_POLLED) && req->apoll) {
@@ -6909,6 +7069,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 +11443,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] 8+ messages in thread

* [PATCH v7 5/5] io_uring: add fgetxattr and getxattr support
  2021-12-23 19:56 [PATCH v7 0/5] io_uring: add xattr support Stefan Roesch
                   ` (3 preceding siblings ...)
  2021-12-23 19:56 ` [PATCH v7 4/5] io_uring: add fsetxattr and setxattr support Stefan Roesch
@ 2021-12-23 19:56 ` Stefan Roesch
  4 siblings, 0 replies; 8+ messages in thread
From: Stefan Roesch @ 2021-12-23 19:56 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 <shr@fb.com>
---
 fs/io_uring.c                 | 148 ++++++++++++++++++++++++++++++++++
 include/uapi/linux/io_uring.h |   2 +
 2 files changed, 150 insertions(+)

diff --git a/fs/io_uring.c b/fs/io_uring.c
index d26afce61321..cd7b5b0742fd 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -1131,6 +1131,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() */
@@ -3900,6 +3904,133 @@ 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;
+
+	ix->ctx.kname = kmalloc(XATTR_NAME_MAX + 1, GFP_KERNEL);
+	if (!ix->ctx.kname)
+		return -ENOMEM;
+
+	ret = strncpy_from_user(ix->ctx.kname, name, XATTR_NAME_MAX + 1);
+	if (!ret || ret == XATTR_NAME_MAX + 1)
+		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,
+			(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,
+				(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)
 {
@@ -6775,6 +6906,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",
@@ -6924,6 +7059,13 @@ static void io_clean_op(struct io_kiocb *req)
 			kfree(req->xattr.ctx.kname);
 			kvfree(req->xattr.value);
 			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) {
@@ -7075,6 +7217,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] 8+ messages in thread

* Re: [PATCH v7 2/5] fs: split off setxattr_copy and do_setxattr function from setxattr
  2021-12-23 19:56 ` [PATCH v7 2/5] fs: split off setxattr_copy and do_setxattr function from setxattr Stefan Roesch
@ 2021-12-23 20:11   ` Linus Torvalds
  2021-12-23 23:54     ` Stefan Roesch
  0 siblings, 1 reply; 8+ messages in thread
From: Linus Torvalds @ 2021-12-23 20:11 UTC (permalink / raw)
  To: Stefan Roesch; +Cc: io-uring, linux-fsdevel, Kernel Team, Christian Brauner

On Thu, Dec 23, 2021 at 11:57 AM Stefan Roesch <shr@fb.com> wrote:
>
> +       /* Attribute name */
> +       char *kname;
> +       int kname_sz;

I still don't like this.

Clearly the "just embed the kname in the context" didn't work, but I
hate how this adds that "pointer and size", when the size really
should be part of the type.

The patch takes what used to be a fixed size, and turns it into
something we pass along as an argument - for no actual good reason.
The 'size' isn't even the size of the name, it's literally the size of
the allocation that has a fixed definition.

Can we perhaps do it another way, by just encoding the size in the
type itself - but keeping it as a pointer.

We have a fixed size for attribute names, so maybe we can do

        struct xattr_name {
                char name[XATTR_NAME_MAX + 1];
        };

and actually use that.

Because I don't see that kname_sz is ever validly anything else, and
ever has any actual value to be passed around?

Maybe some day we'd actually make that "xattr_name" structure also
have the actual length of the name in it, but that would still *not*
be the size of the allocation.

I think it's actively misleading to have "kname_sz' that isn't
actually the size of the name, but I also think it's stupid to have a
variable for what is a constant value.

             Linus

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

* Re: [PATCH v7 2/5] fs: split off setxattr_copy and do_setxattr function from setxattr
  2021-12-23 20:11   ` Linus Torvalds
@ 2021-12-23 23:54     ` Stefan Roesch
  0 siblings, 0 replies; 8+ messages in thread
From: Stefan Roesch @ 2021-12-23 23:54 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: io-uring, linux-fsdevel, Kernel Team, Christian Brauner



On 12/23/21 12:11 PM, Linus Torvalds wrote:
> On Thu, Dec 23, 2021 at 11:57 AM Stefan Roesch <shr@fb.com> wrote:
>>
>> +       /* Attribute name */
>> +       char *kname;
>> +       int kname_sz;
> 
> I still don't like this.
> 
> Clearly the "just embed the kname in the context" didn't work, but I
> hate how this adds that "pointer and size", when the size really
> should be part of the type.
> 
> The patch takes what used to be a fixed size, and turns it into
> something we pass along as an argument - for no actual good reason.
> The 'size' isn't even the size of the name, it's literally the size of
> the allocation that has a fixed definition.
> 
> Can we perhaps do it another way, by just encoding the size in the
> type itself - but keeping it as a pointer.
> 
> We have a fixed size for attribute names, so maybe we can do
> 
>         struct xattr_name {
>                 char name[XATTR_NAME_MAX + 1];
>         };
> 
> and actually use that.
> 
> Because I don't see that kname_sz is ever validly anything else, and
> ever has any actual value to be passed around?
> 
> Maybe some day we'd actually make that "xattr_name" structure also
> have the actual length of the name in it, but that would still *not*
> be the size of the allocation.
> 
> I think it's actively misleading to have "kname_sz' that isn't
> actually the size of the name, but I also think it's stupid to have a
> variable for what is a constant value.
> 
>              Linus
> 

Linus, I added the xattr_name struct and removed the kname_sz field from
the xattr_ctx struct. In addition the xattr_name struct is used in xattr.c
and io_uring.c.


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

end of thread, other threads:[~2021-12-23 23:54 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-23 19:56 [PATCH v7 0/5] io_uring: add xattr support Stefan Roesch
2021-12-23 19:56 ` [PATCH v7 1/5] fs: split off do_user_path_at_empty from user_path_at_empty() Stefan Roesch
2021-12-23 19:56 ` [PATCH v7 2/5] fs: split off setxattr_copy and do_setxattr function from setxattr Stefan Roesch
2021-12-23 20:11   ` Linus Torvalds
2021-12-23 23:54     ` Stefan Roesch
2021-12-23 19:56 ` [PATCH v7 3/5] fs: split off do_getxattr from getxattr Stefan Roesch
2021-12-23 19:56 ` [PATCH v7 4/5] io_uring: add fsetxattr and setxattr support Stefan Roesch
2021-12-23 19:56 ` [PATCH v7 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.