Skip to contentSkip to conversation

io_uring: add xattr support

PATCH Superseded Stefan Roesch 2 participants 6 messages Jan 5, 2022 – Jan 6, 2022

Subsystems (2)

v12 of 13 Superseded Latest is v13 →

lore
Share & tools
lore
#0 lore raw

v12 cover io_uring: add xattr support

This adds the xattr support to io_uring. The intent is to have a more complete support for file operations in io_uring.

This change adds support for the following functions to io_uring:
- fgetxattr
- fsetxattr
- getxattr
- setxattr

Patch 1: fs: split off setxattr_copy and do_setxattr function from setxattr
Split off the setup part of the setxattr function in the setxattr_copy function. Split off the processing part in do_setxattr.

Patch 2: fs: split off do_getxattr from getxattr
Split of the do_getxattr part from getxattr. This will allow it to be invoked it from io_uring.

Patch 3: io_uring: add fsetxattr and setxattr support
This adds new functions to support the fsetxattr and setxattr functions.

Patch 4: io_uring: add fgetxattr and getxattr support
This adds new functions to support the fgetxattr and getxattr functions.

There are two additional patches:
liburing: Add support for xattr api's.
This also includes the tests for the new code.
xfstests: Add support for io_uring xattr support.

V12: - add union to xattr_ctx structure. The getxattr api requires
a pointer to value and the setxattr requires a const pointer to value (with a union this can be unified).
- use xattr_ctx structure in do_getxattr call.
V11: - removed the do_user_path_at_empty function and directly
call filename_lookup
- introduce __io_xattr_finish and io_xattr_finish functions to unify the cleanup code
- remove the older __io_setxattr_finish function
V10: - move do_user_path_at_empty definition to fs/internal.h
- introduce __io_setxattr_finish function
- introduce __io_getxattr_finish function
V9 : - keep kvalue in struct xattr_ctx
V8 : - introduce xattr_name struct as advised by Linus
- remove kname_sz field in xattr_ctx
V7 : - split off setxattr in two functions as recommeneded by
Christian.
V6 : - reverted addition of kname array to xattr_ctx structure
Adding the kname array increases the io_kiocb beyond 64 bytes (increases it to 224 bytes). We try hard to limit it to 64 bytes. Keeping the original interface also is a bit more efficient.
- addressed Pavel's reordering comment
- addressed Pavel's putname comment
- addressed Pavel's kvfree comment
- rebased on for-5.17/io_uring-getdents64
V5 : - add kname array to xattr_ctx structure
V4 : - rebased patch series
V3 : - remove req->file checks in prep functions
- change size parameter in do_xattr
V2 : - split off function do_user_path_empty instead of changing
the function signature of user_path_at
- Fix datatype size problem in do_getxattr

Stefan Roesch (4):
fs: split off setxattr_copy and do_setxattr function from setxattr
fs: split off do_getxattr from getxattr
io_uring: add fsetxattr and setxattr support
io_uring: add fgetxattr and getxattr support

 fs/internal.h                 |  29 ++++
 fs/io_uring.c                 | 294 ++++++++++++++++++++++++++++++++++
 fs/xattr.c                    | 141 ++++++++++------
 include/uapi/linux/io_uring.h |   8 +-
 4 files changed, 426 insertions(+), 46 deletions(-)

base-commit: c0235652ee5194fc75926daa580817e63ceb37ab

Signature · 1 line
2.30.2
#1 lore raw

PATCH v12 1/4 fs: split off setxattr_copy and do_setxattr function from setxattr

This splits of the setup part of the function setxattr in its own dedicated function called setxattr_copy. In addition it also exposes a new function called do_setxattr for making the setxattr call.

This makes it possible to call these two functions from io_uring in the processing of an xattr request.

---
 fs/internal.h | 24 +++++++++++++++
 fs/xattr.c    | 82 ++++++++++++++++++++++++++++++++++++---------------
 2 files changed, 82 insertions(+), 24 deletions(-)
fs/internal.h +24 -0
index 7979ff8d168c..3aec2ef9fada 100644
@@ -194,3 +194,27 @@ long splice_file_to_pipe(struct file *in,
 			 struct pipe_inode_info *opipe,
 			 loff_t *offset,
 			 size_t len, unsigned int flags);
+
+/*
+ * fs/xattr.c:
+ */
+struct xattr_name {
+	char name[XATTR_NAME_MAX + 1];
+};
+
+struct xattr_ctx {
+	/* Value of attribute */
+	union {
+		const void __user *cvalue;
+		void __user *value;
+	};
+	void *kvalue;
+	size_t size;
+	/* Attribute name */
+	struct xattr_name *kname;
+	unsigned int flags;
+};
+
+int setxattr_copy(const char __user *name, struct xattr_ctx *ctx);
+int do_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
+		struct xattr_ctx *ctx);
fs/xattr.c +58 -24

107 lines not on this page · raw message

Signature · 1 line
2.30.2
#2 lore raw

PATCH v12 2/4 fs: split off do_getxattr from getxattr

In reply to Stefan Roesch

This splits off do_getxattr function from the getxattr function. This will allow io_uring to call it from its io worker.

---
 fs/internal.h |  5 +++++
 fs/xattr.c    | 59 +++++++++++++++++++++++++++++++++------------------
 2 files changed, 43 insertions(+), 21 deletions(-)
fs/internal.h +5 -0
index 3aec2ef9fada..c69abc68158d 100644
@@ -215,6 +215,11 @@ struct xattr_ctx {
 	unsigned int flags;
 };
 
+
+ssize_t do_getxattr(struct user_namespace *mnt_userns,
+		    struct dentry *d,
+		    struct xattr_ctx *ctx);
+
 int setxattr_copy(const char __user *name, struct xattr_ctx *ctx);
 int do_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
 		struct xattr_ctx *ctx);
fs/xattr.c +38 -21

81 lines not on this page · raw message

Signature · 1 line
2.30.2
#3 lore raw

PATCH v12 3/4 io_uring: add fsetxattr and setxattr support

In reply to Stefan Roesch

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

---
 fs/io_uring.c                 | 165 ++++++++++++++++++++++++++++++++++
 include/uapi/linux/io_uring.h |   6 +-
 2 files changed, 170 insertions(+), 1 deletion(-)
fs/io_uring.c +165 -0
index aed1625a26e1..a724e37410d7 100644
@@ -81,6 +81,7 @@
 #include <linux/tracehook.h>
 #include <linux/audit.h>
 #include <linux/security.h>
+#include <linux/xattr.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/io_uring.h>
@@ -716,6 +717,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,
@@ -855,6 +862,7 @@ struct io_kiocb {
 		struct io_mkdir		mkdir;
 		struct io_symlink	symlink;
 		struct io_hardlink	hardlink;
+		struct io_xattr		xattr;
 	};
 
 	u8				opcode;
@@ -1105,6 +1113,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() */
@@ -3844,6 +3856,144 @@ static int io_renameat(struct io_kiocb *req, unsigned int issue_flags)
 	return 0;
 }
 
+static inline void __io_xattr_finish(struct io_kiocb *req)
+{
+	struct io_xattr *ix = &req->xattr;
+
+	if (ix->filename)
+		putname(ix->filename);
+
+	kfree(ix->ctx.kname);
+	kvfree(ix->ctx.kvalue);
+}
+
+static void io_xattr_finish(struct io_kiocb *req, int ret)
+{
+	req->flags &= ~REQ_F_NEED_CLEANUP;
+
+	__io_xattr_finish(req);
+	if (ret < 0)
+		req_set_fail(req);
+
+	io_req_complete(req, ret);
+}
+
+static int __io_setxattr_prep(struct io_kiocb *req,
+			const struct io_uring_sqe *sqe)
+{
+	struct io_xattr *ix = &req->xattr;
+	const char __user *name;
+	int ret;
+
+	if (unlikely(req->ctx->flags & IORING_SETUP_IOPOLL))
+		return -EINVAL;
+	if (unlikely(sqe->ioprio))
+		return -EINVAL;
+	if (unlikely(req->flags & REQ_F_FIXED_FILE))
+		return -EBADF;
+
+	ix->filename = NULL;
+	name = u64_to_user_ptr(READ_ONCE(sqe->addr));
+	ix->ctx.cvalue = u64_to_user_ptr(READ_ONCE(sqe->addr2));
+	ix->ctx.kvalue = NULL;
+	ix->ctx.size = READ_ONCE(sqe->len);
+	ix->ctx.flags = READ_ONCE(sqe->xattr_flags);
+
+	ix->ctx.kname = kmalloc(sizeof(*ix->ctx.kname), GFP_KERNEL);
+	if (!ix->ctx.kname)
+		return -ENOMEM;
+
+	ret = setxattr_copy(name, &ix->ctx);
+	if (ret) {
+		kfree(ix->ctx.kname);
+		return ret;
+	}
+
+	req->flags |= REQ_F_NEED_CLEANUP;
+	return 0;
+}
+
+static int io_setxattr_prep(struct io_kiocb *req,
+			const struct io_uring_sqe *sqe)
+{
+	struct io_xattr *ix = &req->xattr;
+	const char __user *path;
+	int ret;
+
+	ret = __io_setxattr_prep(req, sqe);
+	if (ret)
+		return ret;
+
+	path = u64_to_user_ptr(READ_ONCE(sqe->addr3));
+
+	ix->filename = getname_flags(path, LOOKUP_FOLLOW, NULL);
+	if (IS_ERR(ix->filename)) {
+		ret = PTR_ERR(ix->filename);
+		ix->filename = NULL;
+	}
+
+	return ret;
+}
+
+static int io_fsetxattr_prep(struct io_kiocb *req,
+			const struct io_uring_sqe *sqe)
+{
+	return __io_setxattr_prep(req, sqe);
+}
+
+static int __io_setxattr(struct io_kiocb *req, unsigned int issue_flags,
+			struct path *path)
+{
+	struct io_xattr *ix = &req->xattr;
+	int ret;
+
+	ret = mnt_want_write(path->mnt);
+	if (!ret) {
+		ret = do_setxattr(mnt_user_ns(path->mnt), path->dentry, &ix->ctx);
+		mnt_drop_write(path->mnt);
+	}
+
+	return ret;
+}
+
+static int io_fsetxattr(struct io_kiocb *req, unsigned int issue_flags)
+{
+	int ret;
+
+	if (issue_flags & IO_URING_F_NONBLOCK)
+		return -EAGAIN;
+
+	ret = __io_setxattr(req, issue_flags, &req->file->f_path);
+	io_xattr_finish(req, ret);
+
+	return 0;
+}
+
+static int io_setxattr(struct io_kiocb *req, unsigned int issue_flags)
+{
+	struct io_xattr *ix = &req->xattr;
+	unsigned int lookup_flags = LOOKUP_FOLLOW;
+	struct path path;
+	int ret;
+
+	if (issue_flags & IO_URING_F_NONBLOCK)
+		return -EAGAIN;
+
+retry:
+	ret = filename_lookup(AT_FDCWD, ix->filename, lookup_flags, &path, NULL);
+	if (!ret) {
+		ret = __io_setxattr(req, issue_flags, &path);
+		path_put(&path);
+		if (retry_estale(ret, lookup_flags)) {
+			lookup_flags |= LOOKUP_REVAL;
+			goto retry;
+		}
+	}
+
+	io_xattr_finish(req, ret);
+	return 0;
+}
+
 static int io_unlinkat_prep(struct io_kiocb *req,
 			    const struct io_uring_sqe *sqe)
 {
@@ -6464,6 +6614,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",
@@ -6605,6 +6759,10 @@ static void io_clean_op(struct io_kiocb *req)
 			putname(req->hardlink.oldpath);
 			putname(req->hardlink.newpath);
 			break;
+		case IORING_OP_SETXATTR:
+		case IORING_OP_FSETXATTR:
+			__io_xattr_finish(req);
+			break;
 		}
 	}
 	if ((req->flags & REQ_F_POLLED) && req->apoll) {
@@ -6747,6 +6905,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;
@@ -11127,6 +11291,7 @@ static int __init io_uring_init(void)
 	BUILD_BUG_SQE_ELEM(42, __u16,  personality);
 	BUILD_BUG_SQE_ELEM(44, __s32,  splice_fd_in);
 	BUILD_BUG_SQE_ELEM(44, __u32,  file_index);
+	BUILD_BUG_SQE_ELEM(48, __u64,  addr3);
 
 	BUILD_BUG_ON(sizeof(struct io_uring_files_update) !=
 		     sizeof(struct io_uring_rsrc_update));
include/uapi/linux/io_uring.h +5 -1
index 787f491f0d2a..dbf473900da2 100644
@@ -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,
Signature · 1 line
2.30.2
#4 lore raw

PATCH v12 4/4 io_uring: add fgetxattr and getxattr support

In reply to Stefan Roesch

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

---
 fs/io_uring.c                 | 129 ++++++++++++++++++++++++++++++++++
 include/uapi/linux/io_uring.h |   2 +
 2 files changed, 131 insertions(+)
fs/io_uring.c +129 -0
index a724e37410d7..0bbd46a813b5 100644
@@ -1117,6 +1117,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() */
@@ -3878,6 +3882,119 @@ static void io_xattr_finish(struct io_kiocb *req, int ret)
 	io_req_complete(req, ret);
 }
 
+static int __io_getxattr_prep(struct io_kiocb *req,
+			      const struct io_uring_sqe *sqe)
+{
+	struct io_xattr *ix = &req->xattr;
+	const char __user *name;
+	int ret;
+
+	if (unlikely(req->ctx->flags & IORING_SETUP_IOPOLL))
+		return -EINVAL;
+	if (unlikely(sqe->ioprio))
+		return -EINVAL;
+	if (unlikely(req->flags & REQ_F_FIXED_FILE))
+		return -EBADF;
+
+	ix->filename = NULL;
+	ix->ctx.kvalue = NULL;
+	name = u64_to_user_ptr(READ_ONCE(sqe->addr));
+	ix->ctx.cvalue = u64_to_user_ptr(READ_ONCE(sqe->addr2));
+	ix->ctx.size = READ_ONCE(sqe->len);
+	ix->ctx.flags = READ_ONCE(sqe->xattr_flags);
+
+	if (ix->ctx.flags)
+		return -EINVAL;
+
+	ix->ctx.kname = kmalloc(sizeof(*ix->ctx.kname), GFP_KERNEL);
+	if (!ix->ctx.kname)
+		return -ENOMEM;
+
+	ret = strncpy_from_user(ix->ctx.kname->name, name,
+				sizeof(ix->ctx.kname->name));
+	if (!ret || ret == sizeof(ix->ctx.kname->name))
+		ret = -ERANGE;
+	if (ret < 0) {
+		kfree(ix->ctx.kname);
+		return ret;
+	}
+
+	req->flags |= REQ_F_NEED_CLEANUP;
+	return 0;
+}
+
+static int io_fgetxattr_prep(struct io_kiocb *req,
+			     const struct io_uring_sqe *sqe)
+{
+	return __io_getxattr_prep(req, sqe);
+}
+
+static int io_getxattr_prep(struct io_kiocb *req,
+			    const struct io_uring_sqe *sqe)
+{
+	struct io_xattr *ix = &req->xattr;
+	const char __user *path;
+	int ret;
+
+	ret = __io_getxattr_prep(req, sqe);
+	if (ret)
+		return ret;
+
+	path = u64_to_user_ptr(READ_ONCE(sqe->addr3));
+
+	ix->filename = getname_flags(path, LOOKUP_FOLLOW, NULL);
+	if (IS_ERR(ix->filename)) {
+		ret = PTR_ERR(ix->filename);
+		ix->filename = NULL;
+	}
+
+	return ret;
+}
+
+static int io_fgetxattr(struct io_kiocb *req, unsigned int issue_flags)
+{
+	struct io_xattr *ix = &req->xattr;
+	int ret;
+
+	if (issue_flags & IO_URING_F_NONBLOCK)
+		return -EAGAIN;
+
+	ret = do_getxattr(mnt_user_ns(req->file->f_path.mnt),
+			req->file->f_path.dentry,
+			&ix->ctx);
+
+	io_xattr_finish(req, ret);
+	return 0;
+}
+
+static int io_getxattr(struct io_kiocb *req, unsigned int issue_flags)
+{
+	struct io_xattr *ix = &req->xattr;
+	unsigned int lookup_flags = LOOKUP_FOLLOW;
+	struct path path;
+	int ret;
+
+	if (issue_flags & IO_URING_F_NONBLOCK)
+		return -EAGAIN;
+
+retry:
+	ret = filename_lookup(AT_FDCWD, ix->filename, lookup_flags, &path, NULL);
+	if (!ret) {
+		ret = do_getxattr(mnt_user_ns(path.mnt),
+				path.dentry,
+				&ix->ctx);
+
+		path_put(&path);
+		if (retry_estale(ret, lookup_flags)) {
+			lookup_flags |= LOOKUP_REVAL;
+			goto retry;
+		}
+	}
+
+	io_xattr_finish(req, ret);
+	return 0;
+}
+
 static int __io_setxattr_prep(struct io_kiocb *req,
 			const struct io_uring_sqe *sqe)
 {
@@ -6618,6 +6735,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",
@@ -6761,6 +6882,8 @@ static void io_clean_op(struct io_kiocb *req)
 			break;
 		case IORING_OP_SETXATTR:
 		case IORING_OP_FSETXATTR:
+		case IORING_OP_GETXATTR:
+		case IORING_OP_FGETXATTR:
 			__io_xattr_finish(req);
 			break;
 		}
@@ -6911,6 +7034,12 @@ static int io_issue_sqe(struct io_kiocb *req, unsigned int issue_flags)
 	case IORING_OP_SETXATTR:
 		ret = io_setxattr(req, issue_flags);
 		break;
+	case IORING_OP_FGETXATTR:
+		ret = io_fgetxattr(req, issue_flags);
+		break;
+	case IORING_OP_GETXATTR:
+		ret = io_getxattr(req, issue_flags);
+		break;
 	default:
 		ret = -EINVAL;
 		break;
include/uapi/linux/io_uring.h +2 -0
index dbf473900da2..9c6e617d3187 100644
@@ -147,6 +147,8 @@ enum {
 	IORING_OP_LINKAT,
 	IORING_OP_FSETXATTR,
 	IORING_OP_SETXATTR,
+	IORING_OP_FGETXATTR,
+	IORING_OP_GETXATTR,
 
 	/* this goes last, obviously */
 	IORING_OP_LAST,
Signature · 1 line
2.30.2
#5 lore raw
In reply to Stefan Roesch
Quoted 32 lines · Stefan Roesch

This adds the xattr support to io_uring. The intent is to have a more complete support for file operations in io_uring.

This change adds support for the following functions to io_uring:
- fgetxattr
- fsetxattr
- getxattr
- setxattr

Patch 1: fs: split off setxattr_copy and do_setxattr function from setxattr
Split off the setup part of the setxattr function in the setxattr_copy function. Split off the processing part in do_setxattr.

Patch 2: fs: split off do_getxattr from getxattr
Split of the do_getxattr part from getxattr. This will allow it to be invoked it from io_uring.

Patch 3: io_uring: add fsetxattr and setxattr support
This adds new functions to support the fsetxattr and setxattr functions.

Patch 4: io_uring: add fgetxattr and getxattr support
This adds new functions to support the fgetxattr and getxattr functions.

There are two additional patches:
liburing: Add support for xattr api's.
This also includes the tests for the new code.
xfstests: Add support for io_uring xattr support.

Quoted 3 lines

V12: - add union to xattr_ctx structure. The getxattr api requires
a pointer to value and the setxattr requires a const pointer to value (with a union this can be unified).

I'm fine with adding a union in there. I think it's also what Linus suggested in a previous mail. Al suggested a different allocation for the attribute name. Fwiw, I'm fine with either (struct kattr or dynamically allocating via an additional helper).

I've ran this through the generic vfs and idmapped mount xfstests I added last year. They do test core xattr functionality. I've applied your patchset on top of Jen's for-next. They pass:

ubuntu@f2-vm:~/src/git/xfstests$ sudo ./check -g idmapped
SECTION       -- xfs
RECREATING    -- xfs on /dev/loop4
FSTYP         -- xfs (debug)
PLATFORM      -- Linux/x86_64 f2-vm 5.16.0-rc3-fs-xattr-c62607c023ad #41 SMP PREEMPT Thu Jan 6 12:11:34 UTC 2022
MKFS_OPTIONS  -- -f -f /dev/loop5
MOUNT_OPTIONS -- /dev/loop5 /mnt/scratch

generic/633 26s ... 29s
generic/644 5s ... 19s
generic/645 413s ... 225s
generic/656 13s ... 21s
xfs/152 70s ... 75s
xfs/153 46s ... 48s
Ran: generic/633 generic/644 generic/645 generic/656 xfs/152 xfs/153 Passed all 6 tests

SECTION       -- ext4
RECREATING    -- ext4 on /dev/loop4
FSTYP         -- ext4
PLATFORM      -- Linux/x86_64 f2-vm 5.16.0-rc3-fs-xattr-c62607c023ad #41 SMP PREEMPT Thu Jan 6 12:11:34 UTC 2022
MKFS_OPTIONS  -- -F -F /dev/loop5

MOUNT_OPTIONS -- -o acl,user_xattr /dev/loop5 /mnt/scratch

generic/633 29s ... 20s
generic/644 19s ... 5s
generic/645 225s ... 208s
generic/656 21s ... 12s
Ran: generic/633 generic/644 generic/645 generic/656 Passed all 4 tests

SECTION       -- btrfs
RECREATING    -- btrfs on /dev/loop4
FSTYP         -- btrfs
PLATFORM      -- Linux/x86_64 f2-vm 5.16.0-rc3-fs-xattr-c62607c023ad #41 SMP PREEMPT Thu Jan 6 12:11:34 UTC 2022
MKFS_OPTIONS  -- -f /dev/loop5

MOUNT_OPTIONS -- /dev/loop5 /mnt/scratch

btrfs/245 10s ... 11s
generic/633 20s ... 25s
generic/644 5s ... 4s
generic/645 208s ... 209s
generic/656 12s ... 14s
Ran: btrfs/245 generic/633 generic/644 generic/645 generic/656 Passed all 5 tests

SECTION -- xfs
=========================
Ran: generic/633 generic/644 generic/645 generic/656 xfs/152 xfs/153 Passed all 6 tests

SECTION -- ext4
=========================
Ran: generic/633 generic/644 generic/645 generic/656 Passed all 4 tests

SECTION -- btrfs
=========================
Ran: btrfs/245 generic/633 generic/644 generic/645 generic/656 Passed all 5 tests