fstests.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] fsstress: add support for btrfs subvol and snapshot ops
@ 2019-11-14 15:58 Josef Bacik
  2019-11-14 15:58 ` [PATCH 1/3] fsstress: add the ability to create/delete subvolumes Josef Bacik
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Josef Bacik @ 2019-11-14 15:58 UTC (permalink / raw)
  To: fstests, kernel-team, linux-btrfs

For btrfs it would be nice to exercise our subvol and snapshot operations with
fsstress as well.  The set of patches adds this ability.  I've added a new file
type for subvolumes, and they behave just like directories for all intents and
purposes.  The bulk of the supporting code needed for this went into the first
patch, as well as the code to add the ability to link in libbtrfsutil.  The
second patch is more straightforward as it just adds the snapshot operation, and
the final patch goes through and makes everybody pick either a directory or
subvolume for their target file.  I've done a bunch of testing with this on
btrfs to make sure everything works as expected.  I then did a follow up run on
xfs to verify I didn't break the non-btrfs case.  Thanks,

Josef


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

* [PATCH 1/3] fsstress: add the ability to create/delete subvolumes
  2019-11-14 15:58 [PATCH 0/3] fsstress: add support for btrfs subvol and snapshot ops Josef Bacik
@ 2019-11-14 15:58 ` Josef Bacik
  2019-11-14 18:14   ` [PATCH][v2] " Josef Bacik
  2019-11-14 15:58 ` [PATCH 2/3] fsstress: add the ability to create snapshots Josef Bacik
  2019-11-14 15:58 ` [PATCH 3/3] fsstress: allow operations to use either a directory or subvol Josef Bacik
  2 siblings, 1 reply; 8+ messages in thread
From: Josef Bacik @ 2019-11-14 15:58 UTC (permalink / raw)
  To: fstests, kernel-team, linux-btrfs

This patch adds support to fsstress for creating and deleting subvolumes
on a btrfs file system.  We link in the libbtrfsutil library to handle
the mechanics of creating and deleting subvolumes instead of duplicating
the ioctl logic.  There is code to check if we're on a btrfs fs at
startup time and if so 0 out the frequency of the btrfs specific
operations.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
 configure.ac           |   1 +
 include/builddefs.in   |   1 +
 ltp/Makefile           |   4 +
 ltp/fsstress.c         | 228 ++++++++++++++++++++++++++++++++++-------
 m4/package_libbtrfs.m4 |   5 +
 5 files changed, 204 insertions(+), 35 deletions(-)
 create mode 100644 m4/package_libbtrfs.m4

diff --git a/configure.ac b/configure.ac
index 19798824..4bb50b32 100644
--- a/configure.ac
+++ b/configure.ac
@@ -67,6 +67,7 @@ AC_PACKAGE_WANT_FALLOCATE
 AC_PACKAGE_WANT_OPEN_BY_HANDLE_AT
 AC_PACKAGE_WANT_LINUX_PRCTL_H
 AC_PACKAGE_WANT_LINUX_FS_H
+AC_PACKAGE_WANT_LIBBTRFSUTIL
 
 AC_HAVE_COPY_FILE_RANGE
 
diff --git a/include/builddefs.in b/include/builddefs.in
index 2605e42d..e7894b1a 100644
--- a/include/builddefs.in
+++ b/include/builddefs.in
@@ -68,6 +68,7 @@ HAVE_ATTR_LIST = @have_attr_list@
 HAVE_FIEMAP = @have_fiemap@
 HAVE_FALLOCATE = @have_fallocate@
 HAVE_COPY_FILE_RANGE = @have_copy_file_range@
+HAVE_LIBBTRFSUTIL = @have_libbtrfsutil@
 
 GCCFLAGS = -funsigned-char -fno-strict-aliasing -Wall
 
diff --git a/ltp/Makefile b/ltp/Makefile
index e4ca45f4..ebf40336 100644
--- a/ltp/Makefile
+++ b/ltp/Makefile
@@ -24,6 +24,10 @@ LCFLAGS += -DAIO
 LLDLIBS += -laio -lpthread
 endif
 
+ifeq ($(HAVE_LIBBTRFSUTIL), true)
+LLDLIBS += -lbtrfsutil
+endif
+
 ifeq ($(HAVE_FALLOCATE), true)
 LCFLAGS += -DFALLOCATE
 endif
diff --git a/ltp/fsstress.c b/ltp/fsstress.c
index 9f5ec1d0..e0636a12 100644
--- a/ltp/fsstress.c
+++ b/ltp/fsstress.c
@@ -53,6 +53,10 @@ io_context_t	io_ctx;
 #define SYS_renameat2 353
 #endif
 
+#ifdef HAVE_BTRFSUTIL_H
+#include <btrfsutil.h>
+#endif
+
 static int renameat2(int dfd1, const char *path1,
 		     int dfd2, const char *path2,
 		     unsigned int flags)
@@ -127,6 +131,8 @@ typedef enum {
 	OP_SETXATTR,
 	OP_SPLICE,
 	OP_STAT,
+	OP_SUBVOL_CREATE,
+	OP_SUBVOL_DELETE,
 	OP_SYMLINK,
 	OP_SYNC,
 	OP_TRUNCATE,
@@ -149,6 +155,7 @@ typedef struct opdesc {
 
 typedef struct fent {
 	int	id;
+	int	ft;
 	int	parent;
 	int	xattr_counter;
 } fent_t;
@@ -176,20 +183,22 @@ struct print_string {
 	int max;
 };
 
-#define	FT_DIR	0
-#define	FT_DIRm	(1 << FT_DIR)
-#define	FT_REG	1
-#define	FT_REGm	(1 << FT_REG)
-#define	FT_SYM	2
-#define	FT_SYMm	(1 << FT_SYM)
-#define	FT_DEV	3
-#define	FT_DEVm	(1 << FT_DEV)
-#define	FT_RTF	4
-#define	FT_RTFm	(1 << FT_RTF)
-#define	FT_nft	5
-#define	FT_ANYm	((1 << FT_nft) - 1)
+#define	FT_DIR		0
+#define	FT_DIRm		(1 << FT_DIR)
+#define	FT_REG		1
+#define	FT_REGm		(1 << FT_REG)
+#define	FT_SYM		2
+#define	FT_SYMm		(1 << FT_SYM)
+#define	FT_DEV		3
+#define	FT_DEVm		(1 << FT_DEV)
+#define	FT_RTF		4
+#define	FT_RTFm		(1 << FT_RTF)
+#define	FT_SUBVOL	5
+#define	FT_SUBVOLm	(1 << FT_SUBVOL)
+#define	FT_nft		6
+#define	FT_ANYm		((1 << FT_nft) - 1)
 #define	FT_REGFILE	(FT_REGm | FT_RTFm)
-#define	FT_NOTDIR	(FT_ANYm & ~FT_DIRm)
+#define	FT_NOTDIR	(FT_ANYm & (~FT_DIRm & ~FT_SUBVOLm))
 
 #define	FLIST_SLOT_INCR	16
 #define	NDCACHE	64
@@ -248,6 +257,8 @@ void	setfattr_f(int, long);
 void	setxattr_f(int, long);
 void	splice_f(int, long);
 void	stat_f(int, long);
+void	subvol_create_f(int, long);
+void	subvol_delete_f(int, long);
 void	symlink_f(int, long);
 void	sync_f(int, long);
 void	truncate_f(int, long);
@@ -313,6 +324,8 @@ opdesc_t	ops[] = {
 	{ OP_SETXATTR, "setxattr", setxattr_f, 1, 1 },
 	{ OP_SPLICE, "splice", splice_f, 1, 1 },
 	{ OP_STAT, "stat", stat_f, 1, 0 },
+	{ OP_SUBVOL_CREATE, "subvol_create", subvol_create_f, 1, 1},
+	{ OP_SUBVOL_DELETE, "subvol_delete", subvol_delete_f, 1, 1},
 	{ OP_SYMLINK, "symlink", symlink_f, 2, 1 },
 	{ OP_SYNC, "sync", sync_f, 1, 1 },
 	{ OP_TRUNCATE, "truncate", truncate_f, 2, 1 },
@@ -328,6 +341,7 @@ flist_t	flist[FT_nft] = {
 	{ 0, 0, 'l', NULL },
 	{ 0, 0, 'c', NULL },
 	{ 0, 0, 'r', NULL },
+	{ 0, 0, 's', NULL },
 };
 
 int		dcache[NDCACHE];
@@ -372,11 +386,11 @@ int	creat_path(pathname_t *, mode_t);
 void	dcache_enter(int, int);
 void	dcache_init(void);
 fent_t	*dcache_lookup(int);
-void	dcache_purge(int);
+void	dcache_purge(int, int);
 void	del_from_flist(int, int);
 int	dirid_to_name(char *, int);
 void	doproc(void);
-int	fent_to_name(pathname_t *, flist_t *, fent_t *);
+int	fent_to_name(pathname_t *, fent_t *);
 bool	fents_ancestor_check(fent_t *, fent_t *);
 void	fix_parent(int, int, bool);
 void	free_pathname(pathname_t *);
@@ -407,6 +421,7 @@ int	unlink_path(pathname_t *);
 void	usage(void);
 void	write_freq(void);
 void	zero_freq(void);
+void	non_btrfs_freq(const char *);
 
 void sg_handler(int signum)
 {
@@ -560,6 +575,7 @@ int main(int argc, char **argv)
             exit(1);
         }
 
+	non_btrfs_freq(dirname);
 	(void)mkdir(dirname, 0777);
 	if (logname && logname[0] != '/') {
 		if (!getcwd(rpath, sizeof(rpath))){
@@ -795,6 +811,7 @@ add_to_flist(int ft, int id, int parent, int xattr_counter)
 	}
 	fep = &ftp->fents[ftp->nfiles++];
 	fep->id = id;
+	fep->ft = ft;
 	fep->parent = parent;
 	fep->xattr_counter = xattr_counter;
 }
@@ -962,18 +979,22 @@ dcache_lookup(int dirid)
 	int	i;
 
 	i = dcache[dirid % NDCACHE];
-	if (i >= 0 && (fep = &flist[FT_DIR].fents[i])->id == dirid)
+	if (i >= 0 && i < flist[FT_DIR].nfiles &&
+	    (fep = &flist[FT_DIR].fents[i])->id == dirid)
+		return fep;
+	if (i >= 0 && i < flist[FT_SUBVOL].nfiles &&
+	    (fep = &flist[FT_SUBVOL].fents[i])->id == dirid)
 		return fep;
 	return NULL;
 }
 
 void
-dcache_purge(int dirid)
+dcache_purge(int dirid, int ft)
 {
 	int	*dcp;
-
 	dcp = &dcache[dirid % NDCACHE];
-	if (*dcp >= 0 && flist[FT_DIR].fents[*dcp].id == dirid)
+	if (*dcp >= 0 && *dcp < flist[ft].nfiles &&
+	    flist[ft].fents[*dcp].id == dirid)
 		*dcp = -1;
 }
 
@@ -989,32 +1010,58 @@ del_from_flist(int ft, int slot)
 	flist_t	*ftp;
 
 	ftp = &flist[ft];
-	if (ft == FT_DIR)
-		dcache_purge(ftp->fents[slot].id);
+	if (ft == FT_DIR || ft == FT_SUBVOL)
+		dcache_purge(ftp->fents[slot].id, ft);
 	if (slot != ftp->nfiles - 1) {
-		if (ft == FT_DIR)
-			dcache_purge(ftp->fents[ftp->nfiles - 1].id);
+		if (ft == FT_DIR || ft == FT_SUBVOL)
+			dcache_purge(ftp->fents[ftp->nfiles - 1].id, ft);
 		ftp->fents[slot] = ftp->fents[--ftp->nfiles];
 	} else
 		ftp->nfiles--;
 }
 
+void
+delete_subvol_children(int parid)
+{
+	flist_t	*flp;
+	int	i;
+again:
+	for (i = 0, flp = flist; i < FT_nft; i++, flp++) {
+		int c;
+		for (c = 0; c < flp->nfiles; c++) {
+			if (flp->fents[c].parent == parid) {
+				int id = flp->fents[c].id;
+				del_from_flist(i, c);
+				if (i == FT_DIR || i == FT_SUBVOL)
+					delete_subvol_children(id);
+				goto again;
+			}
+		}
+	}
+}
+
 fent_t *
 dirid_to_fent(int dirid)
 {
 	fent_t	*efep;
 	fent_t	*fep;
 	flist_t	*flp;
+	int	ft = FT_DIR;
 
 	if ((fep = dcache_lookup(dirid)))
 		return fep;
-	flp = &flist[FT_DIR];
+again:
+	flp = &flist[ft];
 	for (fep = flp->fents, efep = &fep[flp->nfiles]; fep < efep; fep++) {
 		if (fep->id == dirid) {
 			dcache_enter(dirid, fep - flp->fents);
 			return fep;
 		}
 	}
+	if (ft == FT_DIR) {
+		ft = FT_SUBVOL;
+		goto again;
+	}
 	return NULL;
 }
 
@@ -1091,8 +1138,9 @@ errout:
  * Return 0 on error, 1 on success;
  */
 int
-fent_to_name(pathname_t *name, flist_t *flp, fent_t *fep)
+fent_to_name(pathname_t *name, fent_t *fep)
 {
+	flist_t	*flp = &flist[fep->ft];
 	char	buf[NAME_MAX + 1];
 	int	i;
 	fent_t	*pfep;
@@ -1112,7 +1160,7 @@ fent_to_name(pathname_t *name, flist_t *flp, fent_t *fep)
 #endif
 		if (pfep == NULL)
 			return 0;
-		e = fent_to_name(name, &flist[FT_DIR], pfep);
+		e = fent_to_name(name, pfep);
 		if (!e)
 			return 0;
 		append_pathname(name, "/");
@@ -1188,7 +1236,7 @@ generate_fname(fent_t *fep, int ft, pathname_t *name, int *idp, int *v)
 
 	/* prepend fep parent dir-name to it */
 	if (fep) {
-		e = fent_to_name(name, &flist[FT_DIR], fep);
+		e = fent_to_name(name, fep);
 		if (!e)
 			return 0;
 		append_pathname(name, "/");
@@ -1270,7 +1318,7 @@ get_fname(int which, long r, pathname_t *name, flist_t **flpp, fent_t **fepp,
 
 				/* fill-in what we were asked for */
 				if (name) {
-					e = fent_to_name(name, flp, fep);
+					e = fent_to_name(name, fep);
 #ifdef DEBUG
 					if (!e) {
 						fprintf(stderr, "%d: failed to get path for entry:"
@@ -1852,6 +1900,35 @@ zero_freq(void)
 		p->freq = 0;
 }
 
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+opty_t btrfs_ops[] = {
+	OP_SUBVOL_CREATE,
+	OP_SUBVOL_DELETE,
+};
+
+void
+non_btrfs_freq(const char *path)
+{
+	opdesc_t		*p;
+#ifdef HAVE_BTRFSUTIL_H
+	enum btrfs_util_error	e;
+
+	e = btrfs_util_is_subvolume(path);
+	if (e != BTRFS_UTIL_ERROR_NOT_BTRFS)
+		return;
+#endif
+	for (p = ops; p < ops_end; p++) {
+		int i;
+		for (i = 0; i < ARRAY_SIZE(btrfs_ops); i++) {
+			if (p->op == btrfs_ops[i]) {
+				p->freq = 0;
+				break;
+			}
+		}
+	}
+}
+
 void inode_info(char *str, size_t sz, struct stat64 *s, int verbose)
 {
 	if (verbose)
@@ -3103,7 +3180,7 @@ creat_f(int opno, long r)
 	v |= v1;
 	if (!e) {
 		if (v) {
-			(void)fent_to_name(&f, &flist[FT_DIR], fep);
+			(void)fent_to_name(&f, fep);
 			printf("%d/%d: creat - no filename from %s\n",
 				procid, opno, f.path);
 		}
@@ -3767,7 +3844,7 @@ link_f(int opno, long r)
 	v |= v1;
 	if (!e) {
 		if (v) {
-			(void)fent_to_name(&l, &flist[FT_DIR], fep);
+			(void)fent_to_name(&l, fep);
 			printf("%d/%d: link - no filename from %s\n",
 				procid, opno, l.path);
 		}
@@ -3858,7 +3935,7 @@ mkdir_f(int opno, long r)
 	v |= v1;
 	if (!e) {
 		if (v) {
-			(void)fent_to_name(&f, &flist[FT_DIR], fep);
+			(void)fent_to_name(&f, fep);
 			printf("%d/%d: mkdir - no filename from %s\n",
 				procid, opno, f.path);
 		}
@@ -3896,7 +3973,7 @@ mknod_f(int opno, long r)
 	v |= v1;
 	if (!e) {
 		if (v) {
-			(void)fent_to_name(&f, &flist[FT_DIR], fep);
+			(void)fent_to_name(&f, fep);
 			printf("%d/%d: mknod - no filename from %s\n",
 				procid, opno, f.path);
 		}
@@ -4364,7 +4441,7 @@ do_renameat2(int opno, long r, int mode)
 		v |= v1;
 		if (!e) {
 			if (v) {
-				(void)fent_to_name(&f, &flist[FT_DIR], dfep);
+				(void)fent_to_name(&f, dfep);
 				printf("%d/%d: rename - no filename from %s\n",
 					procid, opno, f.path);
 			}
@@ -4378,6 +4455,7 @@ do_renameat2(int opno, long r, int mode)
 	if (e == 0) {
 		int xattr_counter = fep->xattr_counter;
 		bool swap = (mode == RENAME_EXCHANGE) ? true : false;
+		int ft = flp - flist;
 
 		oldid = fep->id;
 		oldparid = fep->parent;
@@ -4386,7 +4464,7 @@ do_renameat2(int opno, long r, int mode)
 		 * Swap the parent ids for RENAME_EXCHANGE, and replace the
 		 * old parent id for the others.
 		 */
-		if (flp - flist == FT_DIR)
+		if (ft == FT_DIR || ft == FT_SUBVOL)
 			fix_parent(oldid, id, swap);
 
 		if (mode == RENAME_WHITEOUT) {
@@ -4647,6 +4725,86 @@ stat_f(int opno, long r)
 	free_pathname(&f);
 }
 
+void
+subvol_create_f(int opno, long r)
+{
+#ifdef HAVE_BTRFSUTIL_H
+	enum btrfs_util_error	e;
+	pathname_t		f;
+	fent_t			*fep;
+	int			id;
+	int			parid;
+	int			v;
+	int			v1;
+	int			err;
+
+	init_pathname(&f);
+	if (!get_fname(FT_DIRm | FT_SUBVOLm, r, NULL, NULL, &fep, &v))
+		parid = -1;
+	else
+		parid = fep->id;
+	err = generate_fname(fep, FT_SUBVOL, &f, &id, &v1);
+	v |= v1;
+	if (!err) {
+		if (v) {
+			(void)fent_to_name(&f, fep);
+			printf("%d/%d: subvol_create - no filename from %s\n",
+			       procid, opno, f.path);
+		}
+		free_pathname(&f);
+		return;
+	}
+	e = btrfs_util_create_subvolume(f.path, 0, NULL, NULL);
+	if (e == BTRFS_UTIL_OK)
+		add_to_flist(FT_SUBVOL, id, parid, 0);
+	if (v) {
+		printf("%d/%d: subvol_create %s %d(%s)\n", procid, opno,
+		       f.path, e, btrfs_util_strerror(e));
+		printf("%d/%d: subvol_create add id=%d,parent=%d\n", procid,
+		       opno, id, parid);
+	}
+	free_pathname(&f);
+#endif
+}
+
+void
+subvol_delete_f(int opno, long r)
+{
+#ifdef HAVE_BTRFSUTIL_H
+	enum btrfs_util_error	e;
+	pathname_t		f;
+	fent_t			*fep;
+	int			v;
+	int			oldid;
+	int			oldparid;
+
+	init_pathname(&f);
+	if (!get_fname(FT_SUBVOLm, r, &f, NULL, &fep, &v)) {
+		if (v)
+			printf("%d:%d: subvol_delete - no subvolume\n", procid,
+			       opno);
+		free_pathname(&f);
+		return;
+	}
+	e = btrfs_util_delete_subvolume(f.path, 0);
+	check_cwd();
+	if (e == BTRFS_UTIL_OK) {
+		oldid = fep->id;
+		oldparid = fep->parent;
+		delete_subvol_children(oldid);
+		del_from_flist(FT_SUBVOL, fep - flist[FT_SUBVOL].fents);
+	}
+	if (v) {
+		printf("%d/%d: subvol_delete %s %d(%s)\n", procid, opno, f.path,
+		       e, btrfs_util_strerror(e));
+		if (e == BTRFS_UTIL_OK)
+			printf("%d/%d: subvol_delete del entry: id=%d,parent=%d\n",
+			       procid, opno, oldid, oldparid);
+	}
+	free_pathname(&f);
+#endif
+}
+
 void
 symlink_f(int opno, long r)
 {
@@ -4670,7 +4828,7 @@ symlink_f(int opno, long r)
 	v |= v1;
 	if (!e) {
 		if (v) {
-			(void)fent_to_name(&f, &flist[FT_DIR], fep);
+			(void)fent_to_name(&f, fep);
 			printf("%d/%d: symlink - no filename from %s\n",
 				procid, opno, f.path);
 		}
diff --git a/m4/package_libbtrfs.m4 b/m4/package_libbtrfs.m4
new file mode 100644
index 00000000..4822cc4a
--- /dev/null
+++ b/m4/package_libbtrfs.m4
@@ -0,0 +1,5 @@
+AC_DEFUN([AC_PACKAGE_WANT_LIBBTRFSUTIL],
+  [ AC_CHECK_HEADERS(btrfsutil.h, [ have_libbtrfsutil=true ],
+                     [ have_libbtrfsutil=false ])
+    AC_SUBST(have_libbtrfsutil)
+  ])
-- 
2.21.0


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

* [PATCH 2/3] fsstress: add the ability to create snapshots
  2019-11-14 15:58 [PATCH 0/3] fsstress: add support for btrfs subvol and snapshot ops Josef Bacik
  2019-11-14 15:58 ` [PATCH 1/3] fsstress: add the ability to create/delete subvolumes Josef Bacik
@ 2019-11-14 15:58 ` Josef Bacik
  2019-12-17 16:06   ` Filipe Manana
  2019-11-14 15:58 ` [PATCH 3/3] fsstress: allow operations to use either a directory or subvol Josef Bacik
  2 siblings, 1 reply; 8+ messages in thread
From: Josef Bacik @ 2019-11-14 15:58 UTC (permalink / raw)
  To: fstests, kernel-team, linux-btrfs

Snapshots are just fancy subvolumes, add this ability so we can stress
snapshot creation.  We get the deletion with SUBVOL_DELETE.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
 ltp/fsstress.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/ltp/fsstress.c b/ltp/fsstress.c
index e0636a12..f7f5f1dc 100644
--- a/ltp/fsstress.c
+++ b/ltp/fsstress.c
@@ -129,6 +129,7 @@ typedef enum {
 	OP_SETATTR,
 	OP_SETFATTR,
 	OP_SETXATTR,
+	OP_SNAPSHOT,
 	OP_SPLICE,
 	OP_STAT,
 	OP_SUBVOL_CREATE,
@@ -255,6 +256,7 @@ void	rmdir_f(int, long);
 void	setattr_f(int, long);
 void	setfattr_f(int, long);
 void	setxattr_f(int, long);
+void	snapshot_f(int, long);
 void	splice_f(int, long);
 void	stat_f(int, long);
 void	subvol_create_f(int, long);
@@ -322,6 +324,7 @@ opdesc_t	ops[] = {
 	{ OP_SETFATTR, "setfattr", setfattr_f, 2, 1 },
 	/* set project id (XFS_IOC_FSSETXATTR ioctl) */
 	{ OP_SETXATTR, "setxattr", setxattr_f, 1, 1 },
+	{ OP_SNAPSHOT, "snapshot", snapshot_f, 1, 1 },
 	{ OP_SPLICE, "splice", splice_f, 1, 1 },
 	{ OP_STAT, "stat", stat_f, 1, 0 },
 	{ OP_SUBVOL_CREATE, "subvol_create", subvol_create_f, 1, 1},
@@ -1903,6 +1906,7 @@ zero_freq(void)
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
 
 opty_t btrfs_ops[] = {
+	OP_SNAPSHOT,
 	OP_SUBVOL_CREATE,
 	OP_SUBVOL_DELETE,
 };
@@ -4703,6 +4707,55 @@ out:
 	free_pathname(&f);
 }
 
+void
+snapshot_f(int opno, long r)
+{
+#ifdef HAVE_BTRFSUTIL_H
+	enum btrfs_util_error	e;
+	pathname_t		f;
+	pathname_t		newf;
+	fent_t			*fep;
+	int			id;
+	int			parid;
+	int			v;
+	int			v1;
+	int			err;
+
+	init_pathname(&f);
+	if (!get_fname(FT_SUBVOLm, r, &f, NULL, &fep, &v)) {
+		if (v)
+			printf("%d/%d: snapshot - no subvolume\n", procid,
+			       opno);
+		free_pathname(&f);
+		return;
+	}
+	init_pathname(&newf);
+	parid = fep->id;
+	err = generate_fname(fep, FT_SUBVOL, &newf, &id, &v1);
+	v |= v1;
+	if (!err) {
+		if (v) {
+			(void)fent_to_name(&f, fep);
+			printf("%d/%d: snapshot - no filename from %s\n",
+			       procid, opno, f.path);
+		}
+		free_pathname(&f);
+		return;
+	}
+	e = btrfs_util_create_snapshot(f.path, newf.path, 0, NULL, NULL);
+	if (e == BTRFS_UTIL_OK)
+		add_to_flist(FT_SUBVOL, id, parid, 0);
+	if (v) {
+		printf("%d/%d: snapshot %s->%s %d(%s)\n", procid, opno,
+		       f.path, newf.path, e, btrfs_util_strerror(e));
+		printf("%d/%d: snapshot add id=%d,parent=%d\n", procid, opno,
+		       id, parid);
+	}
+	free_pathname(&newf);
+	free_pathname(&f);
+#endif
+}
+
 void
 stat_f(int opno, long r)
 {
-- 
2.21.0


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

* [PATCH 3/3] fsstress: allow operations to use either a directory or subvol
  2019-11-14 15:58 [PATCH 0/3] fsstress: add support for btrfs subvol and snapshot ops Josef Bacik
  2019-11-14 15:58 ` [PATCH 1/3] fsstress: add the ability to create/delete subvolumes Josef Bacik
  2019-11-14 15:58 ` [PATCH 2/3] fsstress: add the ability to create snapshots Josef Bacik
@ 2019-11-14 15:58 ` Josef Bacik
  2019-12-17 16:10   ` Filipe Manana
  2 siblings, 1 reply; 8+ messages in thread
From: Josef Bacik @ 2019-11-14 15:58 UTC (permalink / raw)
  To: fstests, kernel-team, linux-btrfs

Most operations are just looking for a base directory to generate a file
in, they don't actually need a directory specifically.  Add FT_ANYDIR to
cover both directories and subvolumes, and then use this in all the
places where it makes sense.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
 ltp/fsstress.c | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/ltp/fsstress.c b/ltp/fsstress.c
index f7f5f1dc..30b2bd94 100644
--- a/ltp/fsstress.c
+++ b/ltp/fsstress.c
@@ -200,6 +200,7 @@ struct print_string {
 #define	FT_ANYm		((1 << FT_nft) - 1)
 #define	FT_REGFILE	(FT_REGm | FT_RTFm)
 #define	FT_NOTDIR	(FT_ANYm & (~FT_DIRm & ~FT_SUBVOLm))
+#define FT_ANYDIR	(FT_DIRm | FT_SUBVOLm)
 
 #define	FLIST_SLOT_INCR	16
 #define	NDCACHE	64
@@ -3165,7 +3166,7 @@ creat_f(int opno, long r)
 	int		v;
 	int		v1;
 
-	if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v1))
+	if (!get_fname(FT_ANYDIR, r, NULL, NULL, &fep, &v1))
 		parid = -1;
 	else
 		parid = fep->id;
@@ -3729,7 +3730,7 @@ getdents_f(int opno, long r)
 	int		v;
 
 	init_pathname(&f);
-	if (!get_fname(FT_DIRm, r, &f, NULL, NULL, &v))
+	if (!get_fname(FT_ANYDIR, r, &f, NULL, NULL, &v))
 		append_pathname(&f, ".");
 	dir = opendir_path(&f);
 	check_cwd();
@@ -3761,7 +3762,7 @@ getfattr_f(int opno, long r)
 	int             xattr_num;
 
 	init_pathname(&f);
-	if (!get_fname(FT_REGFILE | FT_DIRm, r, &f, NULL, &fep, &v)) {
+	if (!get_fname(FT_REGFILE | FT_ANYDIR, r, &f, NULL, &fep, &v)) {
 		if (v)
 			printf("%d/%d: getfattr - no filename\n", procid, opno);
 		goto out;
@@ -3880,7 +3881,7 @@ listfattr_f(int opno, long r)
 	int             buffer_len;
 
 	init_pathname(&f);
-	if (!get_fname(FT_REGFILE | FT_DIRm, r, &f, NULL, &fep, &v)) {
+	if (!get_fname(FT_REGFILE | FT_ANYDIR, r, &f, NULL, &fep, &v)) {
 		if (v)
 			printf("%d/%d: listfattr - no filename\n", procid, opno);
 		goto out;
@@ -3930,7 +3931,7 @@ mkdir_f(int opno, long r)
 	int		v;
 	int		v1;
 
-	if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v))
+	if (!get_fname(FT_ANYDIR, r, NULL, NULL, &fep, &v))
 		parid = -1;
 	else
 		parid = fep->id;
@@ -3968,7 +3969,7 @@ mknod_f(int opno, long r)
 	int		v;
 	int		v1;
 
-	if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v))
+	if (!get_fname(FT_ANYDIR, r, NULL, NULL, &fep, &v))
 		parid = -1;
 	else
 		parid = fep->id;
@@ -4326,7 +4327,7 @@ removefattr_f(int opno, long r)
 	int             xattr_num;
 
 	init_pathname(&f);
-	if (!get_fname(FT_REGFILE | FT_DIRm, r, &f, NULL, &fep, &v)) {
+	if (!get_fname(FT_REGFILE | FT_ANYDIR, r, &f, NULL, &fep, &v)) {
 		if (v)
 			printf("%d/%d: removefattr - no filename\n", procid, opno);
 		goto out;
@@ -4646,7 +4647,7 @@ setfattr_f(int opno, long r)
 	int             xattr_num;
 
 	init_pathname(&f);
-	if (!get_fname(FT_REGFILE | FT_DIRm, r, &f, NULL, &fep, &v)) {
+	if (!get_fname(FT_REGFILE | FT_ANYDIR, r, &f, NULL, &fep, &v)) {
 		if (v)
 			printf("%d/%d: setfattr - no filename\n", procid, opno);
 		goto out;
@@ -4792,7 +4793,7 @@ subvol_create_f(int opno, long r)
 	int			err;
 
 	init_pathname(&f);
-	if (!get_fname(FT_DIRm | FT_SUBVOLm, r, NULL, NULL, &fep, &v))
+	if (!get_fname(FT_ANYDIR, r, NULL, NULL, &fep, &v))
 		parid = -1;
 	else
 		parid = fep->id;
@@ -4872,7 +4873,7 @@ symlink_f(int opno, long r)
 	int		v1;
 	char		*val;
 
-	if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v))
+	if (!get_fname(FT_ANYDIR, r, NULL, NULL, &fep, &v))
 		parid = -1;
 	else
 		parid = fep->id;
-- 
2.21.0


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

* [PATCH][v2] fsstress: add the ability to create/delete subvolumes
  2019-11-14 15:58 ` [PATCH 1/3] fsstress: add the ability to create/delete subvolumes Josef Bacik
@ 2019-11-14 18:14   ` Josef Bacik
  2019-12-17 15:55     ` Filipe Manana
  0 siblings, 1 reply; 8+ messages in thread
From: Josef Bacik @ 2019-11-14 18:14 UTC (permalink / raw)
  To: fstests, kernel-team, linux-btrfs

This patch adds support to fsstress for creating and deleting subvolumes
on a btrfs file system.  We link in the libbtrfsutil library to handle
the mechanics of creating and deleting subvolumes instead of duplicating
the ioctl logic.  There is code to check if we're on a btrfs fs at
startup time and if so 0 out the frequency of the btrfs specific
operations.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
v1->v2:
- fixed the #include location for btrfsutil.h in fsstress.c.  The old centos box
  I had built this fine, but on modern boxes I was tripped up because I put this
  in a weird #ifdef thing for renameat2.  Moving it to the top so it actually
  gets included and the build works.

 configure.ac           |   1 +
 include/builddefs.in   |   1 +
 ltp/Makefile           |   4 +
 ltp/fsstress.c         | 227 ++++++++++++++++++++++++++++++++++-------
 m4/package_libbtrfs.m4 |   5 +
 5 files changed, 203 insertions(+), 35 deletions(-)
 create mode 100644 m4/package_libbtrfs.m4

diff --git a/configure.ac b/configure.ac
index 19798824..4bb50b32 100644
--- a/configure.ac
+++ b/configure.ac
@@ -67,6 +67,7 @@ AC_PACKAGE_WANT_FALLOCATE
 AC_PACKAGE_WANT_OPEN_BY_HANDLE_AT
 AC_PACKAGE_WANT_LINUX_PRCTL_H
 AC_PACKAGE_WANT_LINUX_FS_H
+AC_PACKAGE_WANT_LIBBTRFSUTIL
 
 AC_HAVE_COPY_FILE_RANGE
 
diff --git a/include/builddefs.in b/include/builddefs.in
index 2605e42d..e7894b1a 100644
--- a/include/builddefs.in
+++ b/include/builddefs.in
@@ -68,6 +68,7 @@ HAVE_ATTR_LIST = @have_attr_list@
 HAVE_FIEMAP = @have_fiemap@
 HAVE_FALLOCATE = @have_fallocate@
 HAVE_COPY_FILE_RANGE = @have_copy_file_range@
+HAVE_LIBBTRFSUTIL = @have_libbtrfsutil@
 
 GCCFLAGS = -funsigned-char -fno-strict-aliasing -Wall
 
diff --git a/ltp/Makefile b/ltp/Makefile
index e4ca45f4..ebf40336 100644
--- a/ltp/Makefile
+++ b/ltp/Makefile
@@ -24,6 +24,10 @@ LCFLAGS += -DAIO
 LLDLIBS += -laio -lpthread
 endif
 
+ifeq ($(HAVE_LIBBTRFSUTIL), true)
+LLDLIBS += -lbtrfsutil
+endif
+
 ifeq ($(HAVE_FALLOCATE), true)
 LCFLAGS += -DFALLOCATE
 endif
diff --git a/ltp/fsstress.c b/ltp/fsstress.c
index 9f5ec1d0..45325a67 100644
--- a/ltp/fsstress.c
+++ b/ltp/fsstress.c
@@ -10,6 +10,9 @@
 #include <stddef.h>
 #include "global.h"
 
+#ifdef HAVE_BTRFSUTIL_H
+#include <btrfsutil.h>
+#endif
 #ifdef HAVE_ATTR_ATTRIBUTES_H
 #include <attr/attributes.h>
 #endif
@@ -127,6 +130,8 @@ typedef enum {
 	OP_SETXATTR,
 	OP_SPLICE,
 	OP_STAT,
+	OP_SUBVOL_CREATE,
+	OP_SUBVOL_DELETE,
 	OP_SYMLINK,
 	OP_SYNC,
 	OP_TRUNCATE,
@@ -149,6 +154,7 @@ typedef struct opdesc {
 
 typedef struct fent {
 	int	id;
+	int	ft;
 	int	parent;
 	int	xattr_counter;
 } fent_t;
@@ -176,20 +182,22 @@ struct print_string {
 	int max;
 };
 
-#define	FT_DIR	0
-#define	FT_DIRm	(1 << FT_DIR)
-#define	FT_REG	1
-#define	FT_REGm	(1 << FT_REG)
-#define	FT_SYM	2
-#define	FT_SYMm	(1 << FT_SYM)
-#define	FT_DEV	3
-#define	FT_DEVm	(1 << FT_DEV)
-#define	FT_RTF	4
-#define	FT_RTFm	(1 << FT_RTF)
-#define	FT_nft	5
-#define	FT_ANYm	((1 << FT_nft) - 1)
+#define	FT_DIR		0
+#define	FT_DIRm		(1 << FT_DIR)
+#define	FT_REG		1
+#define	FT_REGm		(1 << FT_REG)
+#define	FT_SYM		2
+#define	FT_SYMm		(1 << FT_SYM)
+#define	FT_DEV		3
+#define	FT_DEVm		(1 << FT_DEV)
+#define	FT_RTF		4
+#define	FT_RTFm		(1 << FT_RTF)
+#define	FT_SUBVOL	5
+#define	FT_SUBVOLm	(1 << FT_SUBVOL)
+#define	FT_nft		6
+#define	FT_ANYm		((1 << FT_nft) - 1)
 #define	FT_REGFILE	(FT_REGm | FT_RTFm)
-#define	FT_NOTDIR	(FT_ANYm & ~FT_DIRm)
+#define	FT_NOTDIR	(FT_ANYm & (~FT_DIRm & ~FT_SUBVOLm))
 
 #define	FLIST_SLOT_INCR	16
 #define	NDCACHE	64
@@ -248,6 +256,8 @@ void	setfattr_f(int, long);
 void	setxattr_f(int, long);
 void	splice_f(int, long);
 void	stat_f(int, long);
+void	subvol_create_f(int, long);
+void	subvol_delete_f(int, long);
 void	symlink_f(int, long);
 void	sync_f(int, long);
 void	truncate_f(int, long);
@@ -313,6 +323,8 @@ opdesc_t	ops[] = {
 	{ OP_SETXATTR, "setxattr", setxattr_f, 1, 1 },
 	{ OP_SPLICE, "splice", splice_f, 1, 1 },
 	{ OP_STAT, "stat", stat_f, 1, 0 },
+	{ OP_SUBVOL_CREATE, "subvol_create", subvol_create_f, 1, 1},
+	{ OP_SUBVOL_DELETE, "subvol_delete", subvol_delete_f, 1, 1},
 	{ OP_SYMLINK, "symlink", symlink_f, 2, 1 },
 	{ OP_SYNC, "sync", sync_f, 1, 1 },
 	{ OP_TRUNCATE, "truncate", truncate_f, 2, 1 },
@@ -328,6 +340,7 @@ flist_t	flist[FT_nft] = {
 	{ 0, 0, 'l', NULL },
 	{ 0, 0, 'c', NULL },
 	{ 0, 0, 'r', NULL },
+	{ 0, 0, 's', NULL },
 };
 
 int		dcache[NDCACHE];
@@ -372,11 +385,11 @@ int	creat_path(pathname_t *, mode_t);
 void	dcache_enter(int, int);
 void	dcache_init(void);
 fent_t	*dcache_lookup(int);
-void	dcache_purge(int);
+void	dcache_purge(int, int);
 void	del_from_flist(int, int);
 int	dirid_to_name(char *, int);
 void	doproc(void);
-int	fent_to_name(pathname_t *, flist_t *, fent_t *);
+int	fent_to_name(pathname_t *, fent_t *);
 bool	fents_ancestor_check(fent_t *, fent_t *);
 void	fix_parent(int, int, bool);
 void	free_pathname(pathname_t *);
@@ -407,6 +420,7 @@ int	unlink_path(pathname_t *);
 void	usage(void);
 void	write_freq(void);
 void	zero_freq(void);
+void	non_btrfs_freq(const char *);
 
 void sg_handler(int signum)
 {
@@ -560,6 +574,7 @@ int main(int argc, char **argv)
             exit(1);
         }
 
+	non_btrfs_freq(dirname);
 	(void)mkdir(dirname, 0777);
 	if (logname && logname[0] != '/') {
 		if (!getcwd(rpath, sizeof(rpath))){
@@ -795,6 +810,7 @@ add_to_flist(int ft, int id, int parent, int xattr_counter)
 	}
 	fep = &ftp->fents[ftp->nfiles++];
 	fep->id = id;
+	fep->ft = ft;
 	fep->parent = parent;
 	fep->xattr_counter = xattr_counter;
 }
@@ -962,18 +978,22 @@ dcache_lookup(int dirid)
 	int	i;
 
 	i = dcache[dirid % NDCACHE];
-	if (i >= 0 && (fep = &flist[FT_DIR].fents[i])->id == dirid)
+	if (i >= 0 && i < flist[FT_DIR].nfiles &&
+	    (fep = &flist[FT_DIR].fents[i])->id == dirid)
+		return fep;
+	if (i >= 0 && i < flist[FT_SUBVOL].nfiles &&
+	    (fep = &flist[FT_SUBVOL].fents[i])->id == dirid)
 		return fep;
 	return NULL;
 }
 
 void
-dcache_purge(int dirid)
+dcache_purge(int dirid, int ft)
 {
 	int	*dcp;
-
 	dcp = &dcache[dirid % NDCACHE];
-	if (*dcp >= 0 && flist[FT_DIR].fents[*dcp].id == dirid)
+	if (*dcp >= 0 && *dcp < flist[ft].nfiles &&
+	    flist[ft].fents[*dcp].id == dirid)
 		*dcp = -1;
 }
 
@@ -989,32 +1009,58 @@ del_from_flist(int ft, int slot)
 	flist_t	*ftp;
 
 	ftp = &flist[ft];
-	if (ft == FT_DIR)
-		dcache_purge(ftp->fents[slot].id);
+	if (ft == FT_DIR || ft == FT_SUBVOL)
+		dcache_purge(ftp->fents[slot].id, ft);
 	if (slot != ftp->nfiles - 1) {
-		if (ft == FT_DIR)
-			dcache_purge(ftp->fents[ftp->nfiles - 1].id);
+		if (ft == FT_DIR || ft == FT_SUBVOL)
+			dcache_purge(ftp->fents[ftp->nfiles - 1].id, ft);
 		ftp->fents[slot] = ftp->fents[--ftp->nfiles];
 	} else
 		ftp->nfiles--;
 }
 
+void
+delete_subvol_children(int parid)
+{
+	flist_t	*flp;
+	int	i;
+again:
+	for (i = 0, flp = flist; i < FT_nft; i++, flp++) {
+		int c;
+		for (c = 0; c < flp->nfiles; c++) {
+			if (flp->fents[c].parent == parid) {
+				int id = flp->fents[c].id;
+				del_from_flist(i, c);
+				if (i == FT_DIR || i == FT_SUBVOL)
+					delete_subvol_children(id);
+				goto again;
+			}
+		}
+	}
+}
+
 fent_t *
 dirid_to_fent(int dirid)
 {
 	fent_t	*efep;
 	fent_t	*fep;
 	flist_t	*flp;
+	int	ft = FT_DIR;
 
 	if ((fep = dcache_lookup(dirid)))
 		return fep;
-	flp = &flist[FT_DIR];
+again:
+	flp = &flist[ft];
 	for (fep = flp->fents, efep = &fep[flp->nfiles]; fep < efep; fep++) {
 		if (fep->id == dirid) {
 			dcache_enter(dirid, fep - flp->fents);
 			return fep;
 		}
 	}
+	if (ft == FT_DIR) {
+		ft = FT_SUBVOL;
+		goto again;
+	}
 	return NULL;
 }
 
@@ -1091,8 +1137,9 @@ errout:
  * Return 0 on error, 1 on success;
  */
 int
-fent_to_name(pathname_t *name, flist_t *flp, fent_t *fep)
+fent_to_name(pathname_t *name, fent_t *fep)
 {
+	flist_t	*flp = &flist[fep->ft];
 	char	buf[NAME_MAX + 1];
 	int	i;
 	fent_t	*pfep;
@@ -1112,7 +1159,7 @@ fent_to_name(pathname_t *name, flist_t *flp, fent_t *fep)
 #endif
 		if (pfep == NULL)
 			return 0;
-		e = fent_to_name(name, &flist[FT_DIR], pfep);
+		e = fent_to_name(name, pfep);
 		if (!e)
 			return 0;
 		append_pathname(name, "/");
@@ -1188,7 +1235,7 @@ generate_fname(fent_t *fep, int ft, pathname_t *name, int *idp, int *v)
 
 	/* prepend fep parent dir-name to it */
 	if (fep) {
-		e = fent_to_name(name, &flist[FT_DIR], fep);
+		e = fent_to_name(name, fep);
 		if (!e)
 			return 0;
 		append_pathname(name, "/");
@@ -1270,7 +1317,7 @@ get_fname(int which, long r, pathname_t *name, flist_t **flpp, fent_t **fepp,
 
 				/* fill-in what we were asked for */
 				if (name) {
-					e = fent_to_name(name, flp, fep);
+					e = fent_to_name(name, fep);
 #ifdef DEBUG
 					if (!e) {
 						fprintf(stderr, "%d: failed to get path for entry:"
@@ -1852,6 +1899,35 @@ zero_freq(void)
 		p->freq = 0;
 }
 
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+opty_t btrfs_ops[] = {
+	OP_SUBVOL_CREATE,
+	OP_SUBVOL_DELETE,
+};
+
+void
+non_btrfs_freq(const char *path)
+{
+	opdesc_t		*p;
+#ifdef HAVE_BTRFSUTIL_H
+	enum btrfs_util_error	e;
+
+	e = btrfs_util_is_subvolume(path);
+	if (e != BTRFS_UTIL_ERROR_NOT_BTRFS)
+		return;
+#endif
+	for (p = ops; p < ops_end; p++) {
+		int i;
+		for (i = 0; i < ARRAY_SIZE(btrfs_ops); i++) {
+			if (p->op == btrfs_ops[i]) {
+				p->freq = 0;
+				break;
+			}
+		}
+	}
+}
+
 void inode_info(char *str, size_t sz, struct stat64 *s, int verbose)
 {
 	if (verbose)
@@ -3103,7 +3179,7 @@ creat_f(int opno, long r)
 	v |= v1;
 	if (!e) {
 		if (v) {
-			(void)fent_to_name(&f, &flist[FT_DIR], fep);
+			(void)fent_to_name(&f, fep);
 			printf("%d/%d: creat - no filename from %s\n",
 				procid, opno, f.path);
 		}
@@ -3767,7 +3843,7 @@ link_f(int opno, long r)
 	v |= v1;
 	if (!e) {
 		if (v) {
-			(void)fent_to_name(&l, &flist[FT_DIR], fep);
+			(void)fent_to_name(&l, fep);
 			printf("%d/%d: link - no filename from %s\n",
 				procid, opno, l.path);
 		}
@@ -3858,7 +3934,7 @@ mkdir_f(int opno, long r)
 	v |= v1;
 	if (!e) {
 		if (v) {
-			(void)fent_to_name(&f, &flist[FT_DIR], fep);
+			(void)fent_to_name(&f, fep);
 			printf("%d/%d: mkdir - no filename from %s\n",
 				procid, opno, f.path);
 		}
@@ -3896,7 +3972,7 @@ mknod_f(int opno, long r)
 	v |= v1;
 	if (!e) {
 		if (v) {
-			(void)fent_to_name(&f, &flist[FT_DIR], fep);
+			(void)fent_to_name(&f, fep);
 			printf("%d/%d: mknod - no filename from %s\n",
 				procid, opno, f.path);
 		}
@@ -4364,7 +4440,7 @@ do_renameat2(int opno, long r, int mode)
 		v |= v1;
 		if (!e) {
 			if (v) {
-				(void)fent_to_name(&f, &flist[FT_DIR], dfep);
+				(void)fent_to_name(&f, dfep);
 				printf("%d/%d: rename - no filename from %s\n",
 					procid, opno, f.path);
 			}
@@ -4378,6 +4454,7 @@ do_renameat2(int opno, long r, int mode)
 	if (e == 0) {
 		int xattr_counter = fep->xattr_counter;
 		bool swap = (mode == RENAME_EXCHANGE) ? true : false;
+		int ft = flp - flist;
 
 		oldid = fep->id;
 		oldparid = fep->parent;
@@ -4386,7 +4463,7 @@ do_renameat2(int opno, long r, int mode)
 		 * Swap the parent ids for RENAME_EXCHANGE, and replace the
 		 * old parent id for the others.
 		 */
-		if (flp - flist == FT_DIR)
+		if (ft == FT_DIR || ft == FT_SUBVOL)
 			fix_parent(oldid, id, swap);
 
 		if (mode == RENAME_WHITEOUT) {
@@ -4647,6 +4724,86 @@ stat_f(int opno, long r)
 	free_pathname(&f);
 }
 
+void
+subvol_create_f(int opno, long r)
+{
+#ifdef HAVE_BTRFSUTIL_H
+	enum btrfs_util_error	e;
+	pathname_t		f;
+	fent_t			*fep;
+	int			id;
+	int			parid;
+	int			v;
+	int			v1;
+	int			err;
+
+	init_pathname(&f);
+	if (!get_fname(FT_DIRm | FT_SUBVOLm, r, NULL, NULL, &fep, &v))
+		parid = -1;
+	else
+		parid = fep->id;
+	err = generate_fname(fep, FT_SUBVOL, &f, &id, &v1);
+	v |= v1;
+	if (!err) {
+		if (v) {
+			(void)fent_to_name(&f, fep);
+			printf("%d/%d: subvol_create - no filename from %s\n",
+			       procid, opno, f.path);
+		}
+		free_pathname(&f);
+		return;
+	}
+	e = btrfs_util_create_subvolume(f.path, 0, NULL, NULL);
+	if (e == BTRFS_UTIL_OK)
+		add_to_flist(FT_SUBVOL, id, parid, 0);
+	if (v) {
+		printf("%d/%d: subvol_create %s %d(%s)\n", procid, opno,
+		       f.path, e, btrfs_util_strerror(e));
+		printf("%d/%d: subvol_create add id=%d,parent=%d\n", procid,
+		       opno, id, parid);
+	}
+	free_pathname(&f);
+#endif
+}
+
+void
+subvol_delete_f(int opno, long r)
+{
+#ifdef HAVE_BTRFSUTIL_H
+	enum btrfs_util_error	e;
+	pathname_t		f;
+	fent_t			*fep;
+	int			v;
+	int			oldid;
+	int			oldparid;
+
+	init_pathname(&f);
+	if (!get_fname(FT_SUBVOLm, r, &f, NULL, &fep, &v)) {
+		if (v)
+			printf("%d:%d: subvol_delete - no subvolume\n", procid,
+			       opno);
+		free_pathname(&f);
+		return;
+	}
+	e = btrfs_util_delete_subvolume(f.path, 0);
+	check_cwd();
+	if (e == BTRFS_UTIL_OK) {
+		oldid = fep->id;
+		oldparid = fep->parent;
+		delete_subvol_children(oldid);
+		del_from_flist(FT_SUBVOL, fep - flist[FT_SUBVOL].fents);
+	}
+	if (v) {
+		printf("%d/%d: subvol_delete %s %d(%s)\n", procid, opno, f.path,
+		       e, btrfs_util_strerror(e));
+		if (e == BTRFS_UTIL_OK)
+			printf("%d/%d: subvol_delete del entry: id=%d,parent=%d\n",
+			       procid, opno, oldid, oldparid);
+	}
+	free_pathname(&f);
+#endif
+}
+
 void
 symlink_f(int opno, long r)
 {
@@ -4670,7 +4827,7 @@ symlink_f(int opno, long r)
 	v |= v1;
 	if (!e) {
 		if (v) {
-			(void)fent_to_name(&f, &flist[FT_DIR], fep);
+			(void)fent_to_name(&f, fep);
 			printf("%d/%d: symlink - no filename from %s\n",
 				procid, opno, f.path);
 		}
diff --git a/m4/package_libbtrfs.m4 b/m4/package_libbtrfs.m4
new file mode 100644
index 00000000..4822cc4a
--- /dev/null
+++ b/m4/package_libbtrfs.m4
@@ -0,0 +1,5 @@
+AC_DEFUN([AC_PACKAGE_WANT_LIBBTRFSUTIL],
+  [ AC_CHECK_HEADERS(btrfsutil.h, [ have_libbtrfsutil=true ],
+                     [ have_libbtrfsutil=false ])
+    AC_SUBST(have_libbtrfsutil)
+  ])
-- 
2.21.0


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

* Re: [PATCH][v2] fsstress: add the ability to create/delete subvolumes
  2019-11-14 18:14   ` [PATCH][v2] " Josef Bacik
@ 2019-12-17 15:55     ` Filipe Manana
  0 siblings, 0 replies; 8+ messages in thread
From: Filipe Manana @ 2019-12-17 15:55 UTC (permalink / raw)
  To: Josef Bacik; +Cc: fstests, kernel-team, linux-btrfs

On Thu, Nov 14, 2019 at 6:15 PM Josef Bacik <josef@toxicpanda.com> wrote:
>
> This patch adds support to fsstress for creating and deleting subvolumes
> on a btrfs file system.  We link in the libbtrfsutil library to handle
> the mechanics of creating and deleting subvolumes instead of duplicating
> the ioctl logic.  There is code to check if we're on a btrfs fs at
> startup time and if so 0 out the frequency of the btrfs specific
> operations.
>
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>

Very useful and works on my test environments, thanks.

Reviewed-by: Filipe Manana <fdmanana@suse.com>

> ---
> v1->v2:
> - fixed the #include location for btrfsutil.h in fsstress.c.  The old centos box
>   I had built this fine, but on modern boxes I was tripped up because I put this
>   in a weird #ifdef thing for renameat2.  Moving it to the top so it actually
>   gets included and the build works.
>
>  configure.ac           |   1 +
>  include/builddefs.in   |   1 +
>  ltp/Makefile           |   4 +
>  ltp/fsstress.c         | 227 ++++++++++++++++++++++++++++++++++-------
>  m4/package_libbtrfs.m4 |   5 +
>  5 files changed, 203 insertions(+), 35 deletions(-)
>  create mode 100644 m4/package_libbtrfs.m4
>
> diff --git a/configure.ac b/configure.ac
> index 19798824..4bb50b32 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -67,6 +67,7 @@ AC_PACKAGE_WANT_FALLOCATE
>  AC_PACKAGE_WANT_OPEN_BY_HANDLE_AT
>  AC_PACKAGE_WANT_LINUX_PRCTL_H
>  AC_PACKAGE_WANT_LINUX_FS_H
> +AC_PACKAGE_WANT_LIBBTRFSUTIL
>
>  AC_HAVE_COPY_FILE_RANGE
>
> diff --git a/include/builddefs.in b/include/builddefs.in
> index 2605e42d..e7894b1a 100644
> --- a/include/builddefs.in
> +++ b/include/builddefs.in
> @@ -68,6 +68,7 @@ HAVE_ATTR_LIST = @have_attr_list@
>  HAVE_FIEMAP = @have_fiemap@
>  HAVE_FALLOCATE = @have_fallocate@
>  HAVE_COPY_FILE_RANGE = @have_copy_file_range@
> +HAVE_LIBBTRFSUTIL = @have_libbtrfsutil@
>
>  GCCFLAGS = -funsigned-char -fno-strict-aliasing -Wall
>
> diff --git a/ltp/Makefile b/ltp/Makefile
> index e4ca45f4..ebf40336 100644
> --- a/ltp/Makefile
> +++ b/ltp/Makefile
> @@ -24,6 +24,10 @@ LCFLAGS += -DAIO
>  LLDLIBS += -laio -lpthread
>  endif
>
> +ifeq ($(HAVE_LIBBTRFSUTIL), true)
> +LLDLIBS += -lbtrfsutil
> +endif
> +
>  ifeq ($(HAVE_FALLOCATE), true)
>  LCFLAGS += -DFALLOCATE
>  endif
> diff --git a/ltp/fsstress.c b/ltp/fsstress.c
> index 9f5ec1d0..45325a67 100644
> --- a/ltp/fsstress.c
> +++ b/ltp/fsstress.c
> @@ -10,6 +10,9 @@
>  #include <stddef.h>
>  #include "global.h"
>
> +#ifdef HAVE_BTRFSUTIL_H
> +#include <btrfsutil.h>
> +#endif
>  #ifdef HAVE_ATTR_ATTRIBUTES_H
>  #include <attr/attributes.h>
>  #endif
> @@ -127,6 +130,8 @@ typedef enum {
>         OP_SETXATTR,
>         OP_SPLICE,
>         OP_STAT,
> +       OP_SUBVOL_CREATE,
> +       OP_SUBVOL_DELETE,
>         OP_SYMLINK,
>         OP_SYNC,
>         OP_TRUNCATE,
> @@ -149,6 +154,7 @@ typedef struct opdesc {
>
>  typedef struct fent {
>         int     id;
> +       int     ft;
>         int     parent;
>         int     xattr_counter;
>  } fent_t;
> @@ -176,20 +182,22 @@ struct print_string {
>         int max;
>  };
>
> -#define        FT_DIR  0
> -#define        FT_DIRm (1 << FT_DIR)
> -#define        FT_REG  1
> -#define        FT_REGm (1 << FT_REG)
> -#define        FT_SYM  2
> -#define        FT_SYMm (1 << FT_SYM)
> -#define        FT_DEV  3
> -#define        FT_DEVm (1 << FT_DEV)
> -#define        FT_RTF  4
> -#define        FT_RTFm (1 << FT_RTF)
> -#define        FT_nft  5
> -#define        FT_ANYm ((1 << FT_nft) - 1)
> +#define        FT_DIR          0
> +#define        FT_DIRm         (1 << FT_DIR)
> +#define        FT_REG          1
> +#define        FT_REGm         (1 << FT_REG)
> +#define        FT_SYM          2
> +#define        FT_SYMm         (1 << FT_SYM)
> +#define        FT_DEV          3
> +#define        FT_DEVm         (1 << FT_DEV)
> +#define        FT_RTF          4
> +#define        FT_RTFm         (1 << FT_RTF)
> +#define        FT_SUBVOL       5
> +#define        FT_SUBVOLm      (1 << FT_SUBVOL)
> +#define        FT_nft          6
> +#define        FT_ANYm         ((1 << FT_nft) - 1)
>  #define        FT_REGFILE      (FT_REGm | FT_RTFm)
> -#define        FT_NOTDIR       (FT_ANYm & ~FT_DIRm)
> +#define        FT_NOTDIR       (FT_ANYm & (~FT_DIRm & ~FT_SUBVOLm))
>
>  #define        FLIST_SLOT_INCR 16
>  #define        NDCACHE 64
> @@ -248,6 +256,8 @@ void        setfattr_f(int, long);
>  void   setxattr_f(int, long);
>  void   splice_f(int, long);
>  void   stat_f(int, long);
> +void   subvol_create_f(int, long);
> +void   subvol_delete_f(int, long);
>  void   symlink_f(int, long);
>  void   sync_f(int, long);
>  void   truncate_f(int, long);
> @@ -313,6 +323,8 @@ opdesc_t    ops[] = {
>         { OP_SETXATTR, "setxattr", setxattr_f, 1, 1 },
>         { OP_SPLICE, "splice", splice_f, 1, 1 },
>         { OP_STAT, "stat", stat_f, 1, 0 },
> +       { OP_SUBVOL_CREATE, "subvol_create", subvol_create_f, 1, 1},
> +       { OP_SUBVOL_DELETE, "subvol_delete", subvol_delete_f, 1, 1},
>         { OP_SYMLINK, "symlink", symlink_f, 2, 1 },
>         { OP_SYNC, "sync", sync_f, 1, 1 },
>         { OP_TRUNCATE, "truncate", truncate_f, 2, 1 },
> @@ -328,6 +340,7 @@ flist_t     flist[FT_nft] = {
>         { 0, 0, 'l', NULL },
>         { 0, 0, 'c', NULL },
>         { 0, 0, 'r', NULL },
> +       { 0, 0, 's', NULL },
>  };
>
>  int            dcache[NDCACHE];
> @@ -372,11 +385,11 @@ int       creat_path(pathname_t *, mode_t);
>  void   dcache_enter(int, int);
>  void   dcache_init(void);
>  fent_t *dcache_lookup(int);
> -void   dcache_purge(int);
> +void   dcache_purge(int, int);
>  void   del_from_flist(int, int);
>  int    dirid_to_name(char *, int);
>  void   doproc(void);
> -int    fent_to_name(pathname_t *, flist_t *, fent_t *);
> +int    fent_to_name(pathname_t *, fent_t *);
>  bool   fents_ancestor_check(fent_t *, fent_t *);
>  void   fix_parent(int, int, bool);
>  void   free_pathname(pathname_t *);
> @@ -407,6 +420,7 @@ int unlink_path(pathname_t *);
>  void   usage(void);
>  void   write_freq(void);
>  void   zero_freq(void);
> +void   non_btrfs_freq(const char *);
>
>  void sg_handler(int signum)
>  {
> @@ -560,6 +574,7 @@ int main(int argc, char **argv)
>              exit(1);
>          }
>
> +       non_btrfs_freq(dirname);
>         (void)mkdir(dirname, 0777);
>         if (logname && logname[0] != '/') {
>                 if (!getcwd(rpath, sizeof(rpath))){
> @@ -795,6 +810,7 @@ add_to_flist(int ft, int id, int parent, int xattr_counter)
>         }
>         fep = &ftp->fents[ftp->nfiles++];
>         fep->id = id;
> +       fep->ft = ft;
>         fep->parent = parent;
>         fep->xattr_counter = xattr_counter;
>  }
> @@ -962,18 +978,22 @@ dcache_lookup(int dirid)
>         int     i;
>
>         i = dcache[dirid % NDCACHE];
> -       if (i >= 0 && (fep = &flist[FT_DIR].fents[i])->id == dirid)
> +       if (i >= 0 && i < flist[FT_DIR].nfiles &&
> +           (fep = &flist[FT_DIR].fents[i])->id == dirid)
> +               return fep;
> +       if (i >= 0 && i < flist[FT_SUBVOL].nfiles &&
> +           (fep = &flist[FT_SUBVOL].fents[i])->id == dirid)
>                 return fep;
>         return NULL;
>  }
>
>  void
> -dcache_purge(int dirid)
> +dcache_purge(int dirid, int ft)
>  {
>         int     *dcp;
> -
>         dcp = &dcache[dirid % NDCACHE];
> -       if (*dcp >= 0 && flist[FT_DIR].fents[*dcp].id == dirid)
> +       if (*dcp >= 0 && *dcp < flist[ft].nfiles &&
> +           flist[ft].fents[*dcp].id == dirid)
>                 *dcp = -1;
>  }
>
> @@ -989,32 +1009,58 @@ del_from_flist(int ft, int slot)
>         flist_t *ftp;
>
>         ftp = &flist[ft];
> -       if (ft == FT_DIR)
> -               dcache_purge(ftp->fents[slot].id);
> +       if (ft == FT_DIR || ft == FT_SUBVOL)
> +               dcache_purge(ftp->fents[slot].id, ft);
>         if (slot != ftp->nfiles - 1) {
> -               if (ft == FT_DIR)
> -                       dcache_purge(ftp->fents[ftp->nfiles - 1].id);
> +               if (ft == FT_DIR || ft == FT_SUBVOL)
> +                       dcache_purge(ftp->fents[ftp->nfiles - 1].id, ft);
>                 ftp->fents[slot] = ftp->fents[--ftp->nfiles];
>         } else
>                 ftp->nfiles--;
>  }
>
> +void
> +delete_subvol_children(int parid)
> +{
> +       flist_t *flp;
> +       int     i;
> +again:
> +       for (i = 0, flp = flist; i < FT_nft; i++, flp++) {
> +               int c;
> +               for (c = 0; c < flp->nfiles; c++) {
> +                       if (flp->fents[c].parent == parid) {
> +                               int id = flp->fents[c].id;
> +                               del_from_flist(i, c);
> +                               if (i == FT_DIR || i == FT_SUBVOL)
> +                                       delete_subvol_children(id);
> +                               goto again;
> +                       }
> +               }
> +       }
> +}
> +
>  fent_t *
>  dirid_to_fent(int dirid)
>  {
>         fent_t  *efep;
>         fent_t  *fep;
>         flist_t *flp;
> +       int     ft = FT_DIR;
>
>         if ((fep = dcache_lookup(dirid)))
>                 return fep;
> -       flp = &flist[FT_DIR];
> +again:
> +       flp = &flist[ft];
>         for (fep = flp->fents, efep = &fep[flp->nfiles]; fep < efep; fep++) {
>                 if (fep->id == dirid) {
>                         dcache_enter(dirid, fep - flp->fents);
>                         return fep;
>                 }
>         }
> +       if (ft == FT_DIR) {
> +               ft = FT_SUBVOL;
> +               goto again;
> +       }
>         return NULL;
>  }
>
> @@ -1091,8 +1137,9 @@ errout:
>   * Return 0 on error, 1 on success;
>   */
>  int
> -fent_to_name(pathname_t *name, flist_t *flp, fent_t *fep)
> +fent_to_name(pathname_t *name, fent_t *fep)
>  {
> +       flist_t *flp = &flist[fep->ft];
>         char    buf[NAME_MAX + 1];
>         int     i;
>         fent_t  *pfep;
> @@ -1112,7 +1159,7 @@ fent_to_name(pathname_t *name, flist_t *flp, fent_t *fep)
>  #endif
>                 if (pfep == NULL)
>                         return 0;
> -               e = fent_to_name(name, &flist[FT_DIR], pfep);
> +               e = fent_to_name(name, pfep);
>                 if (!e)
>                         return 0;
>                 append_pathname(name, "/");
> @@ -1188,7 +1235,7 @@ generate_fname(fent_t *fep, int ft, pathname_t *name, int *idp, int *v)
>
>         /* prepend fep parent dir-name to it */
>         if (fep) {
> -               e = fent_to_name(name, &flist[FT_DIR], fep);
> +               e = fent_to_name(name, fep);
>                 if (!e)
>                         return 0;
>                 append_pathname(name, "/");
> @@ -1270,7 +1317,7 @@ get_fname(int which, long r, pathname_t *name, flist_t **flpp, fent_t **fepp,
>
>                                 /* fill-in what we were asked for */
>                                 if (name) {
> -                                       e = fent_to_name(name, flp, fep);
> +                                       e = fent_to_name(name, fep);
>  #ifdef DEBUG
>                                         if (!e) {
>                                                 fprintf(stderr, "%d: failed to get path for entry:"
> @@ -1852,6 +1899,35 @@ zero_freq(void)
>                 p->freq = 0;
>  }
>
> +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
> +
> +opty_t btrfs_ops[] = {
> +       OP_SUBVOL_CREATE,
> +       OP_SUBVOL_DELETE,
> +};
> +
> +void
> +non_btrfs_freq(const char *path)
> +{
> +       opdesc_t                *p;
> +#ifdef HAVE_BTRFSUTIL_H
> +       enum btrfs_util_error   e;
> +
> +       e = btrfs_util_is_subvolume(path);
> +       if (e != BTRFS_UTIL_ERROR_NOT_BTRFS)
> +               return;
> +#endif
> +       for (p = ops; p < ops_end; p++) {
> +               int i;
> +               for (i = 0; i < ARRAY_SIZE(btrfs_ops); i++) {
> +                       if (p->op == btrfs_ops[i]) {
> +                               p->freq = 0;
> +                               break;
> +                       }
> +               }
> +       }
> +}
> +
>  void inode_info(char *str, size_t sz, struct stat64 *s, int verbose)
>  {
>         if (verbose)
> @@ -3103,7 +3179,7 @@ creat_f(int opno, long r)
>         v |= v1;
>         if (!e) {
>                 if (v) {
> -                       (void)fent_to_name(&f, &flist[FT_DIR], fep);
> +                       (void)fent_to_name(&f, fep);
>                         printf("%d/%d: creat - no filename from %s\n",
>                                 procid, opno, f.path);
>                 }
> @@ -3767,7 +3843,7 @@ link_f(int opno, long r)
>         v |= v1;
>         if (!e) {
>                 if (v) {
> -                       (void)fent_to_name(&l, &flist[FT_DIR], fep);
> +                       (void)fent_to_name(&l, fep);
>                         printf("%d/%d: link - no filename from %s\n",
>                                 procid, opno, l.path);
>                 }
> @@ -3858,7 +3934,7 @@ mkdir_f(int opno, long r)
>         v |= v1;
>         if (!e) {
>                 if (v) {
> -                       (void)fent_to_name(&f, &flist[FT_DIR], fep);
> +                       (void)fent_to_name(&f, fep);
>                         printf("%d/%d: mkdir - no filename from %s\n",
>                                 procid, opno, f.path);
>                 }
> @@ -3896,7 +3972,7 @@ mknod_f(int opno, long r)
>         v |= v1;
>         if (!e) {
>                 if (v) {
> -                       (void)fent_to_name(&f, &flist[FT_DIR], fep);
> +                       (void)fent_to_name(&f, fep);
>                         printf("%d/%d: mknod - no filename from %s\n",
>                                 procid, opno, f.path);
>                 }
> @@ -4364,7 +4440,7 @@ do_renameat2(int opno, long r, int mode)
>                 v |= v1;
>                 if (!e) {
>                         if (v) {
> -                               (void)fent_to_name(&f, &flist[FT_DIR], dfep);
> +                               (void)fent_to_name(&f, dfep);
>                                 printf("%d/%d: rename - no filename from %s\n",
>                                         procid, opno, f.path);
>                         }
> @@ -4378,6 +4454,7 @@ do_renameat2(int opno, long r, int mode)
>         if (e == 0) {
>                 int xattr_counter = fep->xattr_counter;
>                 bool swap = (mode == RENAME_EXCHANGE) ? true : false;
> +               int ft = flp - flist;
>
>                 oldid = fep->id;
>                 oldparid = fep->parent;
> @@ -4386,7 +4463,7 @@ do_renameat2(int opno, long r, int mode)
>                  * Swap the parent ids for RENAME_EXCHANGE, and replace the
>                  * old parent id for the others.
>                  */
> -               if (flp - flist == FT_DIR)
> +               if (ft == FT_DIR || ft == FT_SUBVOL)
>                         fix_parent(oldid, id, swap);
>
>                 if (mode == RENAME_WHITEOUT) {
> @@ -4647,6 +4724,86 @@ stat_f(int opno, long r)
>         free_pathname(&f);
>  }
>
> +void
> +subvol_create_f(int opno, long r)
> +{
> +#ifdef HAVE_BTRFSUTIL_H
> +       enum btrfs_util_error   e;
> +       pathname_t              f;
> +       fent_t                  *fep;
> +       int                     id;
> +       int                     parid;
> +       int                     v;
> +       int                     v1;
> +       int                     err;
> +
> +       init_pathname(&f);
> +       if (!get_fname(FT_DIRm | FT_SUBVOLm, r, NULL, NULL, &fep, &v))
> +               parid = -1;
> +       else
> +               parid = fep->id;
> +       err = generate_fname(fep, FT_SUBVOL, &f, &id, &v1);
> +       v |= v1;
> +       if (!err) {
> +               if (v) {
> +                       (void)fent_to_name(&f, fep);
> +                       printf("%d/%d: subvol_create - no filename from %s\n",
> +                              procid, opno, f.path);
> +               }
> +               free_pathname(&f);
> +               return;
> +       }
> +       e = btrfs_util_create_subvolume(f.path, 0, NULL, NULL);
> +       if (e == BTRFS_UTIL_OK)
> +               add_to_flist(FT_SUBVOL, id, parid, 0);
> +       if (v) {
> +               printf("%d/%d: subvol_create %s %d(%s)\n", procid, opno,
> +                      f.path, e, btrfs_util_strerror(e));
> +               printf("%d/%d: subvol_create add id=%d,parent=%d\n", procid,
> +                      opno, id, parid);
> +       }
> +       free_pathname(&f);
> +#endif
> +}
> +
> +void
> +subvol_delete_f(int opno, long r)
> +{
> +#ifdef HAVE_BTRFSUTIL_H
> +       enum btrfs_util_error   e;
> +       pathname_t              f;
> +       fent_t                  *fep;
> +       int                     v;
> +       int                     oldid;
> +       int                     oldparid;
> +
> +       init_pathname(&f);
> +       if (!get_fname(FT_SUBVOLm, r, &f, NULL, &fep, &v)) {
> +               if (v)
> +                       printf("%d:%d: subvol_delete - no subvolume\n", procid,
> +                              opno);
> +               free_pathname(&f);
> +               return;
> +       }
> +       e = btrfs_util_delete_subvolume(f.path, 0);
> +       check_cwd();
> +       if (e == BTRFS_UTIL_OK) {
> +               oldid = fep->id;
> +               oldparid = fep->parent;
> +               delete_subvol_children(oldid);
> +               del_from_flist(FT_SUBVOL, fep - flist[FT_SUBVOL].fents);
> +       }
> +       if (v) {
> +               printf("%d/%d: subvol_delete %s %d(%s)\n", procid, opno, f.path,
> +                      e, btrfs_util_strerror(e));
> +               if (e == BTRFS_UTIL_OK)
> +                       printf("%d/%d: subvol_delete del entry: id=%d,parent=%d\n",
> +                              procid, opno, oldid, oldparid);
> +       }
> +       free_pathname(&f);
> +#endif
> +}
> +
>  void
>  symlink_f(int opno, long r)
>  {
> @@ -4670,7 +4827,7 @@ symlink_f(int opno, long r)
>         v |= v1;
>         if (!e) {
>                 if (v) {
> -                       (void)fent_to_name(&f, &flist[FT_DIR], fep);
> +                       (void)fent_to_name(&f, fep);
>                         printf("%d/%d: symlink - no filename from %s\n",
>                                 procid, opno, f.path);
>                 }
> diff --git a/m4/package_libbtrfs.m4 b/m4/package_libbtrfs.m4
> new file mode 100644
> index 00000000..4822cc4a
> --- /dev/null
> +++ b/m4/package_libbtrfs.m4
> @@ -0,0 +1,5 @@
> +AC_DEFUN([AC_PACKAGE_WANT_LIBBTRFSUTIL],
> +  [ AC_CHECK_HEADERS(btrfsutil.h, [ have_libbtrfsutil=true ],
> +                     [ have_libbtrfsutil=false ])
> +    AC_SUBST(have_libbtrfsutil)
> +  ])
> --
> 2.21.0
>


-- 
Filipe David Manana,

“Whether you think you can, or you think you can't — you're right.”

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

* Re: [PATCH 2/3] fsstress: add the ability to create snapshots
  2019-11-14 15:58 ` [PATCH 2/3] fsstress: add the ability to create snapshots Josef Bacik
@ 2019-12-17 16:06   ` Filipe Manana
  0 siblings, 0 replies; 8+ messages in thread
From: Filipe Manana @ 2019-12-17 16:06 UTC (permalink / raw)
  To: Josef Bacik; +Cc: fstests, kernel-team, linux-btrfs

On Thu, Nov 14, 2019 at 3:59 PM Josef Bacik <josef@toxicpanda.com> wrote:
>
> Snapshots are just fancy subvolumes, add this ability so we can stress
> snapshot creation.  We get the deletion with SUBVOL_DELETE.
>
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>

Looks good, and it works on my test boxes.

Reviewed-by: Filipe Manana <fdmanana@suse.com>

> ---
>  ltp/fsstress.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 53 insertions(+)
>
> diff --git a/ltp/fsstress.c b/ltp/fsstress.c
> index e0636a12..f7f5f1dc 100644
> --- a/ltp/fsstress.c
> +++ b/ltp/fsstress.c
> @@ -129,6 +129,7 @@ typedef enum {
>         OP_SETATTR,
>         OP_SETFATTR,
>         OP_SETXATTR,
> +       OP_SNAPSHOT,
>         OP_SPLICE,
>         OP_STAT,
>         OP_SUBVOL_CREATE,
> @@ -255,6 +256,7 @@ void        rmdir_f(int, long);
>  void   setattr_f(int, long);
>  void   setfattr_f(int, long);
>  void   setxattr_f(int, long);
> +void   snapshot_f(int, long);
>  void   splice_f(int, long);
>  void   stat_f(int, long);
>  void   subvol_create_f(int, long);
> @@ -322,6 +324,7 @@ opdesc_t    ops[] = {
>         { OP_SETFATTR, "setfattr", setfattr_f, 2, 1 },
>         /* set project id (XFS_IOC_FSSETXATTR ioctl) */
>         { OP_SETXATTR, "setxattr", setxattr_f, 1, 1 },
> +       { OP_SNAPSHOT, "snapshot", snapshot_f, 1, 1 },
>         { OP_SPLICE, "splice", splice_f, 1, 1 },
>         { OP_STAT, "stat", stat_f, 1, 0 },
>         { OP_SUBVOL_CREATE, "subvol_create", subvol_create_f, 1, 1},
> @@ -1903,6 +1906,7 @@ zero_freq(void)
>  #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
>
>  opty_t btrfs_ops[] = {
> +       OP_SNAPSHOT,
>         OP_SUBVOL_CREATE,
>         OP_SUBVOL_DELETE,
>  };
> @@ -4703,6 +4707,55 @@ out:
>         free_pathname(&f);
>  }
>
> +void
> +snapshot_f(int opno, long r)
> +{
> +#ifdef HAVE_BTRFSUTIL_H
> +       enum btrfs_util_error   e;
> +       pathname_t              f;
> +       pathname_t              newf;
> +       fent_t                  *fep;
> +       int                     id;
> +       int                     parid;
> +       int                     v;
> +       int                     v1;
> +       int                     err;
> +
> +       init_pathname(&f);
> +       if (!get_fname(FT_SUBVOLm, r, &f, NULL, &fep, &v)) {
> +               if (v)
> +                       printf("%d/%d: snapshot - no subvolume\n", procid,
> +                              opno);
> +               free_pathname(&f);
> +               return;
> +       }
> +       init_pathname(&newf);
> +       parid = fep->id;
> +       err = generate_fname(fep, FT_SUBVOL, &newf, &id, &v1);
> +       v |= v1;
> +       if (!err) {
> +               if (v) {
> +                       (void)fent_to_name(&f, fep);
> +                       printf("%d/%d: snapshot - no filename from %s\n",
> +                              procid, opno, f.path);
> +               }
> +               free_pathname(&f);
> +               return;
> +       }
> +       e = btrfs_util_create_snapshot(f.path, newf.path, 0, NULL, NULL);
> +       if (e == BTRFS_UTIL_OK)
> +               add_to_flist(FT_SUBVOL, id, parid, 0);
> +       if (v) {
> +               printf("%d/%d: snapshot %s->%s %d(%s)\n", procid, opno,
> +                      f.path, newf.path, e, btrfs_util_strerror(e));
> +               printf("%d/%d: snapshot add id=%d,parent=%d\n", procid, opno,
> +                      id, parid);
> +       }
> +       free_pathname(&newf);
> +       free_pathname(&f);
> +#endif
> +}
> +
>  void
>  stat_f(int opno, long r)
>  {
> --
> 2.21.0
>


-- 
Filipe David Manana,

“Whether you think you can, or you think you can't — you're right.”

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

* Re: [PATCH 3/3] fsstress: allow operations to use either a directory or subvol
  2019-11-14 15:58 ` [PATCH 3/3] fsstress: allow operations to use either a directory or subvol Josef Bacik
@ 2019-12-17 16:10   ` Filipe Manana
  0 siblings, 0 replies; 8+ messages in thread
From: Filipe Manana @ 2019-12-17 16:10 UTC (permalink / raw)
  To: Josef Bacik; +Cc: fstests, kernel-team, linux-btrfs

On Thu, Nov 14, 2019 at 3:59 PM Josef Bacik <josef@toxicpanda.com> wrote:
>
> Most operations are just looking for a base directory to generate a file
> in, they don't actually need a directory specifically.  Add FT_ANYDIR to
> cover both directories and subvolumes, and then use this in all the
> places where it makes sense.
>
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>

Looks good and it works for me, thanks.

Reviewed-by: Filipe Manana <fdmanana@suse.com>

> ---
>  ltp/fsstress.c | 21 +++++++++++----------
>  1 file changed, 11 insertions(+), 10 deletions(-)
>
> diff --git a/ltp/fsstress.c b/ltp/fsstress.c
> index f7f5f1dc..30b2bd94 100644
> --- a/ltp/fsstress.c
> +++ b/ltp/fsstress.c
> @@ -200,6 +200,7 @@ struct print_string {
>  #define        FT_ANYm         ((1 << FT_nft) - 1)
>  #define        FT_REGFILE      (FT_REGm | FT_RTFm)
>  #define        FT_NOTDIR       (FT_ANYm & (~FT_DIRm & ~FT_SUBVOLm))
> +#define FT_ANYDIR      (FT_DIRm | FT_SUBVOLm)
>
>  #define        FLIST_SLOT_INCR 16
>  #define        NDCACHE 64
> @@ -3165,7 +3166,7 @@ creat_f(int opno, long r)
>         int             v;
>         int             v1;
>
> -       if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v1))
> +       if (!get_fname(FT_ANYDIR, r, NULL, NULL, &fep, &v1))
>                 parid = -1;
>         else
>                 parid = fep->id;
> @@ -3729,7 +3730,7 @@ getdents_f(int opno, long r)
>         int             v;
>
>         init_pathname(&f);
> -       if (!get_fname(FT_DIRm, r, &f, NULL, NULL, &v))
> +       if (!get_fname(FT_ANYDIR, r, &f, NULL, NULL, &v))
>                 append_pathname(&f, ".");
>         dir = opendir_path(&f);
>         check_cwd();
> @@ -3761,7 +3762,7 @@ getfattr_f(int opno, long r)
>         int             xattr_num;
>
>         init_pathname(&f);
> -       if (!get_fname(FT_REGFILE | FT_DIRm, r, &f, NULL, &fep, &v)) {
> +       if (!get_fname(FT_REGFILE | FT_ANYDIR, r, &f, NULL, &fep, &v)) {
>                 if (v)
>                         printf("%d/%d: getfattr - no filename\n", procid, opno);
>                 goto out;
> @@ -3880,7 +3881,7 @@ listfattr_f(int opno, long r)
>         int             buffer_len;
>
>         init_pathname(&f);
> -       if (!get_fname(FT_REGFILE | FT_DIRm, r, &f, NULL, &fep, &v)) {
> +       if (!get_fname(FT_REGFILE | FT_ANYDIR, r, &f, NULL, &fep, &v)) {
>                 if (v)
>                         printf("%d/%d: listfattr - no filename\n", procid, opno);
>                 goto out;
> @@ -3930,7 +3931,7 @@ mkdir_f(int opno, long r)
>         int             v;
>         int             v1;
>
> -       if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v))
> +       if (!get_fname(FT_ANYDIR, r, NULL, NULL, &fep, &v))
>                 parid = -1;
>         else
>                 parid = fep->id;
> @@ -3968,7 +3969,7 @@ mknod_f(int opno, long r)
>         int             v;
>         int             v1;
>
> -       if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v))
> +       if (!get_fname(FT_ANYDIR, r, NULL, NULL, &fep, &v))
>                 parid = -1;
>         else
>                 parid = fep->id;
> @@ -4326,7 +4327,7 @@ removefattr_f(int opno, long r)
>         int             xattr_num;
>
>         init_pathname(&f);
> -       if (!get_fname(FT_REGFILE | FT_DIRm, r, &f, NULL, &fep, &v)) {
> +       if (!get_fname(FT_REGFILE | FT_ANYDIR, r, &f, NULL, &fep, &v)) {
>                 if (v)
>                         printf("%d/%d: removefattr - no filename\n", procid, opno);
>                 goto out;
> @@ -4646,7 +4647,7 @@ setfattr_f(int opno, long r)
>         int             xattr_num;
>
>         init_pathname(&f);
> -       if (!get_fname(FT_REGFILE | FT_DIRm, r, &f, NULL, &fep, &v)) {
> +       if (!get_fname(FT_REGFILE | FT_ANYDIR, r, &f, NULL, &fep, &v)) {
>                 if (v)
>                         printf("%d/%d: setfattr - no filename\n", procid, opno);
>                 goto out;
> @@ -4792,7 +4793,7 @@ subvol_create_f(int opno, long r)
>         int                     err;
>
>         init_pathname(&f);
> -       if (!get_fname(FT_DIRm | FT_SUBVOLm, r, NULL, NULL, &fep, &v))
> +       if (!get_fname(FT_ANYDIR, r, NULL, NULL, &fep, &v))
>                 parid = -1;
>         else
>                 parid = fep->id;
> @@ -4872,7 +4873,7 @@ symlink_f(int opno, long r)
>         int             v1;
>         char            *val;
>
> -       if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v))
> +       if (!get_fname(FT_ANYDIR, r, NULL, NULL, &fep, &v))
>                 parid = -1;
>         else
>                 parid = fep->id;
> --
> 2.21.0
>


-- 
Filipe David Manana,

“Whether you think you can, or you think you can't — you're right.”

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

end of thread, other threads:[~2019-12-17 16:10 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-14 15:58 [PATCH 0/3] fsstress: add support for btrfs subvol and snapshot ops Josef Bacik
2019-11-14 15:58 ` [PATCH 1/3] fsstress: add the ability to create/delete subvolumes Josef Bacik
2019-11-14 18:14   ` [PATCH][v2] " Josef Bacik
2019-12-17 15:55     ` Filipe Manana
2019-11-14 15:58 ` [PATCH 2/3] fsstress: add the ability to create snapshots Josef Bacik
2019-12-17 16:06   ` Filipe Manana
2019-11-14 15:58 ` [PATCH 3/3] fsstress: allow operations to use either a directory or subvol Josef Bacik
2019-12-17 16:10   ` Filipe Manana

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).