summaryrefslogtreecommitdiff
path: root/tests/btrfs/276
blob: f15f2082435021ae575a3dbdecb52c1122590b6f (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
#! /bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (C) 2022 SUSE Linux Products GmbH. All Rights Reserved.
#
# FS QA Test 276
#
# Verify that fiemap correctly reports the sharedness of extents for a file with
# a very large number of extents, spanning many b+tree leaves in the fs tree,
# and when the file's subvolume was snapshoted.
#
. ./common/preamble
_begin_fstest auto snapshot fiemap remount

. ./common/filter
. ./common/filter.btrfs
. ./common/attr

_supported_fs btrfs
_require_scratch
_require_xfs_io_command "fiemap" "ranged"
_require_attrs
_require_odirect

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

fiemap_test_file()
{
	local offset=$1
	local len=$2

	# Skip the first two lines of xfs_io's fiemap output (file path and
	# header describing the output columns) as well as holes.
	$XFS_IO_PROG -c "fiemap -v $offset $len" $SCRATCH_MNT/foo | \
		grep -v 'hole' | tail -n +3
}

# Count the number of shared extents for the whole test file or just for a given
# range.
count_shared_extents()
{
	local offset=$1
	local len=$2

	# Column 5 (from xfs_io's "fiemap -v" command) is the flags (hex field).
	# 0x2000 is the value for the FIEMAP_EXTENT_SHARED flag.
	fiemap_test_file $offset $len | \
		$AWK_PROG --source 'BEGIN { cnt = 0 }' \
			  --source '{ if (and(strtonum($5), 0x2000)) cnt++ }' \
			  --source 'END { print cnt }'
}

# Count the number of non shared extents for the whole test file or just for a
# given range.
count_not_shared_extents()
{
	local offset=$1
	local len=$2

	# Column 5 (from xfs_io's "fiemap -v" command) is the flags (hex field).
	# 0x2000 is the value for the FIEMAP_EXTENT_SHARED flag.
	fiemap_test_file $offset $len | \
		$AWK_PROG --source 'BEGIN { cnt = 0 }' \
			  --source '{ if (!and(strtonum($5), 0x2000)) cnt++ }' \
			  --source 'END { print cnt }'
}

# Create a file with 2000 extents, and a fs tree with a height of at least 3
# (root node at level 2). We want to verify later that fiemap correctly reports
# the sharedness of each extent, even when it needs to switch from one leaf to
# the next one and from a node at level 1 to the next node at level 1.
# To speedup creating a fs tree of height >= 3, add several large xattrs.
ext_size=$(( 64 * 1024 ))
file_size=$(( 2000 * 2 * $ext_size )) # about 250M
nr_cpus=$("$here/src/feature" -o)
workers=0
for (( i = 0; i < $file_size; i += 2 * $ext_size )); do
	$XFS_IO_PROG -f -d -c "pwrite -b $ext_size $i $ext_size" \
		$SCRATCH_MNT/foo > /dev/null &
	workers=$(( workers + 1 ))
	if [ "$workers" -ge "$nr_cpus" ]; then
		workers=0
		wait
	fi
done
wait

workers=0
xattr_value=$(printf '%0.sX' $(seq 1 3900))
for (( i = 1; i <= 29000; i++ )); do
	echo -n > $SCRATCH_MNT/filler_$i
	$SETFATTR_PROG -n 'user.x1' -v $xattr_value $SCRATCH_MNT/filler_$i &
	workers=$(( workers + 1 ))
	if [ "$workers" -ge "$nr_cpus" ]; then
		workers=0
		wait
	fi
done
wait

# Make sure every ordered extent completed and therefore updated the fs tree.
sync

# All extents should be reported as non shared (2000 extents).
echo "Number of non-shared extents in the whole file: $(count_not_shared_extents)"

# Creating a snapshot.
$BTRFS_UTIL_PROG subvolume snapshot $SCRATCH_MNT $SCRATCH_MNT/snap | _filter_scratch

# We have a snapshot, so now all extents should be reported as shared.
echo "Number of shared extents in the whole file: $(count_shared_extents)"

# Now COW two file ranges, of 64K each, in the snapshot's file.
# So 2 extents should become non-shared after this. Each file extent item is in
# different leaf of the snapshot tree.
#
$XFS_IO_PROG -d -c "pwrite -b $ext_size 512K $ext_size" \
	     -d -c "pwrite -b $ext_size 249M $ext_size" \
	     $SCRATCH_MNT/snap/foo | _filter_xfs_io

# Wait for ordered extents to complete and commit current transaction to make
# sure fiemap will see all extents in the subvolume and extent trees.
sync

# Now we should have 2 non-shared extents and 1998 shared extents.
echo "Number of non-shared extents in the whole file: $(count_not_shared_extents)"
echo "Number of shared extents in the whole file: $(count_shared_extents)"

# Check that the non-shared extents are indeed in the expected file ranges.
echo "Number of non-shared extents in range [512K, 512K + 64K): $(count_not_shared_extents 512K 64K)"
echo "Number of non-shared extents in range [249M, 249M + 64K): $(count_not_shared_extents 249M 64K)"

# Now delete the snapshot.
$BTRFS_UTIL_PROG subvolume delete -c $SCRATCH_MNT/snap | _filter_btrfs_subvol_delete

# We deleted the snapshot and committed the transaction used to delete it (-c),
# but all its extents (both metadata and data) are actually only deleted in the
# background, by the cleaner kthread. So remount, which wakes up the cleaner
# kthread, with a commit interval of 1 second and sleep for 1.1 seconds - after
# this we are guaranteed all extents of the snapshot were deleted.
_scratch_remount commit=1
sleep 1.1

# Now all extents should be reported as not shared (2000 extents).
echo "Number of non-shared extents in the whole file: $(count_not_shared_extents)"

# success, all done
status=0
exit