blob: 1c81f47e261b72fae005c6deb0d1cebd0a1accb9 [file] [log] [blame]
#! /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
_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 subvolume snapshot $SCRATCH_MNT $SCRATCH_MNT/snap
# 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