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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
|
#! /bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (C) 2016 SUSE Linux Products GmbH. All Rights Reserved.
#
# FS QA Test No. btrfs/127
#
# Test that an incremental send operation works after doing radical changes
# in the directory hierarchy that involve switching the inode that directory
# entries point to.
#
. ./common/preamble
_begin_fstest auto quick send
# Override the default cleanup function.
_cleanup()
{
cd /
rm -fr $send_files_dir
rm -f $tmp.*
}
. ./common/filter
_supported_fs btrfs
_require_test
_require_scratch
_require_fssum
send_files_dir=$TEST_DIR/btrfs-test-$seq
rm -fr $send_files_dir
mkdir $send_files_dir
_scratch_mkfs >>$seqres.full 2>&1
_scratch_mount
# case 1
mkdir -p $SCRATCH_MNT/case_1/d/p1
mkdir $SCRATCH_MNT/case_1/p1
# case 2
mkdir -p $SCRATCH_MNT/case_2/a
mkdir $SCRATCH_MNT/case_2/d
mkdir $SCRATCH_MNT/case_2/e
mkdir $SCRATCH_MNT/case_2/f
mkdir $SCRATCH_MNT/case_2/ance
mkdir $SCRATCH_MNT/case_2/d/ance
mkdir $SCRATCH_MNT/case_2/a/c
mv $SCRATCH_MNT/case_2/e $SCRATCH_MNT/case_2/d/ance
mv $SCRATCH_MNT/case_2/f $SCRATCH_MNT/case_2/d/ance
mv $SCRATCH_MNT/case_2/ance $SCRATCH_MNT/case_2/d/ance
# case 3
mkdir -p $SCRATCH_MNT/case_3/d
mkdir $SCRATCH_MNT/case_3/a
mkdir $SCRATCH_MNT/case_3/waiting_dir
mkdir -p $SCRATCH_MNT/case_3/pre/ance
mkdir $SCRATCH_MNT/case_3/d/ance
mkdir $SCRATCH_MNT/case_3/a/c
mv $SCRATCH_MNT/case_3/waiting_dir $SCRATCH_MNT/case_3/d/ance
# case 4
mkdir -p $SCRATCH_MNT/case_4/tmp
mkdir $SCRATCH_MNT/case_4/below_ance
mkdir -p $SCRATCH_MNT/case_4/pre/wait_dir
mkdir $SCRATCH_MNT/case_4/desc
mkdir $SCRATCH_MNT/case_4/ance
mv $SCRATCH_MNT/case_4/below_ance $SCRATCH_MNT/case_4/ance
mkdir $SCRATCH_MNT/case_4/other_dir
# Filesystem looks like:
#
# . (ino 256)
# |--- case_1/ (ino 257)
# | |---- d/ (ino 258)
# | | |--- p1/ (ino 259)
# | |
# | |---- p1/ (ino 260)
# |
# |--- case_2/ (ino 261)
# | |---- a/ (ino 262)
# | | |---- c/ (ino 268)
# | |
# | |---- d/ (ino 263)
# | |---- ance/ (ino 267)
# | |---- e/ (ino 264)
# | |---- f/ (ino 265)
# | |---- ance/ (ino 266)
# |
# |--- case_3/ (ino 269)
# | |---- a/ (ino 271)
# | | |---- c/ (ino 276)
# | |
# | |---- d/ (ino 270)
# | | |---- ance/ (ino 275)
# | | |---- waiting_dir/ (ino 272)
# | |
# | |---- pre/ (ino 273)
# | |---- ance/ (ino 274)
# |
# |--- case_4/ (ino 277)
# |---- tmp/ (ino 278)
# |---- pre/ (ino 280)
# | |---- wait_dir/ (ino 281)
# |
# |---- desc/ (ino 282)
# |---- ance/ (ino 283)
# | |---- below_ance/ (ino 279)
# |
# |---- other_dir/ (ino 284)
#
_btrfs subvolume snapshot -r $SCRATCH_MNT $SCRATCH_MNT/mysnap1
# case 1
#
# The directory named "d" (inode 257) has in both snapshots an entry with the
# name "p1" but it refers to different inodes in both snapshots (inode 258 in
# the parent snapshot and inode 259 in the send snapshot). When attempting to
# move inode 258, the operation is delayed because its new parent, inode 259,
# was not yet moved/renamed (as the stream is currently processing inode 258).
# Later on when processing inode 259, btrfs' send also ended up delaying the
# move/rename operation for this inode, so that it would happen after inode 258
# was processed, creating a circular dependency that resulted in the send stream
# terminating without issuing a rename operations for the inodes 258 and 259.
#
mv $SCRATCH_MNT/case_1/d/p1 $SCRATCH_MNT/case_1/p1
mv $SCRATCH_MNT/case_1/p1 $SCRATCH_MNT/case_1/d
# case 2
#
# When the inode 265 is processed, the path for inode 267 is computed, which at
# that time corresponds to "case_2/d/ance", and it was stored in the name cache
# (to avoid recomputing it again later when needed).
# Later on when processing inode 266, btrfs' send end up orphanizing (renaming
# to a name matching the pattern o<ino>-<gen>-<seq>) inode 267 because it has
# the same name as inode 266 and at that time it's a child of the new parent
# directory (inode 263) for inode 266. After the orphanization and while still
# processing inode 266, a rename operation for inode 266 was generated. However
# the source path for that rename operation was incorrect because it ended up
# using the old, pre-orphanization, name of inode 267.
#
mv $SCRATCH_MNT/case_2/a/c $SCRATCH_MNT/case_2
mv $SCRATCH_MNT/case_2/d/ance $SCRATCH_MNT/case_2/c
mv $SCRATCH_MNT/case_2/c/ance/ance $SCRATCH_MNT/case_2/d
mv $SCRATCH_MNT/case_2/c/ance/f $SCRATCH_MNT/case_2
mv $SCRATCH_MNT/case_2/c/ance/e $SCRATCH_MNT/case_2/f
# case 3
#
# This is similar to cases 1 and 2, but adding more complexity just to exercise
# btrfs' incremental send correctness.
#
mv $SCRATCH_MNT/case_3/d/ance $SCRATCH_MNT/case_3/a
mv $SCRATCH_MNT/case_3/a/c $SCRATCH_MNT/case_3
mv $SCRATCH_MNT/case_3/a/ance/waiting_dir $SCRATCH_MNT/case_3/c
mv $SCRATCH_MNT/case_3/pre/ance $SCRATCH_MNT/case_3/d
mv $SCRATCH_MNT/case_3/pre $SCRATCH_MNT/case_3/c/waiting_dir
# case 4
#
# When attempting to rename inode 283, the incremental send stream included an
# invalid destination path for the rename command. This was due to a missing
# path loop detection in the send code that made the rename of inode 283 happen
# without waiting for the rename of inode 284 to happen first (since it's an
# ancestor in the send snapshot that is beyond the current progress and it was
# also renamed/moved).
#
mv $SCRATCH_MNT/case_4/other_dir $SCRATCH_MNT/case_4/tmp
mv $SCRATCH_MNT/case_4/ance/below_ance $SCRATCH_MNT/case_4/tmp/other_dir
mv $SCRATCH_MNT/case_4/pre/wait_dir $SCRATCH_MNT/case_4/tmp/other_dir
mv $SCRATCH_MNT/case_4/pre $SCRATCH_MNT/case_4/tmp/other_dir/below_ance
mv $SCRATCH_MNT/case_4/desc $SCRATCH_MNT/case_4/tmp/other_dir/wait_dir
mv $SCRATCH_MNT/case_4/ance $SCRATCH_MNT/case_4/tmp/other_dir/wait_dir/desc
# Filesystem now looks like:
#
# . (ino 256)
# |--- case_1/ (ino 257)
# | |--- d/ (ino 258)
# | |--- p1/ (ino 260)
# | |--- p1/ (ino 259)
# |
# |--- case_2/ (ino 261)
# | |---- a/ (ino 262)
# | |---- c/ (ino 268)
# | | |---- ance/ (ino 267)
# | |
# | |---- d/ (ino 263)
# | | |---- ance/ (ino 266)
# | |
# | |---- f/ (ino 265)
# | |---- e/ (ino 264)
# |
# |--- case_3/ (ino 269)
# | |---- a/ (ino 271)
# | | |---- ance/ (ino 275)
# | |
# | |---- c/ (ino 276)
# | | |---- waiting_dir/ (ino 272)
# | | |---- pre/ (ino 273)
# | |
# | |---- d/ (ino 270)
# | |---- ance/ (ino 274)
# |
# |--- case_4/ (ino 277)
# |---- tmp/ (ino 278)
# |---- other_dir/ (ino 284)
# |---- below_ance/ (ino 279)
# | |---- pre/ (ino 280)
# |
# |---- wait_dir/ (ino 281)
# |---- desc/ (ino 282)
# |---- ance/ (ino 283)
#
_btrfs subvolume snapshot -r $SCRATCH_MNT $SCRATCH_MNT/mysnap2
run_check $FSSUM_PROG -A -f -w $send_files_dir/1.fssum $SCRATCH_MNT/mysnap1
run_check $FSSUM_PROG -A -f -w $send_files_dir/2.fssum \
-x $SCRATCH_MNT/mysnap2/mysnap1 $SCRATCH_MNT/mysnap2
_btrfs send -f $send_files_dir/1.snap $SCRATCH_MNT/mysnap1
_btrfs send -p $SCRATCH_MNT/mysnap1 -f $send_files_dir/2.snap \
$SCRATCH_MNT/mysnap2
# Now recreate the filesystem by receiving both send streams and verify we get
# the same content that the original filesystem had.
_scratch_unmount
_scratch_mkfs >>$seqres.full 2>&1
_scratch_mount
_btrfs receive -f $send_files_dir/1.snap $SCRATCH_MNT
run_check $FSSUM_PROG -r $send_files_dir/1.fssum $SCRATCH_MNT/mysnap1
_btrfs receive -f $send_files_dir/2.snap $SCRATCH_MNT
run_check $FSSUM_PROG -r $send_files_dir/2.fssum $SCRATCH_MNT/mysnap2
echo "Silence is golden"
status=0
exit
|