From b887c9f7bd387d9dfadce26ce384e4f889c683cb Mon Sep 17 00:00:00 2001 From: Boris Burkov Date: Thu, 28 Sep 2023 16:16:45 -0700 Subject: btrfs/301: new test for simple quotas Test some interesting basic and edge cases of simple quotas. To some extent, this is redundant with the alternate testing strategy of using MKFS_OPTIONS to enable simple quotas, running the full suite and relying on kernel warnings and fsck to surface issues. Signed-off-by: Boris Burkov Signed-off-by: Zorro Lang --- tests/btrfs/301 | 444 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/btrfs/301.out | 18 +++ 2 files changed, 462 insertions(+) create mode 100755 tests/btrfs/301 create mode 100644 tests/btrfs/301.out diff --git a/tests/btrfs/301 b/tests/btrfs/301 new file mode 100755 index 00000000..7a0b4c0e --- /dev/null +++ b/tests/btrfs/301 @@ -0,0 +1,444 @@ +#! /bin/bash +# SPDX-License-Identifier: GPL-2.0 +# Copyright (c) 2023 Meta Platforms, Inc. All Rights Reserved. +# +# FS QA Test 301 +# +# Test common btrfs simple quotas scenarios involving sharing extents and +# removing them in various orders. +# +. ./common/preamble +_begin_fstest auto quick qgroup clone subvol prealloc snapshot + +# Import common functions. +. ./common/reflink + +# Real QA test starts here. + +# Modify as appropriate. +_supported_fs btrfs +_require_scratch_reflink +_require_cp_reflink +_require_btrfs_command inspect-internal dump-tree +_require_xfs_io_command "falloc" +_require_scratch_enable_simple_quota + +subv=$SCRATCH_MNT/subv +nested=$SCRATCH_MNT/subv/nested +snap=$SCRATCH_MNT/snap +nr_fill=512 +fill_sz=$((8 * 1024)) +total_fill=$(($nr_fill * $fill_sz)) +nodesize=$($BTRFS_UTIL_PROG inspect-internal dump-super $SCRATCH_DEV | \ + grep nodesize | $AWK_PROG '{print $2}') +ext_sz=$((128 * 1024 * 1024)) +limit_nr=8 +limit=$(($ext_sz * $limit_nr)) + +prep_fio_config=$tmp.fio +fio_out=$tmp.fio.out +cat >$prep_fio_config <> $seqres.full + _scratch_mount + enable_quota "s" + $BTRFS_UTIL_PROG subvolume create $subv >> $seqres.full + set_subvol_limit 256 $limit + check_subvol_usage 256 0 + + # Create a bunch of little filler files to generate several levels in + # the btree, to make snapshotting sharing scenarios complex enough. + $FIO_PROG $prep_fio_config --output=$fio_out + check_subvol_usage 256 $total_fill + + # Create a single file whose extents we will explicitly share/unshare. + do_write $subv/f $ext_sz + check_subvol_usage 256 $(($total_fill + $ext_sz)) +} + +prepare_snapshotted() +{ + prepare + $BTRFS_UTIL_PROG subvolume snapshot $subv $snap >> $seqres.full + check_subvol_usage 256 $(($total_fill + $ext_sz)) + check_subvol_usage 257 0 +} + +prepare_nested() +{ + prepare + $BTRFS_UTIL_PROG qgroup create 1/100 $SCRATCH_MNT + $BTRFS_UTIL_PROG qgroup limit $limit 1/100 $SCRATCH_MNT + $BTRFS_UTIL_PROG qgroup assign 0/256 1/100 $SCRATCH_MNT >> $seqres.full + $BTRFS_UTIL_PROG subvolume create $nested >> $seqres.full + do_write $nested/f $ext_sz + check_subvol_usage 257 $ext_sz + check_subvol_usage 256 $(($total_fill + $ext_sz)) + local subv_usage=$(get_subvol_usage 256) + local nested_usage=$(get_subvol_usage 257) + check_qgroup_usage 1/100 $(($subv_usage + $nested_usage)) +} + +# Write in a single subvolume, including going over the limit. +basic_accounting() +{ + echo "basic accounting" + prepare + rm $subv/f + check_subvol_usage 256 $total_fill + cycle_mount_check_subvol_usage 256 $total_fill + do_write $subv/tmp 512M + rm $subv/tmp + do_write $subv/tmp 512M + rm $subv/tmp + do_enospc_falloc $subv/large_falloc 2G + do_enospc_write $subv/large 2G + _scratch_unmount +} + +# Write to the same range of a file a bunch of times in a row +# to test extent aware reservations. +reservation_accounting() +{ + echo "reservation accounting" + prepare + for i in $(seq 10); do + do_write $subv/tmp 512M + rm $subv/tmp + done + do_enospc_write $subv/large 2G + _scratch_unmount +} + +# Write in a snapshot. +snapshot_accounting() +{ + echo "snapshot accounting" + prepare_snapshotted + touch $snap/f + check_subvol_usage 256 $(($total_fill + $ext_sz)) + check_subvol_usage 257 0 + do_write $snap/f $ext_sz + check_subvol_usage 256 $(($total_fill + $ext_sz)) + check_subvol_usage 257 $ext_sz + rm $snap/f + check_subvol_usage 256 $(($total_fill + $ext_sz)) + check_subvol_usage 257 0 + rm $subv/f + check_subvol_usage 256 $total_fill + check_subvol_usage 257 0 + cycle_mount_check_subvol_usage 256 $total_fill + check_subvol_usage 257 0 + _scratch_unmount +} + +# Delete the original ref first after a snapshot. +delete_snapshot_src_ref() +{ + echo "delete src ref first" + prepare_snapshotted + rm $subv/f + check_subvol_usage 256 $(($total_fill + $ext_sz)) + check_subvol_usage 257 0 + rm $snap/f + trigger_cleaner + check_subvol_usage 256 $total_fill + check_subvol_usage 257 0 + cycle_mount_check_subvol_usage 256 $total_fill + check_subvol_usage 257 0 + _scratch_unmount +} + +# Delete the snapshot ref first after a snapshot. +delete_snapshot_ref() +{ + echo "delete snapshot ref first" + prepare_snapshotted + rm $snap/f + check_subvol_usage 256 $(($total_fill + $ext_sz)) + check_subvol_usage 257 0 + rm $subv/f + check_subvol_usage 256 $total_fill + check_subvol_usage 257 0 + cycle_mount_check_subvol_usage 256 $total_fill + check_subvol_usage 257 0 + _scratch_unmount +} + +# Delete the snapshotted subvolume after a snapshot. +delete_snapshot_src() +{ + echo "delete snapshot src first" + prepare_snapshotted + $BTRFS_UTIL_PROG subvolume delete $subv >> $seqres.full + check_subvol_usage 256 $(($total_fill + $ext_sz)) + check_subvol_usage 257 0 + rm $snap/f + trigger_cleaner + check_subvol_usage 256 $total_fill + check_subvol_usage 257 0 + $BTRFS_UTIL_PROG subvolume delete $snap >> $seqres.full + trigger_cleaner + check_subvol_usage 256 0 + check_subvol_usage 257 0 + cycle_mount_check_subvol_usage 256 0 + check_subvol_usage 257 0 + _scratch_unmount +} + +# Delete the snapshot subvolume after a snapshot. +delete_snapshot() +{ + echo "delete snapshot first" + prepare_snapshotted + $BTRFS_UTIL_PROG subvolume delete $snap >> $seqres.full + check_subvol_usage 256 $(($total_fill + $ext_sz)) + check_subvol_usage 257 0 + $BTRFS_UTIL_PROG subvolume delete $subv >> $seqres.full + trigger_cleaner + check_subvol_usage 256 0 + check_subvol_usage 257 0 + _scratch_unmount +} + +# Write to a subvolume nested in another subvolume. +# Exercises the auto-inheritance feature of simple quotas. +nested_accounting() +{ + echo "nested accounting" + prepare_nested + rm $subv/f + check_subvol_usage 256 $total_fill + check_subvol_usage 257 $ext_sz + local subv_usage=$(get_subvol_usage 256) + local nested_usage=$(get_subvol_usage 257) + check_qgroup_usage 1/100 $(($subv_usage + $nested_usage)) + rm $nested/f + check_subvol_usage 256 $total_fill + check_subvol_usage 257 0 + subv_usage=$(get_subvol_usage 256) + nested_usage=$(get_subvol_usage 257) + check_qgroup_usage 1/100 $(($subv_usage + $nested_usage)) + do_enospc_falloc $nested/large_falloc 2G + do_enospc_write $nested/large 2G + _scratch_unmount +} + +# Enable simple quotas on a filesystem with existing extents. +enable_mature() +{ + echo "enable mature" + _scratch_mkfs >> $seqres.full + _scratch_mount + $BTRFS_UTIL_PROG subvolume create $subv >> $seqres.full + do_write $subv/f $ext_sz + # Sync before enabling squotas to reliably *not* count the writes + # we did before enabling. + sync + enable_quota "s" + set_subvol_limit 256 $limit + _scratch_cycle_mount + usage=$(get_subvol_usage 256) + [ $usage -lt $ext_sz ] || \ + echo "captured usage from before enable $usage >= $ext_sz" + do_write $subv/g $ext_sz + usage=$(get_subvol_usage 256) + [ $usage -lt $ext_sz ] && \ + echo "failed to capture usage after enable $usage < $ext_sz" + check_subvol_usage 256 $ext_sz + rm $subv/f + check_subvol_usage 256 $ext_sz + _scratch_cycle_mount + rm $subv/g + check_subvol_usage 256 0 + _scratch_unmount +} + +# Reflink a file within the subvolume. +reflink_accounting() +{ + echo "reflink" + prepare + # Do enough reflinks to prove that they're free. If they counted, then + # this wouldn't fit in the limit. + for i in $(seq $(($limit_nr * 2))); do + _cp_reflink $subv/f $subv/f.i + done + # Confirm that there is no additional data usage from the reflinks. + check_subvol_usage 256 $(($total_fill + $ext_sz)) + _scratch_unmount +} + +# Delete the src ref of a reflink first. +delete_reflink_src_ref() +{ + echo "delete reflink src ref" + prepare + _cp_reflink $subv/f $subv/f.link + check_subvol_usage 256 $(($total_fill + $ext_sz)) + rm $subv/f + check_subvol_usage 256 $(($total_fill + $ext_sz)) + rm $subv/f.link + check_subvol_usage 256 $(($total_fill)) + _scratch_unmount +} + +# Delete the link ref of a reflink first. +delete_reflink_ref() +{ + echo "delete reflink ref" + prepare + _cp_reflink $subv/f $subv/f.link + check_subvol_usage 256 $(($total_fill + $ext_sz)) + rm $subv/f.link + check_subvol_usage 256 $(($total_fill + $ext_sz)) + rm $subv/f + check_subvol_usage 256 $(($total_fill)) + _scratch_unmount +} + +basic_accounting +reservation_accounting +snapshot_accounting +delete_snapshot_src_ref +delete_snapshot_ref +delete_snapshot_src +delete_snapshot +nested_accounting +enable_mature +reflink_accounting +delete_reflink_src_ref +delete_reflink_ref + +# success, all done +status=0 +exit diff --git a/tests/btrfs/301.out b/tests/btrfs/301.out new file mode 100644 index 00000000..1c502689 --- /dev/null +++ b/tests/btrfs/301.out @@ -0,0 +1,18 @@ +QA output created by 301 +basic accounting +fallocate: Disk quota exceeded +pwrite: Disk quota exceeded +reservation accounting +pwrite: Disk quota exceeded +snapshot accounting +delete src ref first +delete snapshot ref first +delete snapshot src first +delete snapshot first +nested accounting +fallocate: Disk quota exceeded +pwrite: Disk quota exceeded +enable mature +reflink +delete reflink src ref +delete reflink ref -- cgit v1.2.3