diff mbox series

[v2] generic: test fsync of directory with renamed symlink

Message ID 3f3d20ef0abcc05ebfb6bc4aaa97261598611e49.1652106518.git.fdmanana@suse.com (mailing list archive)
State New, archived
Headers show
Series [v2] generic: test fsync of directory with renamed symlink | expand

Commit Message

Filipe Manana May 9, 2022, 2:31 p.m. UTC
From: Filipe Manana <fdmanana@suse.com>

Test that if we fsync a directory, create a symlink inside it, rename
the symlink, fsync again the directory and then power fail, after the
filesystem is mounted again, the symlink exists with the new name and
it has the correct content.

This currently fails on btrfs, because the symlink ends up empty (which
is illegal on Linux), but it is fixed by kernel commit:

    d0e64a981fd841 ("btrfs: always log symlinks in full mode")

Reviewed-by: David Disseldorp <ddiss@suse.de>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
---

v2: Rebased on latest for-next, quoted $SCRATCH_MNT references (David Disseldorp)
    and added David's review tag.

 tests/generic/690     | 90 +++++++++++++++++++++++++++++++++++++++++++
 tests/generic/690.out |  2 +
 2 files changed, 92 insertions(+)
 create mode 100755 tests/generic/690
 create mode 100644 tests/generic/690.out

Comments

Zorro Lang May 9, 2022, 3:31 p.m. UTC | #1
On Mon, May 09, 2022 at 03:31:02PM +0100, fdmanana@kernel.org wrote:
> From: Filipe Manana <fdmanana@suse.com>
> 
> Test that if we fsync a directory, create a symlink inside it, rename
> the symlink, fsync again the directory and then power fail, after the
> filesystem is mounted again, the symlink exists with the new name and
> it has the correct content.
> 
> This currently fails on btrfs, because the symlink ends up empty (which
> is illegal on Linux), but it is fixed by kernel commit:
> 
>     d0e64a981fd841 ("btrfs: always log symlinks in full mode")
> 
> Reviewed-by: David Disseldorp <ddiss@suse.de>
> Signed-off-by: Filipe Manana <fdmanana@suse.com>
> ---
> 
> v2: Rebased on latest for-next, quoted $SCRATCH_MNT references (David Disseldorp)
>     and added David's review tag.

This case is nearly copied from generic/066, so there's not debatable things
from code format. It's in my local testing branch now, and will be pushed in
next release, after regression test done. Thanks for this new test.

Zorro

> 
>  tests/generic/690     | 90 +++++++++++++++++++++++++++++++++++++++++++
>  tests/generic/690.out |  2 +
>  2 files changed, 92 insertions(+)
>  create mode 100755 tests/generic/690
>  create mode 100644 tests/generic/690.out
> 
> diff --git a/tests/generic/690 b/tests/generic/690
> new file mode 100755
> index 00000000..f03295a5
> --- /dev/null
> +++ b/tests/generic/690
> @@ -0,0 +1,90 @@
> +#! /bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (c) 2022 SUSE Linux Products GmbH.  All Rights Reserved.
> +#
> +# FS QA Test 690
> +#
> +# Test that if we fsync a directory, create a symlink inside it, rename the
> +# symlink, fsync again the directory and then power fail, after the filesystem
> +# is mounted again, the symlink exists with the new name and it has the correct
> +# content.
> +#
> +# On btrfs this used to result in the symlink being empty (i_size 0), and it was
> +# fixed by kernel commit:
> +#
> +#    d0e64a981fd841 ("btrfs: always log symlinks in full mode")
> +#
> +. ./common/preamble
> +_begin_fstest auto quick log
> +
> +_cleanup()
> +{
> +	_cleanup_flakey
> +	cd /
> +	rm -r -f $tmp.*
> +}
> +
> +. ./common/rc
> +. ./common/filter
> +. ./common/dmflakey
> +
> +# real QA test starts here
> +
> +_supported_fs generic
> +_require_scratch
> +_require_symlinks
> +_require_dm_target flakey
> +
> +rm -f $seqres.full
> +
> +# f2fs doesn't support fs-op level transaction functionality, so it has no way
> +# to persist all metadata updates in one transaction. We have to use its mount
> +# option "fastboot" so that it triggers a metadata checkpoint to persist all
> +# metadata updates that happen before a fsync call. Without this, after the
> +# last fsync in the test, the symlink named "baz" will not exist.
> +if [ $FSTYP = "f2fs" ]; then
> +	export MOUNT_OPTIONS="-o fastboot $MOUNT_OPTIONS"
> +fi
> +
> +_scratch_mkfs >>$seqres.full 2>&1
> +_require_metadata_journaling $SCRATCH_DEV
> +_init_flakey
> +_mount_flakey
> +
> +# Create our test directory.
> +mkdir "$SCRATCH_MNT"/testdir
> +
> +# Commit the current transaction and persist the directory.
> +sync
> +
> +# Create a file in the test directory, so that the next fsync on the directory
> +# actually does something (it logs the directory).
> +echo -n > "$SCRATCH_MNT"/testdir/foo
> +
> +# Fsync the directory.
> +$XFS_IO_PROG -c "fsync" "$SCRATCH_MNT"/testdir
> +
> +# Now create a symlink inside the test directory.
> +ln -s "$SCRATCH_MNT"/testdir/foo "$SCRATCH_MNT"/testdir/bar
> +
> +# Rename the symlink.
> +mv "$SCRATCH_MNT"/testdir/bar "$SCRATCH_MNT"/testdir/baz
> +
> +# Fsync again the directory.
> +$XFS_IO_PROG -c "fsync" "$SCRATCH_MNT"/testdir
> +
> +# Simulate a power failure and then mount again the filesystem to replay the
> +# journal/log.
> +_flakey_drop_and_remount
> +
> +# The symlink should exist, with the name "baz" and its content must be
> +# "$SCRATCH_MNT/testdir/foo".
> +[ -L "$SCRATCH_MNT"/testdir/baz ] || echo "symlink 'baz' is missing"
> +symlink_content=$(readlink "$SCRATCH_MNT"/testdir/baz | _filter_scratch)
> +echo "symlink content: ${symlink_content}"
> +
> +_unmount_flakey
> +
> +# success, all done
> +status=0
> +exit
> diff --git a/tests/generic/690.out b/tests/generic/690.out
> new file mode 100644
> index 00000000..84be1247
> --- /dev/null
> +++ b/tests/generic/690.out
> @@ -0,0 +1,2 @@
> +QA output created by 690
> +symlink content: SCRATCH_MNT/testdir/foo
> -- 
> 2.35.1
>
Filipe Manana May 9, 2022, 3:37 p.m. UTC | #2
On Mon, May 09, 2022 at 11:31:58PM +0800, Zorro Lang wrote:
> On Mon, May 09, 2022 at 03:31:02PM +0100, fdmanana@kernel.org wrote:
> > From: Filipe Manana <fdmanana@suse.com>
> > 
> > Test that if we fsync a directory, create a symlink inside it, rename
> > the symlink, fsync again the directory and then power fail, after the
> > filesystem is mounted again, the symlink exists with the new name and
> > it has the correct content.
> > 
> > This currently fails on btrfs, because the symlink ends up empty (which
> > is illegal on Linux), but it is fixed by kernel commit:
> > 
> >     d0e64a981fd841 ("btrfs: always log symlinks in full mode")
> > 
> > Reviewed-by: David Disseldorp <ddiss@suse.de>
> > Signed-off-by: Filipe Manana <fdmanana@suse.com>
> > ---
> > 
> > v2: Rebased on latest for-next, quoted $SCRATCH_MNT references (David Disseldorp)
> >     and added David's review tag.
> 
> This case is nearly copied from generic/066, so there's not debatable things

I think you mean the part of setting the special mount option for f2fs, right?

Because otherwise 066 is very different (testing xattrs and not symlink stuff).

> from code format. It's in my local testing branch now, and will be pushed in
> next release, after regression test done. Thanks for this new test.

Thanks!

> 
> Zorro
> 
> > 
> >  tests/generic/690     | 90 +++++++++++++++++++++++++++++++++++++++++++
> >  tests/generic/690.out |  2 +
> >  2 files changed, 92 insertions(+)
> >  create mode 100755 tests/generic/690
> >  create mode 100644 tests/generic/690.out
> > 
> > diff --git a/tests/generic/690 b/tests/generic/690
> > new file mode 100755
> > index 00000000..f03295a5
> > --- /dev/null
> > +++ b/tests/generic/690
> > @@ -0,0 +1,90 @@
> > +#! /bin/bash
> > +# SPDX-License-Identifier: GPL-2.0
> > +# Copyright (c) 2022 SUSE Linux Products GmbH.  All Rights Reserved.
> > +#
> > +# FS QA Test 690
> > +#
> > +# Test that if we fsync a directory, create a symlink inside it, rename the
> > +# symlink, fsync again the directory and then power fail, after the filesystem
> > +# is mounted again, the symlink exists with the new name and it has the correct
> > +# content.
> > +#
> > +# On btrfs this used to result in the symlink being empty (i_size 0), and it was
> > +# fixed by kernel commit:
> > +#
> > +#    d0e64a981fd841 ("btrfs: always log symlinks in full mode")
> > +#
> > +. ./common/preamble
> > +_begin_fstest auto quick log
> > +
> > +_cleanup()
> > +{
> > +	_cleanup_flakey
> > +	cd /
> > +	rm -r -f $tmp.*
> > +}
> > +
> > +. ./common/rc
> > +. ./common/filter
> > +. ./common/dmflakey
> > +
> > +# real QA test starts here
> > +
> > +_supported_fs generic
> > +_require_scratch
> > +_require_symlinks
> > +_require_dm_target flakey
> > +
> > +rm -f $seqres.full
> > +
> > +# f2fs doesn't support fs-op level transaction functionality, so it has no way
> > +# to persist all metadata updates in one transaction. We have to use its mount
> > +# option "fastboot" so that it triggers a metadata checkpoint to persist all
> > +# metadata updates that happen before a fsync call. Without this, after the
> > +# last fsync in the test, the symlink named "baz" will not exist.
> > +if [ $FSTYP = "f2fs" ]; then
> > +	export MOUNT_OPTIONS="-o fastboot $MOUNT_OPTIONS"
> > +fi
> > +
> > +_scratch_mkfs >>$seqres.full 2>&1
> > +_require_metadata_journaling $SCRATCH_DEV
> > +_init_flakey
> > +_mount_flakey
> > +
> > +# Create our test directory.
> > +mkdir "$SCRATCH_MNT"/testdir
> > +
> > +# Commit the current transaction and persist the directory.
> > +sync
> > +
> > +# Create a file in the test directory, so that the next fsync on the directory
> > +# actually does something (it logs the directory).
> > +echo -n > "$SCRATCH_MNT"/testdir/foo
> > +
> > +# Fsync the directory.
> > +$XFS_IO_PROG -c "fsync" "$SCRATCH_MNT"/testdir
> > +
> > +# Now create a symlink inside the test directory.
> > +ln -s "$SCRATCH_MNT"/testdir/foo "$SCRATCH_MNT"/testdir/bar
> > +
> > +# Rename the symlink.
> > +mv "$SCRATCH_MNT"/testdir/bar "$SCRATCH_MNT"/testdir/baz
> > +
> > +# Fsync again the directory.
> > +$XFS_IO_PROG -c "fsync" "$SCRATCH_MNT"/testdir
> > +
> > +# Simulate a power failure and then mount again the filesystem to replay the
> > +# journal/log.
> > +_flakey_drop_and_remount
> > +
> > +# The symlink should exist, with the name "baz" and its content must be
> > +# "$SCRATCH_MNT/testdir/foo".
> > +[ -L "$SCRATCH_MNT"/testdir/baz ] || echo "symlink 'baz' is missing"
> > +symlink_content=$(readlink "$SCRATCH_MNT"/testdir/baz | _filter_scratch)
> > +echo "symlink content: ${symlink_content}"
> > +
> > +_unmount_flakey
> > +
> > +# success, all done
> > +status=0
> > +exit
> > diff --git a/tests/generic/690.out b/tests/generic/690.out
> > new file mode 100644
> > index 00000000..84be1247
> > --- /dev/null
> > +++ b/tests/generic/690.out
> > @@ -0,0 +1,2 @@
> > +QA output created by 690
> > +symlink content: SCRATCH_MNT/testdir/foo
> > -- 
> > 2.35.1
> >
diff mbox series

Patch

diff --git a/tests/generic/690 b/tests/generic/690
new file mode 100755
index 00000000..f03295a5
--- /dev/null
+++ b/tests/generic/690
@@ -0,0 +1,90 @@ 
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2022 SUSE Linux Products GmbH.  All Rights Reserved.
+#
+# FS QA Test 690
+#
+# Test that if we fsync a directory, create a symlink inside it, rename the
+# symlink, fsync again the directory and then power fail, after the filesystem
+# is mounted again, the symlink exists with the new name and it has the correct
+# content.
+#
+# On btrfs this used to result in the symlink being empty (i_size 0), and it was
+# fixed by kernel commit:
+#
+#    d0e64a981fd841 ("btrfs: always log symlinks in full mode")
+#
+. ./common/preamble
+_begin_fstest auto quick log
+
+_cleanup()
+{
+	_cleanup_flakey
+	cd /
+	rm -r -f $tmp.*
+}
+
+. ./common/rc
+. ./common/filter
+. ./common/dmflakey
+
+# real QA test starts here
+
+_supported_fs generic
+_require_scratch
+_require_symlinks
+_require_dm_target flakey
+
+rm -f $seqres.full
+
+# f2fs doesn't support fs-op level transaction functionality, so it has no way
+# to persist all metadata updates in one transaction. We have to use its mount
+# option "fastboot" so that it triggers a metadata checkpoint to persist all
+# metadata updates that happen before a fsync call. Without this, after the
+# last fsync in the test, the symlink named "baz" will not exist.
+if [ $FSTYP = "f2fs" ]; then
+	export MOUNT_OPTIONS="-o fastboot $MOUNT_OPTIONS"
+fi
+
+_scratch_mkfs >>$seqres.full 2>&1
+_require_metadata_journaling $SCRATCH_DEV
+_init_flakey
+_mount_flakey
+
+# Create our test directory.
+mkdir "$SCRATCH_MNT"/testdir
+
+# Commit the current transaction and persist the directory.
+sync
+
+# Create a file in the test directory, so that the next fsync on the directory
+# actually does something (it logs the directory).
+echo -n > "$SCRATCH_MNT"/testdir/foo
+
+# Fsync the directory.
+$XFS_IO_PROG -c "fsync" "$SCRATCH_MNT"/testdir
+
+# Now create a symlink inside the test directory.
+ln -s "$SCRATCH_MNT"/testdir/foo "$SCRATCH_MNT"/testdir/bar
+
+# Rename the symlink.
+mv "$SCRATCH_MNT"/testdir/bar "$SCRATCH_MNT"/testdir/baz
+
+# Fsync again the directory.
+$XFS_IO_PROG -c "fsync" "$SCRATCH_MNT"/testdir
+
+# Simulate a power failure and then mount again the filesystem to replay the
+# journal/log.
+_flakey_drop_and_remount
+
+# The symlink should exist, with the name "baz" and its content must be
+# "$SCRATCH_MNT/testdir/foo".
+[ -L "$SCRATCH_MNT"/testdir/baz ] || echo "symlink 'baz' is missing"
+symlink_content=$(readlink "$SCRATCH_MNT"/testdir/baz | _filter_scratch)
+echo "symlink content: ${symlink_content}"
+
+_unmount_flakey
+
+# success, all done
+status=0
+exit
diff --git a/tests/generic/690.out b/tests/generic/690.out
new file mode 100644
index 00000000..84be1247
--- /dev/null
+++ b/tests/generic/690.out
@@ -0,0 +1,2 @@ 
+QA output created by 690
+symlink content: SCRATCH_MNT/testdir/foo