From: "Darrick J. Wong" <djwong@xxxxxxxxxx> Move the common atomic writes code to common/atomicwrites so we can share them. Signed-off-by: "Darrick J. Wong" <djwong@xxxxxxxxxx> Signed-off-by: Catherine Hoang <catherine.hoang@xxxxxxxxxx> Reviewed-by: John Garry <john.g.garry@xxxxxxxxxx> Reviewed-by: Ritesh Harjani (IBM) <ritesh.list@xxxxxxxxx> Reviewed-by: Ojaswin Mujoo <ojaswin@xxxxxxxxxxxxx> --- common/atomicwrites | 111 ++++++++++++++++++++++++++++++++++++++++++++ common/rc | 47 ------------------- tests/generic/765 | 53 ++------------------- 3 files changed, 114 insertions(+), 97 deletions(-) create mode 100644 common/atomicwrites diff --git a/common/atomicwrites b/common/atomicwrites new file mode 100644 index 00000000..fd3a9b71 --- /dev/null +++ b/common/atomicwrites @@ -0,0 +1,111 @@ +##/bin/bash +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2025 Oracle. All Rights Reserved. +# +# Routines for testing atomic writes. + +_get_atomic_write_unit_min() +{ + $XFS_IO_PROG -c "statx -r -m $STATX_WRITE_ATOMIC" $1 | \ + grep atomic_write_unit_min | grep -o '[0-9]\+' +} + +_get_atomic_write_unit_max() +{ + $XFS_IO_PROG -c "statx -r -m $STATX_WRITE_ATOMIC" $1 | \ + grep -w atomic_write_unit_max | grep -o '[0-9]\+' +} + +_get_atomic_write_segments_max() +{ + $XFS_IO_PROG -c "statx -r -m $STATX_WRITE_ATOMIC" $1 | \ + grep -w atomic_write_segments_max | grep -o '[0-9]\+' +} + +_require_scratch_write_atomic() +{ + _require_scratch + + export STATX_WRITE_ATOMIC=0x10000 + + awu_min_bdev=$(_get_atomic_write_unit_min $SCRATCH_DEV) + awu_max_bdev=$(_get_atomic_write_unit_max $SCRATCH_DEV) + + if [ $awu_min_bdev -eq 0 ] && [ $awu_max_bdev -eq 0 ]; then + _notrun "write atomic not supported by this block device" + fi + + _scratch_mkfs > /dev/null 2>&1 + _scratch_mount + + testfile=$SCRATCH_MNT/testfile + touch $testfile + + awu_min_fs=$(_get_atomic_write_unit_min $testfile) + awu_max_fs=$(_get_atomic_write_unit_max $testfile) + + _scratch_unmount + + if [ $awu_min_fs -eq 0 ] && [ $awu_max_fs -eq 0 ]; then + _notrun "write atomic not supported by this filesystem" + fi +} + +_test_atomic_file_writes() +{ + local bsize="$1" + local testfile="$2" + local bytes_written + local testfile_cp="$testfile.copy" + + # Check that we can perform an atomic write of len = FS block size + bytes_written=$($XFS_IO_PROG -dc "pwrite -A -D -V1 -b $bsize 0 $bsize" $testfile | \ + grep wrote | awk -F'[/ ]' '{print $2}') + test $bytes_written -eq $bsize || echo "atomic write len=$bsize failed" + + # Check that we can perform an atomic single-block cow write + if [ "$FSTYP" == "xfs" ]; then + testfile_cp=$SCRATCH_MNT/testfile_copy + if _xfs_has_feature $SCRATCH_MNT reflink; then + cp --reflink $testfile $testfile_cp + fi + bytes_written=$($XFS_IO_PROG -dc "pwrite -A -D -V1 -b $bsize 0 $bsize" $testfile_cp | \ + grep wrote | awk -F'[/ ]' '{print $2}') + test $bytes_written -eq $bsize || echo "atomic write on reflinked file failed" + fi + + # Check that we can perform an atomic write on an unwritten block + $XFS_IO_PROG -c "falloc $bsize $bsize" $testfile + bytes_written=$($XFS_IO_PROG -dc "pwrite -A -D -V1 -b $bsize $bsize $bsize" $testfile | \ + grep wrote | awk -F'[/ ]' '{print $2}') + test $bytes_written -eq $bsize || echo "atomic write to unwritten block failed" + + # Check that we can perform an atomic write on a sparse hole + $XFS_IO_PROG -c "fpunch 0 $bsize" $testfile + bytes_written=$($XFS_IO_PROG -dc "pwrite -A -D -V1 -b $bsize 0 $bsize" $testfile | \ + grep wrote | awk -F'[/ ]' '{print $2}') + test $bytes_written -eq $bsize || echo "atomic write to sparse hole failed" + + # Check that we can perform an atomic write on a fully mapped block + bytes_written=$($XFS_IO_PROG -dc "pwrite -A -D -V1 -b $bsize 0 $bsize" $testfile | \ + grep wrote | awk -F'[/ ]' '{print $2}') + test $bytes_written -eq $bsize || echo "atomic write to mapped block failed" + + # Reject atomic write if len is out of bounds + $XFS_IO_PROG -dc "pwrite -A -D -V1 -b $bsize 0 $((bsize - 1))" $testfile 2>> $seqres.full && \ + echo "atomic write len=$((bsize - 1)) should fail" + $XFS_IO_PROG -dc "pwrite -A -D -V1 -b $bsize 0 $((bsize + 1))" $testfile 2>> $seqres.full && \ + echo "atomic write len=$((bsize + 1)) should fail" + + # Reject atomic write when iovecs > 1 + $XFS_IO_PROG -dc "pwrite -A -D -V2 -b $bsize 0 $bsize" $testfile 2>> $seqres.full && \ + echo "atomic write only supports iovec count of 1" + + # Reject atomic write when not using direct I/O + $XFS_IO_PROG -c "pwrite -A -V1 -b $bsize 0 $bsize" $testfile 2>> $seqres.full && \ + echo "atomic write requires direct I/O" + + # Reject atomic write when offset % bsize != 0 + $XFS_IO_PROG -dc "pwrite -A -D -V1 -b $bsize 1 $bsize" $testfile 2>> $seqres.full && \ + echo "atomic write requires offset to be aligned to bsize" +} diff --git a/common/rc b/common/rc index f7d38894..94ae3d8c 100644 --- a/common/rc +++ b/common/rc @@ -5443,53 +5443,6 @@ _require_scratch_btime() _scratch_unmount } -_get_atomic_write_unit_min() -{ - $XFS_IO_PROG -c "statx -r -m $STATX_WRITE_ATOMIC" $1 | \ - grep atomic_write_unit_min | grep -o '[0-9]\+' -} - -_get_atomic_write_unit_max() -{ - $XFS_IO_PROG -c "statx -r -m $STATX_WRITE_ATOMIC" $1 | \ - grep -w atomic_write_unit_max | grep -o '[0-9]\+' -} - -_get_atomic_write_segments_max() -{ - $XFS_IO_PROG -c "statx -r -m $STATX_WRITE_ATOMIC" $1 | \ - grep -w atomic_write_segments_max | grep -o '[0-9]\+' -} - -_require_scratch_write_atomic() -{ - _require_scratch - - export STATX_WRITE_ATOMIC=0x10000 - - awu_min_bdev=$(_get_atomic_write_unit_min $SCRATCH_DEV) - awu_max_bdev=$(_get_atomic_write_unit_max $SCRATCH_DEV) - - if [ $awu_min_bdev -eq 0 ] && [ $awu_max_bdev -eq 0 ]; then - _notrun "write atomic not supported by this block device" - fi - - _scratch_mkfs > /dev/null 2>&1 - _scratch_mount - - testfile=$SCRATCH_MNT/testfile - touch $testfile - - awu_min_fs=$(_get_atomic_write_unit_min $testfile) - awu_max_fs=$(_get_atomic_write_unit_max $testfile) - - _scratch_unmount - - if [ $awu_min_fs -eq 0 ] && [ $awu_max_fs -eq 0 ]; then - _notrun "write atomic not supported by this filesystem" - fi -} - _require_inode_limits() { if [ $(_get_free_inode $TEST_DIR) -eq 0 ]; then diff --git a/tests/generic/765 b/tests/generic/765 index 84381730..09e9fa38 100755 --- a/tests/generic/765 +++ b/tests/generic/765 @@ -9,6 +9,8 @@ . ./common/preamble _begin_fstest auto quick rw atomicwrites +. ./common/atomicwrites + _require_scratch_write_atomic _require_xfs_io_command pwrite -A @@ -87,56 +89,7 @@ test_atomic_writes() test $file_max_segments -eq 1 || \ echo "atomic write max segments $file_max_segments, should be 1" - # Check that we can perform an atomic write of len = FS block size - bytes_written=$($XFS_IO_PROG -dc "pwrite -A -D -V1 -b $bsize 0 $bsize" $testfile | \ - grep wrote | awk -F'[/ ]' '{print $2}') - test $bytes_written -eq $bsize || echo "atomic write len=$bsize failed" - - # Check that we can perform an atomic single-block cow write - if [ "$FSTYP" == "xfs" ]; then - testfile_cp=$SCRATCH_MNT/testfile_copy - if _xfs_has_feature $SCRATCH_MNT reflink; then - cp --reflink $testfile $testfile_cp - fi - bytes_written=$($XFS_IO_PROG -dc "pwrite -A -D -V1 -b $bsize 0 $bsize" $testfile_cp | \ - grep wrote | awk -F'[/ ]' '{print $2}') - test $bytes_written -eq $bsize || echo "atomic write on reflinked file failed" - fi - - # Check that we can perform an atomic write on an unwritten block - $XFS_IO_PROG -c "falloc $bsize $bsize" $testfile - bytes_written=$($XFS_IO_PROG -dc "pwrite -A -D -V1 -b $bsize $bsize $bsize" $testfile | \ - grep wrote | awk -F'[/ ]' '{print $2}') - test $bytes_written -eq $bsize || echo "atomic write to unwritten block failed" - - # Check that we can perform an atomic write on a sparse hole - $XFS_IO_PROG -c "fpunch 0 $bsize" $testfile - bytes_written=$($XFS_IO_PROG -dc "pwrite -A -D -V1 -b $bsize 0 $bsize" $testfile | \ - grep wrote | awk -F'[/ ]' '{print $2}') - test $bytes_written -eq $bsize || echo "atomic write to sparse hole failed" - - # Check that we can perform an atomic write on a fully mapped block - bytes_written=$($XFS_IO_PROG -dc "pwrite -A -D -V1 -b $bsize 0 $bsize" $testfile | \ - grep wrote | awk -F'[/ ]' '{print $2}') - test $bytes_written -eq $bsize || echo "atomic write to mapped block failed" - - # Reject atomic write if len is out of bounds - $XFS_IO_PROG -dc "pwrite -A -D -V1 -b $bsize 0 $((bsize - 1))" $testfile 2>> $seqres.full && \ - echo "atomic write len=$((bsize - 1)) should fail" - $XFS_IO_PROG -dc "pwrite -A -D -V1 -b $bsize 0 $((bsize + 1))" $testfile 2>> $seqres.full && \ - echo "atomic write len=$((bsize + 1)) should fail" - - # Reject atomic write when iovecs > 1 - $XFS_IO_PROG -dc "pwrite -A -D -V2 -b $bsize 0 $bsize" $testfile 2>> $seqres.full && \ - echo "atomic write only supports iovec count of 1" - - # Reject atomic write when not using direct I/O - $XFS_IO_PROG -c "pwrite -A -V1 -b $bsize 0 $bsize" $testfile 2>> $seqres.full && \ - echo "atomic write requires direct I/O" - - # Reject atomic write when offset % bsize != 0 - $XFS_IO_PROG -dc "pwrite -A -D -V1 -b $bsize 1 $bsize" $testfile 2>> $seqres.full && \ - echo "atomic write requires offset to be aligned to bsize" + _test_atomic_file_writes "$bsize" "$testfile" _scratch_unmount } -- 2.34.1