common/fuzzy: try to clear blocking flags first in _scratch_fuzz_modify
[xfstests-dev.git] / tests / btrfs / 103
1 #! /bin/bash
2 # SPDX-License-Identifier: GPL-2.0
3 # Copyright (C) 2015 SUSE Linux Products GmbH. All Rights Reserved.
4 #
5 # FSQA Test No. 103
6 #
7 # Regression test for file read corruption when using compressed extents that
8 # are shared by multiple consecutive ranges of the same file.
9 #
10 seq=`basename $0`
11 seqres=$RESULT_DIR/$seq
12 echo "QA output created by $seq"
13 tmp=/tmp/$$
14 status=1        # failure is the default!
15 trap "_cleanup; exit \$status" 0 1 2 3 15
16
17 _cleanup()
18 {
19         rm -f $tmp.*
20 }
21
22 # get standard environment, filters and checks
23 . ./common/rc
24 . ./common/filter
25
26 # real QA test starts here
27 _supported_fs btrfs
28 _supported_os Linux
29 _require_scratch
30 _require_cloner
31
32 rm -f $seqres.full
33
34 test_clone_and_read_compressed_extent()
35 {
36         local mount_opts=$1
37
38         _scratch_mkfs >>$seqres.full 2>&1
39         _scratch_mount $mount_opts
40
41         BLOCK_SIZE=$(_get_block_size $SCRATCH_MNT)
42
43         # Create a test file with a single extent that is compressed (the
44         # data we write into it is highly compressible no matter which
45         # compression algorithm is used, zlib or lzo).
46         $XFS_IO_PROG -f -c "pwrite -S 0xaa 0K $((1 * $BLOCK_SIZE))" \
47                 -c "pwrite -S 0xbb $((1 * $BLOCK_SIZE)) $((2 * $BLOCK_SIZE))" \
48                 -c "pwrite -S 0xcc $((3 * $BLOCK_SIZE)) $((1 * $BLOCK_SIZE))" \
49                 $SCRATCH_MNT/foo | _filter_xfs_io_blocks_modified
50
51
52         # Now clone our extent into an adjacent offset.
53         $CLONER_PROG -s $((1 * $BLOCK_SIZE)) -d $((4 * $BLOCK_SIZE)) \
54                      -l $((2 * $BLOCK_SIZE)) $SCRATCH_MNT/foo $SCRATCH_MNT/foo
55
56         # Same as before but for this file we clone the extent into a lower
57         # file offset.
58         $XFS_IO_PROG -f \
59                 -c "pwrite -S 0xaa $((2 * $BLOCK_SIZE)) $((1 * $BLOCK_SIZE))" \
60                 -c "pwrite -S 0xbb $((3 * $BLOCK_SIZE)) $((2 * $BLOCK_SIZE))" \
61                 -c "pwrite -S 0xcc $((5 * $BLOCK_SIZE)) $((1 * $BLOCK_SIZE))" \
62                 $SCRATCH_MNT/bar | _filter_xfs_io_blocks_modified
63
64         $CLONER_PROG -s $((3 * $BLOCK_SIZE)) -d 0 -l $((2 * $BLOCK_SIZE)) \
65                 $SCRATCH_MNT/bar $SCRATCH_MNT/bar
66
67         echo "File contents before unmounting filesystem:"
68         echo "foo:"
69         od -t x1 $SCRATCH_MNT/foo | _filter_od
70         echo "bar:"
71         od -t x1 $SCRATCH_MNT/bar | _filter_od
72
73         # Evicting the inode or clearing the page cache before reading again
74         # the file would also trigger the bug - reads were returning all bytes
75         # in the range corresponding to the second reference to the extent with
76         # a value of 0, but the correct data was persisted (it was a bug
77         # exclusively in the read path). The issue happened only if the same
78         # readpages() call targeted pages belonging to the first and second
79         # ranges that point to the same compressed extent.
80         _scratch_cycle_mount
81
82         echo "File contents after mounting filesystem again:"
83         # Must match the same contents we got before.
84         echo "foo:"
85         od -t x1 $SCRATCH_MNT/foo | _filter_od
86         echo "bar:"
87         od -t x1 $SCRATCH_MNT/bar | _filter_od
88 }
89
90 echo -e "\nTesting with zlib compression..."
91 test_clone_and_read_compressed_extent "-o compress=zlib"
92
93 _scratch_unmount
94
95 echo -e "\nTesting with lzo compression..."
96 test_clone_and_read_compressed_extent "-o compress=lzo"
97
98 status=0
99 exit