summaryrefslogtreecommitdiff
path: root/tests/btrfs/055
blob: 900c3dba820fa8604500f025add9532b23ff1ab5 (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
#! /bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2014 Filipe Manana.  All Rights Reserved.
#
# 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
#
. ./common/preamble
_begin_fstest auto quick clone

# Override the default cleanup function.
_cleanup()
{
    rm -fr $tmp
}

. ./common/filter

_supported_fs btrfs
_require_scratch
_require_cloner
_require_btrfs_fs_feature "no_holes"
_require_btrfs_mkfs_feature "no-holes"

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