#! /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 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