#! /bin/bash # SPDX-License-Identifier: GPL-2.0 # Copyright (C) 2022 SUSE Linux Products GmbH. All Rights Reserved. # # FS QA Test 260 # # Make sure "btrfs filesystem defragment" can still convert the compression # algorithm of all regular extents. # . ./common/preamble _begin_fstest auto quick defrag compress prealloc fiemap # Override the default cleanup function. # _cleanup() # { # cd / # rm -r -f $tmp.* # } # Import common functions. . ./common/filter # real QA test starts here # Modify as appropriate. _supported_fs btrfs _require_scratch _require_xfs_io_command "fiemap" "ranged" _require_xfs_io_command "falloc" _require_btrfs_command inspect-internal dump-tree get_inode_number() { local file="$1" stat -c "%i" "$file" } get_file_extent() { local file="$1" local offset="$2" local ino=$(get_inode_number "$file") local file_extent_key="($ino EXTENT_DATA $offset)" $BTRFS_UTIL_PROG inspect-internal dump-tree -t 5 $SCRATCH_DEV |\ grep -A4 "$file_extent_key" } check_file_extent() { local file="$1" local offset="$2" local expected="$3" echo "=== file extent at file '$file' offset $offset ===" >> $seqres.full get_file_extent "$file" "$offset" > $tmp.output cat $tmp.output >> $seqres.full grep -q "$expected" $tmp.output ||\ echo "file \"$file\" offset $offset doesn't have expected string \"$expected\"" } # Unlike file extents whose btrfs specific attributes need to be grabbed from # dump-tree, we can check holes by fiemap. And mkfs enables no-holes feature by # default in recent versions of btrfs-progs, preventing us from grabbing holes # from dump-tree. check_hole() { local file="$1" local offset="$2" local len="$3" output=$($XFS_IO_PROG -c "fiemap $offset $len" "$file" |\ _filter_xfs_io_fiemap | head -n1) if [ -z $output ]; then echo "=== file extent at file '$file' offset $offset is a hole ===" \ >> $seqres.full else echo "=== file extent at file '$file' offset $offset is not a hole ===" fi } # Needs 4K sectorsize as the test is crafted using that sectorsize _require_btrfs_support_sectorsize 4096 _scratch_mkfs -s 4k >> $seqres.full 2>&1 # Initial data is compressed using lzo _scratch_mount -o compress=lzo # file 'large' has all of its compressed extents at their maximum size $XFS_IO_PROG -f -c "pwrite 0 1m" "$SCRATCH_MNT/large" >> $seqres.full # file 'fragment' has all of its compressed extents adjacent to # preallocated/hole ranges, which should not be defragged with regular # defrag ioctl, but should still be defragged by # "btrfs filesystem defragment -c" $XFS_IO_PROG -f -c "pwrite 0 16k" \ -c "pwrite 32k 16k" -c "pwrite 64k 16k" \ "$SCRATCH_MNT/fragment" >> $seqres.full sync # We only do the falloc after the compressed data reached disk. # Or the inode could have PREALLOC flag, and prevent the # data from being compressed. $XFS_IO_PROG -c "falloc 16k 16k" "$SCRATCH_MNT/fragment" sync echo "====== Before the defrag ======" >> $seqres.full # Should be lzo compressed check_file_extent "$SCRATCH_MNT/large" 0 "compression 2" # Should be lzo compressed check_file_extent "$SCRATCH_MNT/fragment" 0 "compression 2" # Should be preallocated check_file_extent "$SCRATCH_MNT/fragment" 16384 "type 2" # Should be lzo compressed check_file_extent "$SCRATCH_MNT/fragment" 32768 "compression 2" # Should be hole check_hole "$SCRATCH_MNT/fragment" 49152 16384 # Should be lzo compressed check_file_extent "$SCRATCH_MNT/fragment" 65536 "compression 2" $BTRFS_UTIL_PROG filesystem defragment "$SCRATCH_MNT/large" -czstd \ "$SCRATCH_MNT/fragment" >> $seqres.full # Need to commit the transaction or dump-tree won't grab the new # metadata on-disk. sync echo "====== After the defrag ======" >> $seqres.full # Should be zstd compressed check_file_extent "$SCRATCH_MNT/large" 0 "compression 3" # Should be zstd compressed check_file_extent "$SCRATCH_MNT/fragment" 0 "compression 3" # Should be preallocated check_file_extent "$SCRATCH_MNT/fragment" 16384 "type 2" # Should be zstd compressed check_file_extent "$SCRATCH_MNT/fragment" 32768 "compression 3" # Should be hole check_hole "$SCRATCH_MNT/fragment" 49152 16384 # Should be zstd compressed check_file_extent "$SCRATCH_MNT/fragment" 65536 "compression 3" echo "Silence is golden" # success, all done status=0 exit