On Tue, Mar 25, 2025 at 12:24:40PM +0000, fdmanana@xxxxxxxxxx wrote: > 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. This version is good to me, Reviewed-by: Zorro Lang <zlang@xxxxxxxxxx> If no more review points this week, I'll merge it this week. Thanks, Zorro > > 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 > >