blob: a8b110bc52d5566fe0ec0c5f320190dac5789996 (
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
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
|
#! /bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2022 BingJing Chang.
#
# FS QA Test No. btrfs/278
#
# Regression test for btrfs incremental send issue when processing inodes
# with no links
#
# This issue is fixed by the following linux kernel btrfs patch:
#
# commit 9ed0a72e5b355d ("btrfs: send: fix failures when processing
# inodes with no links")
#
. ./common/preamble
_begin_fstest auto quick send
_supported_fs btrfs
_fixed_by_kernel_commit 9ed0a72e5b355d \
"btrfs: send: fix failures when processing inodes with no links"
_require_test
_require_scratch
_require_btrfs_command "property"
_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
_btrfs subvolume create $SCRATCH_MNT/vol
# Creating the first snapshot looks like:
#
# . (ino 256)
# |--- deleted.file (ino 257)
# |--- deleted.dir/ (ino 258)
# |--- changed_subcase1.file (ino 259)
# |--- changed_subcase2.file (ino 260)
# |--- changed_subcase1.dir/ (ino 261)
# | |---- foo (ino 262)
# |--- changed_subcase2.dir/ (ino 263)
# | |---- foo (ino 264)
#
touch $SCRATCH_MNT/vol/deleted.file
mkdir $SCRATCH_MNT/vol/deleted.dir
touch $SCRATCH_MNT/vol/changed_subcase1.file
touch $SCRATCH_MNT/vol/changed_subcase2.file
mkdir $SCRATCH_MNT/vol/changed_subcase1.dir
touch $SCRATCH_MNT/vol/changed_subcase1.dir/foo
mkdir $SCRATCH_MNT/vol/changed_subcase2.dir
touch $SCRATCH_MNT/vol/changed_subcase2.dir/foo
_btrfs subvolume snapshot -r $SCRATCH_MNT/vol $SCRATCH_MNT/snap1
# Delete the deleted.*, create a new file and a new directory, and then
# take the second snapshot looks like:
#
# . (ino 256)
# |--- changed_subcase1.file (ino 259)
# |--- changed_subcase2.file (ino 260)
# |--- changed_subcase1.dir/ (ino 261)
# | |---- foo (ino 262)
# |--- changed_subcase2.dir/ (ino 263)
# | |---- foo (ino 264)
# |--- new.file (ino 265)
# |--- new.dir/ (ino 266)
#
unlink $SCRATCH_MNT/vol/deleted.file
rmdir $SCRATCH_MNT/vol/deleted.dir
touch $SCRATCH_MNT/vol/new.file
mkdir $SCRATCH_MNT/vol/new.dir
_btrfs subvolume snapshot -r $SCRATCH_MNT/vol $SCRATCH_MNT/snap2
# Set the snapshot "snap1" to read-write mode and turn several inodes to
# orphans, so that the snapshot will look like this:
#
# . (ino 256)
# |--- (orphan) deleted.file (ino 257)
# |--- (orphan) deleted.dir/ (ino 258)
# |--- (orphan) changed_subcase1.file (ino 259)
# |--- changed_subcase2.file (ino 260)
# |--- (orphan) changed_subcase1.dir/ (ino 261)
# |--- changed_subcase2.dir/ (ino 263)
# | |---- foo (ino 264)
#
# Note: To make an easy illustration, I just put a tag "(orphan)" in front of
# their original names to indicate that they're deleted, but their inodes can
# not be removed because of open file descriptors on them. Mention that orphan
# inodes don't have names(paths).
#
$BTRFS_UTIL_PROG property set $SCRATCH_MNT/snap1 ro false
exec 71<$SCRATCH_MNT/snap1/deleted.file
exec 72<$SCRATCH_MNT/snap1/deleted.dir
exec 73<$SCRATCH_MNT/snap1/changed_subcase1.file
exec 74<$SCRATCH_MNT/snap1/changed_subcase1.dir
unlink $SCRATCH_MNT/snap1/deleted.file
rmdir $SCRATCH_MNT/snap1/deleted.dir
unlink $SCRATCH_MNT/snap1/changed_subcase1.file
unlink $SCRATCH_MNT/snap1/changed_subcase1.dir/foo
rmdir $SCRATCH_MNT/snap1/changed_subcase1.dir
# Turn the snapshot "snap1" back to read-only mode.
$BTRFS_UTIL_PROG property set $SCRATCH_MNT/snap1 ro true
# Set the snapshot "snap2" to read-write mode and turn several inodes to
# orphans, so that the snapshot will look like this:
#
# . (ino 256)
# |--- (orphan) changed_subcase1.file (ino 259)
# |--- (orphan) changed_subcase2.file (ino 260)
# |--- (orphan) changed_subcase1.dir/ (ino 261)
# |--- (orphan) changed_subcase2.dir/ (ino 263)
# |--- (orphan) new.file (ino 265)
# |--- (orphan) new.dir/ (ino 266)
#
# Note: Same notice as above. Mention that orphan inodes don't have
# names(paths).
#
$BTRFS_UTIL_PROG property set $SCRATCH_MNT/snap2 ro false
exec 81<$SCRATCH_MNT/snap2/changed_subcase1.file
exec 82<$SCRATCH_MNT/snap2/changed_subcase1.dir
exec 83<$SCRATCH_MNT/snap2/changed_subcase2.file
exec 84<$SCRATCH_MNT/snap2/changed_subcase2.dir
exec 85<$SCRATCH_MNT/snap2/new.file
exec 86<$SCRATCH_MNT/snap2/new.dir
unlink $SCRATCH_MNT/snap2/changed_subcase1.file
unlink $SCRATCH_MNT/snap2/changed_subcase1.dir/foo
rmdir $SCRATCH_MNT/snap2/changed_subcase1.dir
unlink $SCRATCH_MNT/snap2/changed_subcase2.file
unlink $SCRATCH_MNT/snap2/changed_subcase2.dir/foo
rmdir $SCRATCH_MNT/snap2/changed_subcase2.dir
unlink $SCRATCH_MNT/snap2/new.file
rmdir $SCRATCH_MNT/snap2/new.dir
# Turn the snapshot "snap2" back to read-only mode.
$BTRFS_UTIL_PROG property set $SCRATCH_MNT/snap2 ro true
# Test that a full send operation can handle orphans with no paths
_btrfs send -f $send_files_dir/1.snap $SCRATCH_MNT/snap1
# Test that an incremental send operation can handle orphans.
#
# Here're descriptions for the details:
#
# Case 1: new.file and new.dir (BTRFS_COMPARE_TREE_NEW)
# | send snapshot | action
# --------------------------------
# nlink | 0 | ignore
#
# They are new inodes in the send snapshot ("snap2"), but they don't have
# paths because they have no links. Test that the send operation can ignore
# them in order not to generate the creation commands for them. Or it will
# fail, with -ENOENT, when trying to generate paths for them.
#
#
# Case 2: deleted.file and deleted.dir (BTRFS_COMPARE_TREE_DELETED)
# | parent snapshot | action
# ----------------------------------
# nlink | 0 | as usual
#
# They're deleted in the parent snapshot ("snap1") but become orphans which
# have no paths. Test that no deletion commands will be generated as usual.
# This case didn't fail before.
#
#
# Case 3: changed_*.file and changed_*.dir (BTRFS_COMPARE_TREE_CHANGED)
# | | parent snapshot | send snapshot | action
# -----------------------------------------------------------------------
# subcase 1 | nlink | 0 | 0 | ignore
# subcase 2 | nlink | >0 | 0 | new_gen(deletion)
#
# In subcase 1, test that the send operation can ignore them without trying
# to generate any commands.
#
# In subcase 2, test that the send operation can generate an unlink command
# for that file and test that it can generate a rename command for the
# non-empty directory first and a rmdir command to remove it finally. Or
# the receive operation will fail with a wrong unlink on a non-empty
# directory.
#
_btrfs send -p $SCRATCH_MNT/snap1 -f $send_files_dir/2.snap \
$SCRATCH_MNT/snap2
$FSSUM_PROG -A -f -w $send_files_dir/1.fssum $SCRATCH_MNT/snap1
$FSSUM_PROG -A -f -w $send_files_dir/2.fssum \
-x $SCRATCH_MNT/snap2/snap1 $SCRATCH_MNT/snap2
# Recreate the filesystem by receiving both send streams and verify we get
# the same content that the original filesystem had.
exec 71>&-
exec 72>&-
exec 73>&-
exec 74>&-
exec 81>&-
exec 82>&-
exec 83>&-
exec 84>&-
exec 85>&-
exec 86>&-
_scratch_unmount
_scratch_mkfs >>$seqres.full 2>&1
_scratch_mount
# Add the first snapshot to the new filesystem by applying the first send
# stream.
_btrfs receive -f $send_files_dir/1.snap $SCRATCH_MNT
# Test the incremental send stream
_btrfs receive -f $send_files_dir/2.snap $SCRATCH_MNT
$FSSUM_PROG -r $send_files_dir/1.fssum $SCRATCH_MNT/snap1
$FSSUM_PROG -r $send_files_dir/2.fssum $SCRATCH_MNT/snap2
status=0
exit
|