summaryrefslogtreecommitdiff
path: root/tests/btrfs/241
blob: 96f2e1900210adbf6d4e11e0bccb881af9eb1e39 (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
#! /bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (C) 2021 SUSE Linux Products GmbH. All Rights Reserved.
#
# FS QA Test No. btrfs/241
#
# Test that an incremental send operation succeeds, and produces the correct
# results, after renaming and moving around directories and files with multiple
# hardlinks, in such a way that one of the files gets the old name and location
# of a directory and another name (hardlink) with the old name and location of
# another file that was located in that same directory.
#
seq=`basename $0`
seqres=$RESULT_DIR/$seq
echo "QA output created by $seq"

tmp=/tmp/$$
status=1	# failure is the default!
trap "_cleanup; exit \$status" 0 1 2 3 15

_cleanup()
{
	cd /
	rm -fr $send_files_dir
	rm -f $tmp.*
}

# get standard environment, filters and checks
. ./common/rc
. ./common/filter

# real QA test starts here
_supported_fs btrfs
_require_test
_require_scratch
_require_fssum

send_files_dir=$TEST_DIR/btrfs-test-$seq

rm -f $seqres.full
rm -fr $send_files_dir
mkdir $send_files_dir

_scratch_mkfs >>$seqres.full 2>&1
_scratch_mount

# Create our test files and directory. Inode 259 (file3) has two hard links.
touch $SCRATCH_MNT/file1
touch $SCRATCH_MNT/file2
touch $SCRATCH_MNT/file3

mkdir $SCRATCH_MNT/A
ln $SCRATCH_MNT/file3 $SCRATCH_MNT/A/hard_link

# Filesystem looks like:
#
# .                                     (ino 256)
# |----- file1                          (ino 257)
# |----- file2                          (ino 258)
# |----- file3                          (ino 259)
# |----- A/                             (ino 260)
#        |---- hard_link                (ino 259)
#

# Now create the base snapshot, which is going to be the parent snapshot for
# a later incremental send and receive.
$BTRFS_UTIL_PROG subvolume snapshot -r $SCRATCH_MNT \
	$SCRATCH_MNT/mysnap1 > /dev/null

$BTRFS_UTIL_PROG send -f $send_files_dir/1.snap \
	$SCRATCH_MNT/mysnap1 2>&1 1>/dev/null | _filter_scratch

# Move inode 257 into directory inode 260. This results in computing the path
# for inode 260 as "/A" and caching it.
mv $SCRATCH_MNT/file1 $SCRATCH_MNT/A/file1

# Move inode 258 (file2) into directory inode 260, with a name of "hard_link",
# moving first inode 259 away since it currently has that location and name.
mv $SCRATCH_MNT/A/hard_link $SCRATCH_MNT/tmp
mv $SCRATCH_MNT/file2 $SCRATCH_MNT/A/hard_link

# Now rename inode 260 to something else (B for example) and then create a hard
# link for inode 258 that has the old name and location of inode 260 ("/A").
mv $SCRATCH_MNT/A $SCRATCH_MNT/B
ln $SCRATCH_MNT/B/hard_link $SCRATCH_MNT/A

# Filesystem now looks like:
#
# .                                     (ino 256)
# |----- tmp                            (ino 259)
# |----- file3                          (ino 259)
# |----- B/                             (ino 260)
# |      |---- file1                    (ino 257)
# |      |---- hard_link                (ino 258)
# |
# |----- A                              (ino 258)

# Create another snapshot of our subvolume and use it for an incremental send.
$BTRFS_UTIL_PROG subvolume snapshot -r $SCRATCH_MNT \
		 $SCRATCH_MNT/mysnap2 > /dev/null
$BTRFS_UTIL_PROG send -p $SCRATCH_MNT/mysnap1 -f $send_files_dir/2.snap \
		 $SCRATCH_MNT/mysnap2 2>&1 1>/dev/null | _filter_scratch

$FSSUM_PROG -A -f -w $send_files_dir/1.fssum $SCRATCH_MNT/mysnap1
$FSSUM_PROG -A -f -w $send_files_dir/2.fssum \
	-x $SCRATCH_MNT/mysnap2/mysnap1 $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

# First add the first snapshot to the new filesystem by applying the first send
# stream.
$BTRFS_UTIL_PROG receive -f $send_files_dir/1.snap $SCRATCH_MNT > /dev/null

# The incremental receive operation below used to fail with the following error:
#
#    ERROR: unlink A/hard_link failed: No such file or directory
#
# This is because when send is processing inode 257, it generates the path for
# inode 260 as "/A", since that inode is its parent in the send snapshot, and
# caches that path.
#
# Later when processing inode 258, it first processes its new reference that has
# the path of "/A", which results in orphanizing inode 260 because there is a
# a path collision. This results in issuing a rename operation from "/A" to
# "/o260-6-0".
#
# Finally when processing the new reference "B/hard_link" for inode 258, it
# notices that it collides with inode 259 (not yet processed, because it has a
# higher inode number), since that inode has the name "hard_link" under the
# directory inode 260. It also checks that inode 259 has two hardlinks, so it
# decides to issue a unlink operation for the name "hard_link" for inode 259.
# However the path passed to the unlink operation is "/A/hard_link", which is
# incorrect since currently "/A" does not exists, due to the orphanization of
# inode 260 mentioned before. The path is incorrect because it was computed and
# cached before the orphanization. This results in the receiver to fail with the
# above error.
#
$BTRFS_UTIL_PROG receive -f $send_files_dir/2.snap $SCRATCH_MNT > /dev/null

$FSSUM_PROG -r $send_files_dir/1.fssum $SCRATCH_MNT/mysnap1
$FSSUM_PROG -r $send_files_dir/2.fssum $SCRATCH_MNT/mysnap2

status=0
exit