generic: test for file loss after mix of rename, fsync and inode eviction
[xfstests-dev.git] / tests / generic / 640
1 #! /bin/bash
2 # SPDX-License-Identifier: GPL-2.0
3 # Copyright (C) 2021 SUSE Linux Products GmbH. All Rights Reserved.
4 #
5 # FSQA Test No. 640
6 #
7 # Test that if we fsync a directory A, evict A's inode, move one file from
8 # directory A to a directory B, fsync some other inode that is not directory A,
9 # B or any inode inside these two directories, and then power fail, the file
10 # that was moved is not lost.
11 #
12 . ./common/preamble
13 _begin_fstest auto quick log
14
15 # Override the default cleanup function.
16 _cleanup()
17 {
18         _cleanup_flakey
19         cd /
20         rm -f $tmp.*
21 }
22
23 # Import common functions.
24 . ./common/filter
25 . ./common/dmflakey
26
27 # real QA test starts here
28 _supported_fs generic
29 _require_scratch
30 _require_dm_target flakey
31
32 _scratch_mkfs >>$seqres.full 2>&1
33 _require_metadata_journaling $SCRATCH_DEV
34 _init_flakey
35 _mount_flakey
36
37 # Create two test directories, one with a file we will rename later.
38 mkdir $SCRATCH_MNT/A
39 mkdir $SCRATCH_MNT/B
40 echo -n "hello world" > $SCRATCH_MNT/A/foo
41
42 # Persist everything done so far.
43 sync
44
45 # Add some new file to directory A and fsync the directory.
46 touch $SCRATCH_MNT/A/bar
47 $XFS_IO_PROG -c "fsync" $SCRATCH_MNT/A
48
49 # Now evict all inodes from memory. To trigger the original problem on btrfs we
50 # actually only needed to trigger eviction of A's inode, but there's no simple
51 # way to evict a single inode, so evict everything.
52 echo 2 > /proc/sys/vm/drop_caches
53
54 # Now move file foo from directory A to directory B.
55 mv $SCRATCH_MNT/A/foo $SCRATCH_MNT/B/foo
56
57 # Now make an fsync to anything except A, B or any file inside them, like for
58 # example create a file at the root directory and fsync this new file.
59 touch $SCRATCH_MNT/baz
60 $XFS_IO_PROG -c "fsync" $SCRATCH_MNT/baz
61
62 # Simulate a power failure and then check file foo still exists.
63 _flakey_drop_and_remount
64
65 # Since file foo was not explicitly fsynced we can not guarantee that, for every
66 # filesystem, after replaying the journal/log we have file foo inside directory A
67 # or inside directory B. The file must exist however, and can only be found in
68 # one of the directories, not on both.
69 #
70 # At the moment of this writing, on f2fs file foo exists always at A/foo,
71 # regardless of the fsync-mode mount option ("-o fsync_mode=posix" or
72 # "-o fsync_mode=strict"). On ext4 and xfs it exists at B/foo. It is also
73 # supposed to exist at B/foo on btrfs (at the moment it doesn't exist in
74 # either directory due to a bug).
75
76 foo_in_a=0
77 foo_in_b=0
78
79 if [ -f $SCRATCH_MNT/A/foo ]; then
80         echo "File foo data: $(cat $SCRATCH_MNT/A/foo)"
81         foo_in_a=1
82 fi
83
84 if [ -f $SCRATCH_MNT/B/foo ]; then
85         echo "File foo data: $(cat $SCRATCH_MNT/B/foo)"
86         foo_in_b=1
87 fi
88
89 if [ $foo_in_a -eq 1 ] && [ $foo_in_b -eq 1 ]; then
90         echo "File foo found in A/ and B/"
91 elif [ $foo_in_a -eq 0 ] && [ $foo_in_b -eq 0 ]; then
92         echo "File foo is missing"
93 fi
94
95 # While here, also check that files bar and baz exist.
96 [ -f $SCRATCH_MNT/A/bar ] || echo "File A/bar is missing"
97 [ -f $SCRATCH_MNT/baz ] || echo "File baz is missing"
98
99 _unmount_flakey
100 status=0
101 exit