summaryrefslogtreecommitdiff
path: root/tests/generic/544
blob: 4a9f48526d3ddb1fb4799d426f91464916cf2002 (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
#! /bin/bash
# SPDX-License-Identifier: GPL-2.0+
# Copyright (c) 2019, Oracle and/or its affiliates.  All Rights Reserved.
#
# FS QA Test No. 544
#
# Ensure that we can reflink from a file with a higher inode number to a lower
# inode number and vice versa.  Mix it up by doing this test with inodes that
# already share blocks and inodes that don't share blocks.  This tests both
# double-inode locking order correctness as well as stressing things like ocfs2
# which have per-inode sharing groups and therefore have to check that we don't
# try to link data between disjoint sharing groups.
. ./common/preamble
_begin_fstest auto quick clone

# Import common functions.
. ./common/filter
. ./common/reflink

# real QA test starts here
_supported_fs generic
_require_scratch_reflink
_require_cp_reflink

echo "Format and mount"
_scratch_mkfs > $seqres.full 2>&1
_scratch_mount >> $seqres.full 2>&1

blksz=65536
nr=2
filesize=$((blksz * nr))
testdir=$SCRATCH_MNT/test-$seq
dummy_file=$testdir/dummy
low_file=$testdir/low
high_file=$testdir/high
scenario=1
mkdir $testdir

# Return inode number
inum() {
	stat -c '%i' $1
}

# Create two test files, make $low_file the file with the lower inode
# number, and make $high_file the file with the higher inode number.
create_files() {
	_pwrite_byte 0x60 0 $filesize $testdir/file1 >> $seqres.full
	_pwrite_byte 0x61 0 $filesize $testdir/file2 >> $seqres.full
	if [ "$(inum $testdir/file1)" -lt "$(inum $testdir/file2)" ]; then
		mv $testdir/file1 $low_file
		mv $testdir/file2 $high_file
	else
		mv $testdir/file2 $low_file
		mv $testdir/file1 $high_file
	fi
}

# Check md5sum of both files, but keep results sorted by inode order
check_files() {
	md5sum $low_file | _filter_scratch
	md5sum $high_file | _filter_scratch
}

# Test reflinking data from the first file to the second file
test_files() {
	local src="$1"
	local dest="$2"
	local off=$((filesize / 2))
	local sz=$((filesize / 2))

	check_files
	_reflink_range $src $off $dest $off $sz >> $seqres.full
	_scratch_cycle_mount
	check_files
}

# Make a file shared with a dummy file
dummy_share() {
	local which="$2"
	test -z "$which" && which=1
	local dummy=$dummy_file.$which

	rm -f $dummy
	_cp_reflink $1 $dummy
}

# Make two files share (different ranges) with a dummy file
mutual_dummy_share() {
	rm -f $dummy_file
	_cp_reflink $1 $dummy_file
	_reflink_range $2 0 $dummy_file $blksz $blksz >> $seqres.full
}

# Announce ourselves, remembering which scenario we've tried
ann() {
	echo "$scenario: $@" | tee -a $seqres.full
	scenario=$((scenario + 1))
}

# Scenario 1: low to high, neither file shares
ann "low to high, neither share"
create_files
test_files $low_file $high_file

# Scenario 2: high to low, neither file shares
ann "high to low, neither share"
create_files
test_files $high_file $low_file

# Scenario 3: low to high, only source file shares
ann "low to high, only source shares"
create_files
dummy_share $low_file
test_files $low_file $high_file

# Scenario 4: high to low, only source file shares
ann "high to low, only source shares"
create_files
dummy_share $high_file
test_files $high_file $low_file

# Scenario 5: low to high, only dest file shares
ann "low to high, only dest shares"
create_files
dummy_share $high_file
test_files $low_file $high_file

# Scenario 6: high to low, only dest file shares
ann "high to low, only dest shares"
create_files
dummy_share $low_file
test_files $high_file $low_file

# Scenario 7: low to high, both files share with each other
ann "low to high, both files share with each other"
create_files
_reflink_range $low_file 0 $high_file 0 $blksz >> $seqres.full
test_files $low_file $high_file

# Scenario 8: high to low, both files share with each other
ann "high to low, both files share with each other"
create_files
_reflink_range $low_file 0 $high_file 0 $blksz >> $seqres.full
test_files $high_file $low_file

# Scenario 9: low to high, both files share but not with each other
ann "low to high, both files share but not with each other"
create_files
# ocfs2 can only reflink between files sharing a refcount tree, so for
# this test (and #10) we skip the dummy file because we'd rather not split
# the test code just to mask off the /one/ weird fs like this...
if _supports_arbitrary_fileset_reflink; then
	dummy_share $low_file 1
	dummy_share $high_file 2
fi
test_files $low_file $high_file

# Scenario 10: high to low, both files share but not with each other
ann "high to low, both files share but not with each other"
create_files
if _supports_arbitrary_fileset_reflink; then
	dummy_share $low_file 1
	dummy_share $high_file 2
fi
test_files $high_file $low_file

# Scenario 11: low to high, both files share mutually
ann "low to high, both files share mutually"
create_files
mutual_dummy_share $low_file $high_file
test_files $low_file $high_file

# Scenario 12: high to low, both files share mutually
ann "high to low, both files share mutually"
create_files
mutual_dummy_share $low_file $high_file
test_files $high_file $low_file

# success, all done
status=0
exit