summaryrefslogtreecommitdiff
path: root/tests/btrfs/052
blob: 09f03f8a11f56cfae76b87dc5fe869f66c41752b (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
#! /bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2014 Filipe Manana.  All Rights Reserved.
#
# FS QA Test No. btrfs/052
#
# Verify that the btrfs ioctl clone operation can operate on the same
# file as a source and target. That is, clone extents within the same
# file.
#
. ./common/preamble
_begin_fstest auto quick clone compress

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

. ./common/filter

_supported_fs btrfs
_require_scratch
_require_cloner

test_btrfs_clone_same_file()
{
	if [ -z $1 ]; then
		MOUNT_OPTIONS=""
	else
		MOUNT_OPTIONS="-O $1"
	fi
	_scratch_mkfs >/dev/null 2>&1
	_scratch_mount $MOUNT_OPTIONS

	BLOCK_SIZE=$(_get_block_size $SCRATCH_MNT)

	EXTENT_SIZE=$((2 * $BLOCK_SIZE))

	# Create a file with 5 extents, 4 extents of 2 blocks each and 1 extent
	# of 16 blocks.
	OFFSET=0
	$XFS_IO_PROG -f -c "pwrite -S 0x01 -b $EXTENT_SIZE $OFFSET $EXTENT_SIZE" $SCRATCH_MNT/foo \
		| _filter_xfs_io_blocks_modified
	sync

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

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

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

	OFFSET=$(($OFFSET + $EXTENT_SIZE))
	EXTENT_SIZE=$((16 * $BLOCK_SIZE))
	$XFS_IO_PROG -c "pwrite -S 0x05 -b $EXTENT_SIZE $OFFSET $EXTENT_SIZE" $SCRATCH_MNT/foo \
		| _filter_xfs_io_blocks_modified
	sync

	# Initial file content.
	od -t x1 $SCRATCH_MNT/foo | _filter_od

	# Same source and target ranges - must fail.
	$CLONER_PROG -s $((2 * $BLOCK_SIZE)) -d $((2 * $BLOCK_SIZE)) \
		     -l $((2 * $BLOCK_SIZE)) $SCRATCH_MNT/foo $SCRATCH_MNT/foo
	# Check file content didn't change.
	od -t x1 $SCRATCH_MNT/foo | _filter_od

	# Intersection between source and target ranges - must fail too.
	# $CLONER_PROG -s 4096 -d 8192 -l 8192 $SCRATCH_MNT/foo $SCRATCH_MNT/foo
	$CLONER_PROG -s $((1 * $BLOCK_SIZE)) -d $((2 * $BLOCK_SIZE)) \
		     -l $((2 * $BLOCK_SIZE)) $SCRATCH_MNT/foo $SCRATCH_MNT/foo
	# Check file content didn't change.
	od -t x1 $SCRATCH_MNT/foo | _filter_od

	# Clone an entire extent from a higher range to a lower range.
	$CLONER_PROG -s $((6 * $BLOCK_SIZE)) -d 0 -l $((2 * $BLOCK_SIZE)) \
		     $SCRATCH_MNT/foo $SCRATCH_MNT/foo
	# Check entire file, 0th and 1st blocks now have the same content
	# as the 6th and 7th blocks.
	od -t x1 $SCRATCH_MNT/foo | _filter_od

	# Clone an entire extent from a lower range to a higher range.
	$CLONER_PROG -s $((2 * $BLOCK_SIZE)) -d $((4 * $BLOCK_SIZE)) \
		     -l $((2 * $BLOCK_SIZE)) $SCRATCH_MNT/foo $SCRATCH_MNT/foo
	# Check entire file, 0th and 1st blocks now have the same content
	# as the 6th and 7th block, and 4th and 5th blocks now has the same
	# content as the 2nd and 3rd blocks.
	od -t x1 $SCRATCH_MNT/foo | _filter_od

	# Now clone 1 extent and an half into the file range starting
	# at 16th block So we get the second half of the extent
	# starting at 4th block and the whole extent starting at 6th
	# block cloned into the middle of the 16 blocks extent that
	# starts at 8th block. This makes the clone ioctl process more
	# extent items from the b+tree and forces a split of the large
	# 16-block extent at the end of the file.
	$CLONER_PROG -s $((5 * $BLOCK_SIZE)) -d $((16 * $BLOCK_SIZE)) \
		     -l $((3 * $BLOCK_SIZE)) $SCRATCH_MNT/foo $SCRATCH_MNT/foo

	# Check entire file. Besides the previous changes, we now
	# should have 1 block with the value 0x02 at 16th block, and 2
	# blocks with value 0x04 starting at the 17th block . The
	# block ranges [8, 16[ and [19, 24[ should remain with all
	# bytes having the value 0x05.
	od -t x1 $SCRATCH_MNT/foo | _filter_od

	# Now update 2 blocks of data at offset 0. The extent at this
	# position is a clone of the extent at 6th block. Check that
	# writing to this offset doesn't change data at 6th block.
	$XFS_IO_PROG -c "pwrite -S 0xff -b $((2 * $BLOCK_SIZE)) 0 $((2 * $BLOCK_SIZE))" \
		     $SCRATCH_MNT/foo | _filter_xfs_io_blocks_modified
	od -t x1 $SCRATCH_MNT/foo | _filter_od

	# Check that after defragmenting the file and re-mounting, the file
	# content remains exactly the same as before.
	_btrfs filesystem defragment $SCRATCH_MNT/foo
	_scratch_cycle_mount
	od -t x1 $SCRATCH_MNT/foo | _filter_od

	# Verify that there are no consistency errors.
	_check_scratch_fs
}

# For any of the tests below, regardless of cow/nodatacow/compression, the
# results as observed by an application/user should be exactly the same.

echo "Testing with a cow file (default)"
test_btrfs_clone_same_file

_scratch_unmount

echo "Testing with a nocow file (-O nodatacow)"
test_btrfs_clone_same_file "nodatacow"

_scratch_unmount

echo "Testing with a cow file and lzo compression"
test_btrfs_clone_same_file "compress-force=lzo"

_scratch_unmount

echo "Testing with a cow file and zlib compression"
test_btrfs_clone_same_file "compress-force=zlib"

_scratch_unmount

echo "Testing with a nocow file and lzo compression"
test_btrfs_clone_same_file "nodatacow,compress-force=lzo"

_scratch_unmount

echo "Testing with a nocow file and zlib compression"
test_btrfs_clone_same_file "nodatacow,compress-force=zlib"

status=0
exit