481d5c8468faecbace9e5bac77fba02cdc2cbbcf
[xfstests-dev.git] / tests / btrfs / 055
1 #! /bin/bash
2 # FS QA Test No. btrfs/055
3 #
4 # Regression test for the btrfs ioctl clone operation when the source range
5 # contains hole(s) and the FS has the NO_HOLES feature enabled (file holes
6 # don't need file extent items in the btree to represent them).
7 #
8 # This issue is fixed by the following linux kernel btrfs patch:
9 #
10 #    Btrfs: fix clone to deal with holes when NO_HOLES feature is enabled
11 #
12 #-----------------------------------------------------------------------
13 # Copyright (c) 2014 Filipe Manana.  All Rights Reserved.
14 #
15 # This program is free software; you can redistribute it and/or
16 # modify it under the terms of the GNU General Public License as
17 # published by the Free Software Foundation.
18 #
19 # This program is distributed in the hope that it would be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 # GNU General Public License for more details.
23 #
24 # You should have received a copy of the GNU General Public License
25 # along with this program; if not, write the Free Software Foundation,
26 # Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
27 #-----------------------------------------------------------------------
28 #
29
30 seq=`basename $0`
31 seqres=$RESULT_DIR/$seq
32 echo "QA output created by $seq"
33
34 tmp=/tmp/$$
35 status=1        # failure is the default!
36 trap "_cleanup; exit \$status" 0 1 2 3 15
37
38 _cleanup()
39 {
40     rm -fr $tmp
41 }
42
43 # get standard environment, filters and checks
44 . ./common/rc
45 . ./common/filter
46
47 # real QA test starts here
48 _supported_fs btrfs
49 _supported_os Linux
50 _require_scratch
51 _require_cloner
52 _require_btrfs_fs_feature "no_holes"
53 _require_btrfs_mkfs_feature "no-holes"
54
55 rm -f $seqres.full
56
57 test_btrfs_clone_with_holes()
58 {
59         _scratch_mkfs "$1" >/dev/null 2>&1
60         _scratch_mount
61
62         BLOCK_SIZE=$(_get_block_size $SCRATCH_MNT)
63
64         EXTENT_SIZE=$((2 * $BLOCK_SIZE))
65
66         OFFSET=0
67
68         # Create a file with 4 extents and 1 hole, all with 2 blocks each.
69         # The hole is in the block range [4, 5[.
70         $XFS_IO_PROG -s -f -c "pwrite -S 0x01 -b $EXTENT_SIZE $OFFSET $EXTENT_SIZE" \
71                      $SCRATCH_MNT/foo | _filter_xfs_io_blocks_modified
72
73         OFFSET=$(($OFFSET + $EXTENT_SIZE))
74         $XFS_IO_PROG -s -f -c "pwrite -S 0x02 -b $EXTENT_SIZE $OFFSET $EXTENT_SIZE" \
75                      $SCRATCH_MNT/foo | _filter_xfs_io_blocks_modified
76
77         OFFSET=$(($OFFSET + 2 * $EXTENT_SIZE))
78         $XFS_IO_PROG -s -f -c "pwrite -S 0x04 -b $EXTENT_SIZE $OFFSET $EXTENT_SIZE" \
79                      $SCRATCH_MNT/foo | _filter_xfs_io_blocks_modified
80
81         OFFSET=$(($OFFSET + $EXTENT_SIZE))
82         $XFS_IO_PROG -s -f -c "pwrite -S 0x05 -b $EXTENT_SIZE $OFFSET $EXTENT_SIZE" \
83                      $SCRATCH_MNT/foo | _filter_xfs_io_blocks_modified
84
85         # Clone destination file, 1 extent of 24 blocks.
86         EXTENT_SIZE=$((24 * $BLOCK_SIZE))
87         $XFS_IO_PROG -s -f -c "pwrite -S 0xff -b $EXTENT_SIZE 0 $EXTENT_SIZE" \
88                 $SCRATCH_MNT/bar | _filter_xfs_io_blocks_modified
89
90         # Clone 2nd extent, 2-blocks sized hole and 3rd extent of foo into bar.
91         $CLONER_PROG -s $((2 * $BLOCK_SIZE)) -d 0 -l $((6 * $BLOCK_SIZE)) \
92                      $SCRATCH_MNT/foo $SCRATCH_MNT/bar
93
94         # Verify both extents and the hole were cloned.
95         echo "1) Check both extents and the hole were cloned"
96         od -t x1 $SCRATCH_MNT/bar | _filter_od
97
98         # Cloning range starts at the middle of a hole.
99         $CLONER_PROG -s $((5 * $BLOCK_SIZE)) -d $((8 * $BLOCK_SIZE)) \
100                      -l $((3 * $BLOCK_SIZE)) $SCRATCH_MNT/foo $SCRATCH_MNT/bar
101
102         # Verify that half of the hole and the following 2 block extent were cloned.
103         echo "2) Check half hole and the following 2 block extent were cloned"
104         od -t x1 $SCRATCH_MNT/bar | _filter_od
105
106         # Cloning range ends at the middle of a hole.
107         $CLONER_PROG -s 0 -d $((16 * $BLOCK_SIZE)) -l $((5 * $BLOCK_SIZE)) \
108                      $SCRATCH_MNT/foo $SCRATCH_MNT/bar
109
110         # Verify that 2 extents of 2 blocks size and a 1-block hole were cloned.
111         echo "3) Check that 2 extents of 2 blocks each and a hole of 1 block were cloned"
112         od -t x1 $SCRATCH_MNT/bar | _filter_od
113
114         # Create a 6-block hole at the end of the source file (foo).
115         $XFS_IO_PROG -c "truncate $((16 * $BLOCK_SIZE))" $SCRATCH_MNT/foo \
116                 | _filter_xfs_io_blocks_modified
117         sync
118
119         # Now clone a range that overlaps that hole at the end of the foo file.
120         # It should clone the 10th block and the first two blocks of the hole
121         # at the end of foo.
122         $CLONER_PROG -s $((9 * $BLOCK_SIZE)) -d $((21 * $BLOCK_SIZE)) \
123                      -l $((3 * $BLOCK_SIZE)) $SCRATCH_MNT/foo $SCRATCH_MNT/bar
124
125         # Verify that the 9th block of foo and the first 2 blocks of the
126         # 6-block hole of foo were cloned into bar.
127         echo "4) Check that a block of 1 extent and 2 blocks of a hole were cloned"
128         od -t x1 $SCRATCH_MNT/bar | _filter_od
129
130         # Clone the same range as before, but clone it into a different offset
131         # of the target (bar) such that it increases the size of the target
132         # by 2 blocks.
133         $CLONER_PROG -s $((9 * $BLOCK_SIZE)) -d $((23 * $BLOCK_SIZE)) \
134                      -l $((3 * $BLOCK_SIZE)) $SCRATCH_MNT/foo $SCRATCH_MNT/bar
135
136         # Verify that the 9th block of foo and the first 2 blocks of the 6-block
137         # hole of foo were cloned into bar at bar's 23rd block and that bar's
138         # size increased by 2 blocks.
139         echo "5) Check that a block of 1 extent and 2 blocks of a hole were" \
140              "cloned and file size increased"
141         od -t x1 $SCRATCH_MNT/bar | _filter_od
142
143         # Create a new completely sparse file (no extents, it's a big hole).
144         $XFS_IO_PROG -f -c "truncate $((25 * $BLOCK_SIZE))" $SCRATCH_MNT/qwerty \
145                 | _filter_xfs_io_blocks_modified
146         sync
147
148         # Test cloning a range from the sparse file to the bar file without
149         # increasing bar's size.
150         $CLONER_PROG -s $((1 * $BLOCK_SIZE)) -d 0 -l $((2 * $BLOCK_SIZE)) \
151                      $SCRATCH_MNT/qwerty $SCRATCH_MNT/bar
152
153         # First 2 blocks of bar should now be zeroes.
154         echo "6) Check that 2 blocks of the hole were cloned"
155         od -t x1 $SCRATCH_MNT/bar | _filter_od
156
157         # Test cloning a range from the sparse file to the end of the bar file.
158         # The bar file currently has 26 blocks.
159         $CLONER_PROG -s 0 -d $((26 * $BLOCK_SIZE)) -l $((8 * $BLOCK_SIZE)) $SCRATCH_MNT/qwerty \
160                 $SCRATCH_MNT/bar
161
162         # Verify bar's size increased to 26 + 8 blocks, and its
163         # last 8 blocks are all zeroes.
164         echo "7) Check that 8 blocks of the hole were cloned and the file size increased"
165         od -t x1 $SCRATCH_MNT/bar | _filter_od
166
167         # Verify that there are no consistency errors.
168         _check_scratch_fs
169 }
170
171 # Regardless of the NO_HOLES feature being enabled or not, the test results
172 # should be exactly the same for both cases.
173
174 echo "Testing without the NO_HOLES feature"
175 # As of btrfs-progs 3.14.x, the no-holes feature isn't enabled by default.
176 # But explicitly disable it at mkfs time as it might be enabled by default
177 # in future versions.
178 test_btrfs_clone_with_holes "-O ^no-holes"
179
180 _scratch_unmount
181
182 echo "Testing with the NO_HOLES feature enabled"
183 test_btrfs_clone_with_holes "-O no-holes"
184
185 status=0
186 exit