blob: a9346d5b36d3a3ee8d3cbe45a394e578e7fc7a83 [file] [log] [blame]
#! /bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (C) 2021 SUSE Linux Products GmbH. All Rights Reserved.
#
# FSQA Test No. 640
#
# Test that if we fsync a directory A, evict A's inode, move one file from
# directory A to a directory B, fsync some other inode that is not directory A,
# B or any inode inside these two directories, and then power fail, the file
# that was moved is not lost.
#
. ./common/preamble
_begin_fstest auto quick log
# Override the default cleanup function.
_cleanup()
{
_cleanup_flakey
cd /
rm -f $tmp.*
}
# Import common functions.
. ./common/filter
. ./common/dmflakey
# real QA test starts here
_supported_fs generic
_require_scratch
_require_dm_target flakey
_scratch_mkfs >>$seqres.full 2>&1
_require_metadata_journaling $SCRATCH_DEV
_init_flakey
_mount_flakey
# Create two test directories, one with a file we will rename later.
mkdir $SCRATCH_MNT/A
mkdir $SCRATCH_MNT/B
echo -n "hello world" > $SCRATCH_MNT/A/foo
# Persist everything done so far.
sync
# Add some new file to directory A and fsync the directory.
touch $SCRATCH_MNT/A/bar
$XFS_IO_PROG -c "fsync" $SCRATCH_MNT/A
# Now evict all inodes from memory. To trigger the original problem on btrfs we
# actually only needed to trigger eviction of A's inode, but there's no simple
# way to evict a single inode, so evict everything.
echo 2 > /proc/sys/vm/drop_caches
# Now move file foo from directory A to directory B.
mv $SCRATCH_MNT/A/foo $SCRATCH_MNT/B/foo
# Now make an fsync to anything except A, B or any file inside them, like for
# example create a file at the root directory and fsync this new file.
touch $SCRATCH_MNT/baz
$XFS_IO_PROG -c "fsync" $SCRATCH_MNT/baz
# Simulate a power failure and then check file foo still exists.
_flakey_drop_and_remount
# Since file foo was not explicitly fsynced we can not guarantee that, for every
# filesystem, after replaying the journal/log we have file foo inside directory A
# or inside directory B. The file must exist however, and can only be found in
# one of the directories, not on both.
#
# At the moment of this writing, on f2fs file foo exists always at A/foo,
# regardless of the fsync-mode mount option ("-o fsync_mode=posix" or
# "-o fsync_mode=strict"). On ext4 and xfs it exists at B/foo. It is also
# supposed to exist at B/foo on btrfs (at the moment it doesn't exist in
# either directory due to a bug).
foo_in_a=0
foo_in_b=0
if [ -f $SCRATCH_MNT/A/foo ]; then
echo "File foo data: $(cat $SCRATCH_MNT/A/foo)"
foo_in_a=1
fi
if [ -f $SCRATCH_MNT/B/foo ]; then
echo "File foo data: $(cat $SCRATCH_MNT/B/foo)"
foo_in_b=1
fi
if [ $foo_in_a -eq 1 ] && [ $foo_in_b -eq 1 ]; then
echo "File foo found in A/ and B/"
elif [ $foo_in_a -eq 0 ] && [ $foo_in_b -eq 0 ]; then
echo "File foo is missing"
fi
# While here, also check that files bar and baz exist.
[ -f $SCRATCH_MNT/A/bar ] || echo "File A/bar is missing"
[ -f $SCRATCH_MNT/baz ] || echo "File baz is missing"
_unmount_flakey
status=0
exit