From 5858995b1f4e14f52230c70bfe9f83df295b04ec Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Thu, 30 Mar 2023 09:46:17 -0700 Subject: [PATCH] generic/{251,260}: compute maximum fitrim offset FITRIM is a bizarre ioctl. Callers are allowed to pass in "start" and "length" parameters, which are clearly some kind of range argument. No means is provided to discover the minimum or maximum range. Although regular userspace programs default to (start=0, length=-1ULL), this test tries to exercise different parameters. However, the test assumes that the "size" column returned by the df command is the maximum value supported by the FITRIM command, and is surprised if the number of bytes trimmed by (start=0, length=-1ULL) is larger than this size quantity. This is completely wrong on XFS with realtime volumes, because the statfs output (which is what df reports) will reflect the realtime volume if the directory argument is a realtime file or a directory flagged with rtinherit. This is trivially reproducible by configuring a rt volume that is much larger than the data volume, setting rtinherit on the root dir at mkfs time, and running either of these tests. Refactor the open-coded df logic so that we can determine the value programmatically for XFS. Signed-off-by: Darrick J. Wong Reviewed-by: David Disseldorp Signed-off-by: Zorro Lang --- common/rc | 15 +++++++++++++++ common/xfs | 8 ++++++++ tests/generic/251 | 2 +- tests/generic/260 | 2 +- 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/common/rc b/common/rc index 9e4475c0..e89b0a37 100644 --- a/common/rc +++ b/common/rc @@ -3927,6 +3927,21 @@ _require_batched_discard() fi } +# Given a mountpoint and the device associated with that mountpoint, return the +# maximum start offset that the FITRIM command will accept, in units of 1024 +# byte blocks. +_discard_max_offset_kb() +{ + case "$FSTYP" in + xfs) + _xfs_discard_max_offset_kb "$1" + ;; + *) + $DF_PROG -k | awk -v dev="$2" -v mnt="$1" '$1 == dev && $7 == mnt { print $3 }' + ;; + esac +} + _require_dumpe2fs() { if [ -z "$DUMPE2FS_PROG" ]; then diff --git a/common/xfs b/common/xfs index e8e4832c..c558e940 100644 --- a/common/xfs +++ b/common/xfs @@ -1783,3 +1783,11 @@ _require_xfs_scratch_atomicswap() _notrun "atomicswap dependencies not supported by scratch filesystem type: $FSTYP" _scratch_unmount } + +# Return the maximum start offset that the FITRIM command will accept, in units +# of 1024 byte blocks. +_xfs_discard_max_offset_kb() +{ + $XFS_IO_PROG -c 'statfs' "$1" | \ + awk '{g[$1] = $3} END {print (g["geom.bsize"] * g["geom.datablocks"] / 1024)}' +} diff --git a/tests/generic/251 b/tests/generic/251 index 2a271cd1..8ee74980 100755 --- a/tests/generic/251 +++ b/tests/generic/251 @@ -71,7 +71,7 @@ _guess_max_minlen() fstrim_loop() { trap "_destroy_fstrim; exit \$status" 2 15 - fsize=$($DF_PROG | grep $SCRATCH_MNT | grep $SCRATCH_DEV | awk '{print $3}') + fsize=$(_discard_max_offset_kb "$SCRATCH_MNT" "$SCRATCH_DEV") mmlen=$(_guess_max_minlen) while true ; do diff --git a/tests/generic/260 b/tests/generic/260 index 2f653b4a..08fde468 100755 --- a/tests/generic/260 +++ b/tests/generic/260 @@ -27,7 +27,7 @@ _scratch_mount _require_batched_discard $SCRATCH_MNT -fssize=$($DF_PROG -k | grep "$SCRATCH_MNT" | grep "$SCRATCH_DEV" | awk '{print $3}') +fssize=$(_discard_max_offset_kb "$SCRATCH_MNT" "$SCRATCH_DEV") beyond_eofs=$(_math "$fssize*2048") max_64bit=$(_math "2^64 - 1") -- 2.39.5