fstests: test for fallocate capability in more tests
[xfstests-dev.git] / tests / generic / 404
1 #! /bin/bash
2 # SPDX-License-Identifier: GPL-2.0
3 # Copyright (c) 2017 Roman Penyaev.  All Rights Reserved.
4 #
5 # FS QA Test 404
6 #
7 # Regression test which targets two nasty ext4 bugs in a logic which
8 # shifts extents:
9 #
10 # 1) 14d981f468a1 ("ext4: Include forgotten start block on fallocate insert range")
11 #
12 # An incorrect right shift (insert range) for the first extent in
13 # a range.
14 #
15 # Test tries to insert many blocks at the same offset to reproduce
16 # the following layout:
17 #
18 #    block #0  block #1
19 #    |ext0 ext1|ext2 ext3 ...|
20 #         ^
21 #      insert of a new block
22 #
23 # Because of an incorrect range first block is never reached,
24 # thus ext1 is untouched, resulting to a hole at a wrong offset:
25 #
26 # What we got:
27 #
28 #    block #0   block #1
29 #    |ext0 ext1|   ext2 ext3 ...|
30 #               ^
31 #               hole at a wrong offset
32 #
33 # What we expect:
34 #
35 #    block #0    block #1
36 #    |ext0   ext1|ext2 ext3 ...|
37 #         ^
38 #         hole at a correct offset
39 #
40 # 2) 2b3864b32403 ("ext4: do not polute the extents cache while shifting extents")
41 #
42 # Extents status tree is filled in with outdated offsets while doing
43 # extents shift, that leads to wrong data blocks.  That is why test
44 # writes unique block content and checks md5sum of a result file after
45 # each block insert.
46 #
47 seq=`basename $0`
48 seqres=$RESULT_DIR/$seq
49 echo "QA output created by $seq"
50
51 here=`pwd`
52 tmp=/tmp/$$
53 status=1        # failure is the default!
54 trap "_cleanup; exit \$status" 0 1 2 3 15
55
56 testfile=$TEST_DIR/$seq.file
57 pattern=$tmp.pattern
58
59 _cleanup()
60 {
61         cd /
62         rm -f $tmp.*
63         rm -f $testfile
64 }
65
66 # get standard environment, filters and checks
67 . ./common/rc
68 . ./common/filter
69
70 # remove previous $seqres.full before test
71 rm -f $seqres.full
72
73 # real QA test starts here
74
75 # Modify as appropriate.
76 _supported_fs generic
77 _supported_os Linux
78 _require_test
79 _require_xfs_io_command "falloc"
80 _require_xfs_io_command "finsert"
81
82 blksize=`_get_block_size $TEST_DIR`
83
84 # Generate a block with a repeating number represented as 4 bytes decimal.
85 # The test generates unique pattern for each block in order to observe a
86 # wrong order if any.
87 function generate_pattern() {
88         blkind=$1
89         printf "%04d" $blkind | awk  '{ while (c++ < '$(($blksize/4))') \
90                 printf "%s", $0 }' > $pattern
91 }
92
93 $XFS_IO_PROG -f -c "falloc 0 $(($blksize * 2))" $testfile \
94                          >> $seqres.full 2>&1
95
96 # First block, has 0001 as a pattern
97 generate_pattern 1
98 $XFS_IO_PROG -c "pwrite -i $pattern        0 $blksize" $testfile \
99                          >> $seqres.full 2>&1
100
101 # Second block, has 0002 as a pattern
102 generate_pattern 2
103 $XFS_IO_PROG -c "pwrite -i $pattern $blksize $blksize" $testfile \
104                          >> $seqres.full 2>&1
105
106 # Insert 498 blocks after the first block.  We use this quite big
107 # number to increase the reproduction probability.
108 for (( block=3; block<=500; block++ )); do
109         $XFS_IO_PROG -c "finsert $blksize $blksize" $testfile \
110                                  >> $seqres.full 2>&1
111
112         generate_pattern $block
113         $XFS_IO_PROG -c "pwrite -i $pattern $blksize $blksize" $testfile \
114                                  >> $seqres.full 2>&1
115
116         # Avoid offsets in hexdump output, because block size can vary.
117         # Here we check md5 after each insert to be sure that zero blocks
118         # do not appear, targets this commit:
119         #   14d981f468a1 ("ext4: Include forgotten start block on fallocate insert range")
120         # or blocks are in correct order, this commit:
121         #   2b3864b32403 ("ext4: do not polute the extents cache while shifting extents")
122         #
123         md5=`hexdump -e '16/1 "%_p" "\n"' $testfile | md5sum`
124         printf "#%d %s\n" "$block" "$md5"
125 done
126
127 # Eventually output file has 500 blocks in the following order:
128 #   0001 0500 0499 0498 ... 0002
129
130 # success, all done
131 status=0
132 exit