7e90e00412777d7d8ff616322966d7b1728fa7c6
[xfstests-dev.git] / tests / generic / 040
1 #! /bin/bash
2 # FS QA Test No. 040
3 #
4 # This test is motivated by an fsync issue discovered in btrfs.
5 # The issue in btrfs was that adding a new hard link to an inode that already
6 # had a large number of hardlinks and fsync the inode, would make the fsync
7 # log replay code update the inode with a wrong link count (smaller than the
8 # correct value). This resulted later in dangling directory index entries,
9 # after removing most of the hard links (correct_value - wrong_value), that
10 # were visible to user space but it was impossible to delete them or do
11 # any other operation on them (since they pointed to an inode that didn't
12 # exist anymore, resulting in -ESTALE errors).
13 #
14 # The btrfs issue was fixed by the following linux kernel patch:
15 #
16 #    Btrfs: fix fsync when extend references are added to an inode
17 #
18 # This issue was present in btrfs since the extrefs (extend references)
19 # feature was added (2012).
20 #
21 #-----------------------------------------------------------------------
22 # Copyright (C) 2015 SUSE Linux Products GmbH. All Rights Reserved.
23 # Author: Filipe Manana <fdmanana@suse.com>
24 #
25 # This program is free software; you can redistribute it and/or
26 # modify it under the terms of the GNU General Public License as
27 # published by the Free Software Foundation.
28 #
29 # This program is distributed in the hope that it would be useful,
30 # but WITHOUT ANY WARRANTY; without even the implied warranty of
31 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
32 # GNU General Public License for more details.
33 #
34 # You should have received a copy of the GNU General Public License
35 # along with this program; if not, write the Free Software Foundation,
36 # Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
37 #-----------------------------------------------------------------------
38 #
39
40 seq=`basename $0`
41 seqres=$RESULT_DIR/$seq
42 echo "QA output created by $seq"
43
44 here=`pwd`
45 tmp=/tmp/$$
46 status=1        # failure is the default!
47
48 _cleanup()
49 {
50         _cleanup_flakey
51 }
52 trap "_cleanup; exit \$status" 0 1 2 3 15
53
54 # get standard environment, filters and checks
55 . ./common/rc
56 . ./common/filter
57 . ./common/dmflakey
58
59 # real QA test starts here
60 _supported_fs generic
61 _supported_os Linux
62 _need_to_be_root
63 _require_scratch
64 _require_dm_target flakey
65 _require_metadata_journaling $SCRATCH_DEV
66
67 rm -f $seqres.full
68
69 # If the test filesystem is btrfs, make sure we create a filesystem with
70 # the extend references (extrefs) feature enabled (it's enabled by default
71 # in recent versions of btrfs-progs).
72 if [ "$FSTYP" = "btrfs" ]; then
73         _scratch_mkfs "-O extref" >> $seqres.full 2>&1
74 else
75         _scratch_mkfs >> $seqres.full 2>&1
76 fi
77
78 _init_flakey
79 _mount_flakey
80
81 # Create a test file with 3001 hard links. This number is large enough to
82 # make btrfs start using extrefs at some point even if the fs has the maximum
83 # possible leaf/node size (64Kb).
84 echo "hello world" > $SCRATCH_MNT/foo
85 for i in `seq 1 3000`; do
86         ln $SCRATCH_MNT/foo $SCRATCH_MNT/foo_link_`printf "%04d" $i`
87 done
88
89 # Make sure all metadata and data are durably persisted.
90 sync
91
92 # Add one more link to the inode that ends up being a btrfs extref and fsync
93 # the inode.
94 ln $SCRATCH_MNT/foo $SCRATCH_MNT/foo_link_3001
95 $XFS_IO_PROG -c "fsync" $SCRATCH_MNT/foo
96
97 _flakey_drop_and_remount
98
99 # Now after the fsync log replay btrfs left our inode with a wrong link count N,
100 # which was smaller than the correct link count M (N < M).
101 # So after removing N hard links, the remaining M - N directory entries were
102 # still visible to user space but it was impossible to do anything with them
103 # because they pointed to an inode that didn't exist anymore. This resulted in
104 # stale file handle errors (-ESTALE) when accessing those dentries for example.
105 #
106 # So remove all hard links except the first one and then attempt to read the
107 # file, to verify we don't get an -ESTALE error when accessing the inode.
108 #
109 # The btrfs fsck tool also detected the incorrect inode link count and it
110 # reported an error message like the following:
111 #
112 # root 5 inode 257 errors 2001, no inode item, link count wrong
113 #   unresolved ref dir 256 index 2978 namelen 13 name foo_link_2976 filetype 1 errors 4, no inode ref
114 #
115 # The fstests framework automatically calls fsck after a test is run, so we
116 # don't need to call fsck explicitly here.
117
118 echo "Link count before rm foo_link_*: $(stat -c %h $SCRATCH_MNT/foo)"
119 rm -f $SCRATCH_MNT/foo_link_*
120 echo "Link count after rm foo_link_*: $(stat -c %h $SCRATCH_MNT/foo)"
121 cat $SCRATCH_MNT/foo
122
123 status=0
124 exit