summaryrefslogtreecommitdiff
path: root/tests/btrfs/055
blob: 481d5c8468faecbace9e5bac77fba02cdc2cbbcf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#! /bin/bash
# FS QA Test No. btrfs/055
#
# Regression test for the btrfs ioctl clone operation when the source range
# contains hole(s) and the FS has the NO_HOLES feature enabled (file holes
# don't need file extent items in the btree to represent them).
#
# This issue is fixed by the following linux kernel btrfs patch:
#
#    Btrfs: fix clone to deal with holes when NO_HOLES feature is enabled
#
#-----------------------------------------------------------------------
# Copyright (c) 2014 Filipe Manana.  All Rights Reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it would be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write the Free Software Foundation,
# Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
#-----------------------------------------------------------------------
#

seq=`basename $0`
seqres=$RESULT_DIR/$seq
echo "QA output created by $seq"

tmp=/tmp/$$
status=1	# failure is the default!
trap "_cleanup; exit \$status" 0 1 2 3 15

_cleanup()
{
    rm -fr $tmp
}

# get standard environment, filters and checks
. ./common/rc
. ./common/filter

# real QA test starts here
_supported_fs btrfs
_supported_os Linux
_require_scratch
_require_cloner
_require_btrfs_fs_feature "no_holes"
_require_btrfs_mkfs_feature "no-holes"

rm -f $seqres.full

test_btrfs_clone_with_holes()
{
	_scratch_mkfs "$1" >/dev/null 2>&1
	_scratch_mount

	BLOCK_SIZE=$(_get_block_size $SCRATCH_MNT)

	EXTENT_SIZE=$((2 * $BLOCK_SIZE))

	OFFSET=0

	# Create a file with 4 extents and 1 hole, all with 2 blocks each.
	# The hole is in the block range [4, 5[.
	$XFS_IO_PROG -s -f -c "pwrite -S 0x01 -b $EXTENT_SIZE $OFFSET $EXTENT_SIZE" \
		     $SCRATCH_MNT/foo | _filter_xfs_io_blocks_modified

	OFFSET=$(($OFFSET + $EXTENT_SIZE))
	$XFS_IO_PROG -s -f -c "pwrite -S 0x02 -b $EXTENT_SIZE $OFFSET $EXTENT_SIZE" \
		     $SCRATCH_MNT/foo | _filter_xfs_io_blocks_modified

	OFFSET=$(($OFFSET + 2 * $EXTENT_SIZE))
	$XFS_IO_PROG -s -f -c "pwrite -S 0x04 -b $EXTENT_SIZE $OFFSET $EXTENT_SIZE" \
		     $SCRATCH_MNT/foo | _filter_xfs_io_blocks_modified

	OFFSET=$(($OFFSET + $EXTENT_SIZE))
	$XFS_IO_PROG -s -f -c "pwrite -S 0x05 -b $EXTENT_SIZE $OFFSET $EXTENT_SIZE" \
		     $SCRATCH_MNT/foo | _filter_xfs_io_blocks_modified

	# Clone destination file, 1 extent of 24 blocks.
	EXTENT_SIZE=$((24 * $BLOCK_SIZE))
	$XFS_IO_PROG -s -f -c "pwrite -S 0xff -b $EXTENT_SIZE 0 $EXTENT_SIZE" \
		$SCRATCH_MNT/bar | _filter_xfs_io_blocks_modified

	# Clone 2nd extent, 2-blocks sized hole and 3rd extent of foo into bar.
	$CLONER_PROG -s $((2 * $BLOCK_SIZE)) -d 0 -l $((6 * $BLOCK_SIZE)) \
		     $SCRATCH_MNT/foo $SCRATCH_MNT/bar

	# Verify both extents and the hole were cloned.
	echo "1) Check both extents and the hole were cloned"
	od -t x1 $SCRATCH_MNT/bar | _filter_od

	# Cloning range starts at the middle of a hole.
	$CLONER_PROG -s $((5 * $BLOCK_SIZE)) -d $((8 * $BLOCK_SIZE)) \
		     -l $((3 * $BLOCK_SIZE)) $SCRATCH_MNT/foo $SCRATCH_MNT/bar

	# Verify that half of the hole and the following 2 block extent were cloned.
	echo "2) Check half hole and the following 2 block extent were cloned"
	od -t x1 $SCRATCH_MNT/bar | _filter_od

	# Cloning range ends at the middle of a hole.
	$CLONER_PROG -s 0 -d $((16 * $BLOCK_SIZE)) -l $((5 * $BLOCK_SIZE)) \
		     $SCRATCH_MNT/foo $SCRATCH_MNT/bar

	# Verify that 2 extents of 2 blocks size and a 1-block hole were cloned.
	echo "3) Check that 2 extents of 2 blocks each and a hole of 1 block were cloned"
	od -t x1 $SCRATCH_MNT/bar | _filter_od

	# Create a 6-block hole at the end of the source file (foo).
	$XFS_IO_PROG -c "truncate $((16 * $BLOCK_SIZE))" $SCRATCH_MNT/foo \
		| _filter_xfs_io_blocks_modified
	sync

	# Now clone a range that overlaps that hole at the end of the foo file.
	# It should clone the 10th block and the first two blocks of the hole
	# at the end of foo.
	$CLONER_PROG -s $((9 * $BLOCK_SIZE)) -d $((21 * $BLOCK_SIZE)) \
		     -l $((3 * $BLOCK_SIZE)) $SCRATCH_MNT/foo $SCRATCH_MNT/bar

	# Verify that the 9th block of foo and the first 2 blocks of the
	# 6-block hole of foo were cloned into bar.
	echo "4) Check that a block of 1 extent and 2 blocks of a hole were cloned"
	od -t x1 $SCRATCH_MNT/bar | _filter_od

	# Clone the same range as before, but clone it into a different offset
	# of the target (bar) such that it increases the size of the target
	# by 2 blocks.
	$CLONER_PROG -s $((9 * $BLOCK_SIZE)) -d $((23 * $BLOCK_SIZE)) \
		     -l $((3 * $BLOCK_SIZE)) $SCRATCH_MNT/foo $SCRATCH_MNT/bar

	# Verify that the 9th block of foo and the first 2 blocks of the 6-block
	# hole of foo were cloned into bar at bar's 23rd block and that bar's
	# size increased by 2 blocks.
	echo "5) Check that a block of 1 extent and 2 blocks of a hole were" \
	     "cloned and file size increased"
	od -t x1 $SCRATCH_MNT/bar | _filter_od

	# Create a new completely sparse file (no extents, it's a big hole).
	$XFS_IO_PROG -f -c "truncate $((25 * $BLOCK_SIZE))" $SCRATCH_MNT/qwerty \
		| _filter_xfs_io_blocks_modified
	sync

	# Test cloning a range from the sparse file to the bar file without
	# increasing bar's size.
	$CLONER_PROG -s $((1 * $BLOCK_SIZE)) -d 0 -l $((2 * $BLOCK_SIZE)) \
		     $SCRATCH_MNT/qwerty $SCRATCH_MNT/bar

	# First 2 blocks of bar should now be zeroes.
	echo "6) Check that 2 blocks of the hole were cloned"
	od -t x1 $SCRATCH_MNT/bar | _filter_od

	# Test cloning a range from the sparse file to the end of the bar file.
	# The bar file currently has 26 blocks.
	$CLONER_PROG -s 0 -d $((26 * $BLOCK_SIZE)) -l $((8 * $BLOCK_SIZE)) $SCRATCH_MNT/qwerty \
		$SCRATCH_MNT/bar

	# Verify bar's size increased to 26 + 8 blocks, and its
	# last 8 blocks are all zeroes.
	echo "7) Check that 8 blocks of the hole were cloned and the file size increased"
	od -t x1 $SCRATCH_MNT/bar | _filter_od

	# Verify that there are no consistency errors.
	_check_scratch_fs
}

# Regardless of the NO_HOLES feature being enabled or not, the test results
# should be exactly the same for both cases.

echo "Testing without the NO_HOLES feature"
# As of btrfs-progs 3.14.x, the no-holes feature isn't enabled by default.
# But explicitly disable it at mkfs time as it might be enabled by default
# in future versions.
test_btrfs_clone_with_holes "-O ^no-holes"

_scratch_unmount

echo "Testing with the NO_HOLES feature enabled"
test_btrfs_clone_with_holes "-O no-holes"

status=0
exit