025e1b0fe7a6c95d6e28a7af4577b8eaf2627831
[xfstests-dev.git] / tests / generic / 038
1 #! /bin/bash
2 # FSQA Test No. 038
3 #
4 # This test was motivated by btrfs issues, but it's generic enough as it
5 # doesn't use any btrfs specific features.
6 #
7 # Stress btrfs' block group allocation and deallocation while running fstrim in
8 # parallel. Part of the goal is also to get data block groups deallocated so
9 # that new metadata block groups, using the same physical device space ranges,
10 # get allocated while fstrim is running. This caused several issues ranging
11 # from invalid memory accesses, kernel crashes, metadata or data corruption,
12 # free space cache inconsistencies, free space leaks and memory leaks.
13 #
14 # These issues were fixed by the following btrfs linux kernel patches:
15 #
16 #   Btrfs: fix invalid block group rbtree access after bg is removed
17 #   Btrfs: fix crash caused by block group removal
18 #   Btrfs: fix freeing used extents after removing empty block group
19 #   Btrfs: fix race between fs trimming and block group remove/allocation
20 #   Btrfs: fix race between writing free space cache and trimming
21 #   Btrfs: make btrfs_abort_transaction consider existence of new block groups
22 #   Btrfs: fix memory leak after block remove + trimming
23 #   Btrfs: fix fs mapping extent map leak
24 #   Btrfs: fix unprotected deletion from pending_chunks list
25 #
26 # The issues were found on a qemu/kvm guest with 4 virtual CPUs, 4Gb of ram and
27 # scsi-hd devices with discard support enabled (that means hole punching in the
28 # disk's image file is performed by the host).
29 #
30 #-----------------------------------------------------------------------
31 #
32 # Copyright (C) 2014 SUSE Linux Products GmbH. All Rights Reserved.
33 # Author: Filipe Manana <fdmanana@suse.com>
34 #
35 # This program is free software; you can redistribute it and/or
36 # modify it under the terms of the GNU General Public License as
37 # published by the Free Software Foundation.
38 #
39 # This program is distributed in the hope that it would be useful,
40 # but WITHOUT ANY WARRANTY; without even the implied warranty of
41 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
42 # GNU General Public License for more details.
43 #
44 # You should have received a copy of the GNU General Public License
45 # along with this program; if not, write the Free Software Foundation,
46 # Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
47 #-----------------------------------------------------------------------
48 #
49
50 seq=`basename $0`
51 seqres=$RESULT_DIR/$seq
52 echo "QA output created by $seq"
53
54 tmp=/tmp/$$
55 status=1        # failure is the default!
56 trap "_cleanup; exit \$status" 0 1 2 3 15
57
58 _cleanup()
59 {
60         rm -fr $tmp
61 }
62
63 # get standard environment, filters and checks
64 . ./common/rc
65 . ./common/filter
66
67 # real QA test starts here
68 _supported_fs generic
69 _supported_os Linux
70 _require_scratch
71 _require_xfs_io_command "falloc"
72
73 rm -f $seqres.full
74
75 # Keep allocating and deallocating 1G of data space with the goal of creating
76 # and deleting 1 block group constantly. The intention is to race with the
77 # fstrim loop below.
78 fallocate_loop()
79 {
80         # Wait for running subcommand before exitting so that
81         # mountpoint is not busy when we try to unmount it
82         trap "wait; exit" SIGTERM
83
84         local name=$1
85         while true; do
86                 $XFS_IO_PROG -f -c "falloc -k 0 1G" \
87                         $SCRATCH_MNT/$name &> /dev/null
88                 sleep 3
89                 $XFS_IO_PROG -c "truncate 0" \
90                         $SCRATCH_MNT/$name &> /dev/null
91                 sleep 3
92         done
93 }
94
95 trim_loop()
96 {
97         # Wait for running subcommand before exitting so that
98         # mountpoint is not busy when we try to unmount it
99         trap "wait; exit" SIGTERM
100
101         while true; do
102                 $FSTRIM_PROG $SCRATCH_MNT
103         done
104 }
105
106 # Create a bunch of small files that get their single extent inlined in the
107 # btree, so that we consume a lot of metadata space and get a chance of a
108 # data block group getting deleted and reused for metadata later. Sometimes
109 # the creation of all these files succeeds other times we get ENOSPC failures
110 # at some point - this depends on how fast the btrfs' cleaner kthread is
111 # notified about empty block groups, how fast it deletes them and how fast
112 # the fallocate calls happen. So we don't really care if they all succeed or
113 # not, the goal is just to keep metadata space usage growing while data block
114 # groups are deleted.
115 #
116 # Creating 200,000 files sequentially is really slow, so speed it up a bit
117 # by doing it concurrently with 4 threads in 4 separate directories.
118 nr_files=$((50000 * LOAD_FACTOR))
119 create_files()
120 {
121         local prefix=$1
122
123         for ((n = 0; n < 4; n++)); do
124                 mkdir $SCRATCH_MNT/$n
125                 (
126                 trap "wait; exit" SIGTERM
127
128                 for ((i = 1; i <= $nr_files; i++)); do
129                         $XFS_IO_PROG -f -c "pwrite -S 0xaa 0 3900" \
130                                 $SCRATCH_MNT/$n/"${prefix}_$i" &> /dev/null
131                         if [ $? -ne 0 ]; then
132                                 echo "Failed creating file $n/${prefix}_$i" >>$seqres.full
133                                 break
134                         fi
135                 done
136                 ) &
137                 create_pids[$n]=$!
138         done
139
140         wait ${create_pids[@]}
141
142 }
143
144 _scratch_mkfs >>$seqres.full 2>&1
145 _scratch_mount
146 _require_fs_space $SCRATCH_MNT $((10 * 1024 * 1024))
147 _require_batched_discard $SCRATCH_MNT
148
149 for ((i = 0; i < $((4 * $LOAD_FACTOR)); i++)); do
150         trim_loop &
151         trim_pids[$i]=$!
152 done
153
154 for ((i = 0; i < $((1 * $LOAD_FACTOR)); i++)); do
155         fallocate_loop "falloc_file_$i" &
156         fallocate_pids[$i]=$!
157 done
158
159 create_files "foobar"
160
161 kill ${fallocate_pids[@]}
162 kill ${trim_pids[@]}
163 wait
164
165 # The fstests framework will now check for fs consistency with fsck.
166 # The trimming was racy and caused some btree nodes to get full of zeroes on
167 # disk, which obviously caused fs metadata corruption. The race often lead
168 # to missing free space entries in a block group's free space cache too.
169
170 echo "Silence is golden"
171 status=0
172 exit