[PATCH v2] generic: test fsync of file with no more hard links

[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]



From: Filipe Manana <fdmanana@xxxxxxxx>

Test that if we fsync a file that has no more hard links, power fail and
then mount the filesystem, after the journal/log is replayed, the file
doesn't exists anymore.

This exercises a bug recently found and fixed by the following patch for
the linux kernel:

   btrfs: fix fsync of files with no hard links not persisting deletion

Signed-off-by: Filipe Manana <fdmanana@xxxxxxxx>
---

V2: Use the src/multi_open_unlink.c program with added options to sync
    filesystem after creating files and fsync files after the unlink.

 src/multi_open_unlink.c | 24 ++++++++++++++++++--
 tests/generic/764       | 50 +++++++++++++++++++++++++++++++++++++++++
 tests/generic/764.out   |  2 ++
 3 files changed, 74 insertions(+), 2 deletions(-)
 create mode 100755 tests/generic/764
 create mode 100644 tests/generic/764.out

diff --git a/src/multi_open_unlink.c b/src/multi_open_unlink.c
index c221d39e..fb054e87 100644
--- a/src/multi_open_unlink.c
+++ b/src/multi_open_unlink.c
@@ -28,7 +28,7 @@
 void
 usage(char *prog)
 {
-	fprintf(stderr, "Usage: %s [-e num-eas] [-f path_prefix] [-n num_files] [-s sleep_time] [-v ea-valuesize] \n", prog);
+	fprintf(stderr, "Usage: %s [-e num-eas] [-f path_prefix] [-F] [-n num_files] [-s sleep_time] [-S] [-v ea-valuesize] \n", prog);
 	exit(1);
 }
 
@@ -44,8 +44,10 @@ main(int argc, char *argv[])
 	int value_size = MAX_VALUELEN;
 	int fd = -1;
 	int i,j,c;
+	int fsync_files = 0;
+	int sync_fs = 0;
 
-	while ((c = getopt(argc, argv, "e:f:n:s:v:")) != EOF) {
+	while ((c = getopt(argc, argv, "e:f:Fn:s:Sv:")) != EOF) {
 		switch (c) {
 			case 'e':   /* create eas */
 				num_eas = atoi(optarg);
@@ -53,12 +55,18 @@ main(int argc, char *argv[])
 			case 'f':   /* file prefix */
 				given_path = optarg;
 				break;
+			case 'F':   /* fsync files after unlink */
+				fsync_files = 1;
+				break;
 			case 'n':   /* number of files */
 				num_files = atoi(optarg);
 				break;
 			case 's':   /* sleep time */
 				sleep_time = atoi(optarg);
 				break;
+			case 'S':   /* sync fs after creating files */
+				sync_fs = 1;
+				break;
 			case 'v':  /* value size on eas */
 				value_size = atoi(optarg);
 				break;
@@ -83,6 +91,12 @@ main(int argc, char *argv[])
 			return 1;
 		}
 
+		if (sync_fs && syncfs(fd) == -1) {
+			fprintf(stderr, "%s: failed to sync filesystem: %s\n",
+				prog, strerror(errno));
+			return 1;
+		}
+
 		/* set the EAs */
 		for (j = 0; j < num_eas; j++) {
 			int sts;
@@ -111,6 +125,12 @@ main(int argc, char *argv[])
 				prog, path, strerror(errno));
 			return 1;
 		}
+
+		if (fsync_files && fsync(fd) == -1) {
+			fprintf(stderr, "%s: failed to fsync \"%s\": %s\n",
+				prog, path, strerror(errno));
+			return 1;
+		}
 	}
 
 	sleep(sleep_time);
diff --git a/tests/generic/764 b/tests/generic/764
new file mode 100755
index 00000000..1b21bc02
--- /dev/null
+++ b/tests/generic/764
@@ -0,0 +1,50 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2025 SUSE Linux Products GmbH.  All Rights Reserved.
+#
+# FS QA Test 764
+#
+# Test that if we fsync a file that has no more hard links, power fail and then
+# mount the filesystem, after the journal/log is replayed, the file doesn't
+# exists anymore.
+#
+. ./common/preamble
+_begin_fstest auto quick log
+
+_cleanup()
+{
+	_cleanup_flakey
+	cd /
+	rm -r -f $tmp.*
+}
+
+. ./common/dmflakey
+
+[ "$FSTYP" = "btrfs" ] && _fixed_by_kernel_commit xxxxxxxxxxxx \
+	"btrfs: fix fsync of files with no hard links not persisting deletion"
+
+_require_scratch
+_require_dm_target flakey
+_require_test_program "multi_open_unlink"
+
+_scratch_mkfs >>$seqres.full 2>&1 || _fail "mkfs failed"
+_require_metadata_journaling $SCRATCH_DEV
+_init_flakey
+_mount_flakey
+
+mkdir $SCRATCH_MNT/testdir
+$here/src/multi_open_unlink -f $SCRATCH_MNT/testdir/foo -F -S -n 1 -s 0
+
+# Simulate a power failure and then mount again the filesystem to replay the
+# journal/log.
+_flakey_drop_and_remount
+
+# We don't expect the file to exist anymore, since it was fsynced when it had no
+# more hard links.
+ls $SCRATCH_MNT/testdir
+
+_unmount_flakey
+
+echo "Silence is golden"
+status=0
+exit
diff --git a/tests/generic/764.out b/tests/generic/764.out
new file mode 100644
index 00000000..bb58e5b8
--- /dev/null
+++ b/tests/generic/764.out
@@ -0,0 +1,2 @@
+QA output created by 764
+Silence is golden
-- 
2.45.2





[Index of Archives]     [Linux Filesystems Development]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux