summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rwxr-xr-xcheck147
-rw-r--r--common/btrfs5
-rw-r--r--common/config5
-rw-r--r--common/dmerror167
-rw-r--r--common/encrypt2
-rw-r--r--common/ext4193
-rw-r--r--common/fail_make_request64
-rw-r--r--common/filter4
-rw-r--r--common/punch3
-rw-r--r--common/rc284
-rw-r--r--common/report105
-rw-r--r--common/verity48
-rw-r--r--common/xfs61
-rw-r--r--src/Makefile7
-rw-r--r--src/fscrypt-crypt-util.c357
-rw-r--r--src/seek_sanity_test.c36
-rw-r--r--src/t_mmap_cow_memory_failure.c157
-rw-r--r--src/t_ofd_locks.c2
-rw-r--r--src/uuid_ioctl.c105
-rw-r--r--src/vfs/idmapped-mounts.c1207
-rw-r--r--src/vfs/idmapped-mounts.h2
-rw-r--r--src/vfs/utils.c14
-rw-r--r--src/vfs/utils.h1
-rw-r--r--src/vfs/vfstest.c558
-rwxr-xr-xtests/btrfs/08814
-rwxr-xr-xtests/btrfs/15013
-rwxr-xr-xtests/btrfs/2021
-rwxr-xr-xtests/btrfs/2151
-rwxr-xr-xtests/btrfs/2532
-rwxr-xr-xtests/btrfs/2573
-rwxr-xr-xtests/btrfs/26187
-rw-r--r--tests/btrfs/261.out2
-rwxr-xr-xtests/btrfs/2681
-rwxr-xr-xtests/btrfs/2691
-rwxr-xr-xtests/btrfs/27012
-rw-r--r--tests/btrfs/270.out34
-rwxr-xr-xtests/btrfs/27160
-rw-r--r--tests/btrfs/271.out523
-rwxr-xr-xtests/btrfs/27288
-rw-r--r--tests/btrfs/272.out3
-rwxr-xr-xtests/btrfs/277115
-rw-r--r--tests/btrfs/277.out59
-rwxr-xr-xtests/btrfs/290172
-rw-r--r--tests/btrfs/290.out25
-rwxr-xr-xtests/btrfs/291168
-rw-r--r--tests/btrfs/291.out2
-rwxr-xr-xtests/ceph/0046
-rwxr-xr-xtests/ext4/0531
-rwxr-xr-xtests/ext4/05764
-rw-r--r--tests/ext4/057.out2
-rwxr-xr-xtests/ext4/05833
-rw-r--r--tests/ext4/058.out2
-rwxr-xr-xtests/ext4/05941
-rw-r--r--tests/ext4/059.out2
-rwxr-xr-xtests/generic/0172
-rwxr-xr-xtests/generic/01940
-rwxr-xr-xtests/generic/0311
-rwxr-xr-xtests/generic/0424
-rwxr-xr-xtests/generic/0642
-rwxr-xr-xtests/generic/0812
-rwxr-xr-xtests/generic/1082
-rwxr-xr-xtests/generic/1161
-rwxr-xr-xtests/generic/1181
-rwxr-xr-xtests/generic/1191
-rwxr-xr-xtests/generic/1211
-rwxr-xr-xtests/generic/1221
-rwxr-xr-xtests/generic/1341
-rwxr-xr-xtests/generic/1361
-rwxr-xr-xtests/generic/1371
-rwxr-xr-xtests/generic/1441
-rwxr-xr-xtests/generic/1491
-rwxr-xr-xtests/generic/1532
-rwxr-xr-xtests/generic/1582
-rwxr-xr-xtests/generic/1621
-rwxr-xr-xtests/generic/1631
-rwxr-xr-xtests/generic/1641
-rwxr-xr-xtests/generic/1651
-rwxr-xr-xtests/generic/1681
-rwxr-xr-xtests/generic/1701
-rwxr-xr-xtests/generic/1811
-rwxr-xr-xtests/generic/1831
-rwxr-xr-xtests/generic/1851
-rwxr-xr-xtests/generic/1861
-rwxr-xr-xtests/generic/1871
-rwxr-xr-xtests/generic/1881
-rwxr-xr-xtests/generic/1891
-rwxr-xr-xtests/generic/1901
-rwxr-xr-xtests/generic/1911
-rwxr-xr-xtests/generic/1941
-rwxr-xr-xtests/generic/1951
-rwxr-xr-xtests/generic/1961
-rwxr-xr-xtests/generic/1971
-rwxr-xr-xtests/generic/1991
-rwxr-xr-xtests/generic/2001
-rwxr-xr-xtests/generic/2011
-rwxr-xr-xtests/generic/27515
-rwxr-xr-xtests/generic/2841
-rwxr-xr-xtests/generic/2871
-rwxr-xr-xtests/generic/2891
-rwxr-xr-xtests/generic/2901
-rwxr-xr-xtests/generic/2911
-rwxr-xr-xtests/generic/2921
-rwxr-xr-xtests/generic/2931
-rwxr-xr-xtests/generic/2951
-rwxr-xr-xtests/generic/3521
-rwxr-xr-xtests/generic/3581
-rwxr-xr-xtests/generic/3591
-rwxr-xr-xtests/generic/3721
-rwxr-xr-xtests/generic/4042
-rwxr-xr-xtests/generic/4141
-rwxr-xr-xtests/generic/4412
-rwxr-xr-xtests/generic/4551
-rwxr-xr-xtests/generic/4571
-rwxr-xr-xtests/generic/4701
-rwxr-xr-xtests/generic/4821
-rwxr-xr-xtests/generic/4834
-rwxr-xr-xtests/generic/4842
-rwxr-xr-xtests/generic/4872
-rwxr-xr-xtests/generic/4954
-rwxr-xr-xtests/generic/5011
-rwxr-xr-xtests/generic/5034
-rwxr-xr-xtests/generic/5151
-rwxr-xr-xtests/generic/5161
-rwxr-xr-xtests/generic/5401
-rwxr-xr-xtests/generic/5411
-rwxr-xr-xtests/generic/5421
-rwxr-xr-xtests/generic/5431
-rwxr-xr-xtests/generic/5441
-rwxr-xr-xtests/generic/5461
-rwxr-xr-xtests/generic/57438
-rw-r--r--tests/generic/574.out13
-rwxr-xr-xtests/generic/5761
-rwxr-xr-xtests/generic/5781
-rwxr-xr-xtests/generic/5882
-rwxr-xr-xtests/generic/6282
-rwxr-xr-xtests/generic/6292
-rwxr-xr-xtests/generic/6482
-rwxr-xr-xtests/generic/6731
-rwxr-xr-xtests/generic/6741
-rwxr-xr-xtests/generic/6751
-rwxr-xr-xtests/generic/6774
-rwxr-xr-xtests/generic/6831
-rwxr-xr-xtests/generic/6841
-rwxr-xr-xtests/generic/6851
-rwxr-xr-xtests/generic/6861
-rwxr-xr-xtests/generic/6871
-rwxr-xr-xtests/generic/6881
-rw-r--r--tests/generic/69264
-rw-r--r--tests/generic/692.out7
-rwxr-xr-xtests/generic/69331
-rw-r--r--tests/generic/693.out16
-rwxr-xr-xtests/generic/69447
-rw-r--r--tests/generic/694.out2
-rwxr-xr-xtests/generic/69591
-rw-r--r--tests/generic/695.out15
-rwxr-xr-xtests/generic/69646
-rw-r--r--tests/generic/696.out2
-rwxr-xr-xtests/generic/69733
-rw-r--r--tests/generic/697.out2
-rw-r--r--tests/xfs/006.out6
-rwxr-xr-xtests/xfs/0154
-rwxr-xr-xtests/xfs/01815
-rw-r--r--tests/xfs/018.out43
-rwxr-xr-xtests/xfs/04214
-rw-r--r--tests/xfs/042.out4
-rwxr-xr-xtests/xfs/0691
-rwxr-xr-xtests/xfs/0762
-rwxr-xr-xtests/xfs/1142
-rwxr-xr-xtests/xfs/14414
-rwxr-xr-xtests/xfs/1664
-rwxr-xr-xtests/xfs/1801
-rwxr-xr-xtests/xfs/1821
-rwxr-xr-xtests/xfs/1841
-rwxr-xr-xtests/xfs/191120
-rw-r--r--tests/xfs/191.out7
-rwxr-xr-xtests/xfs/1921
-rwxr-xr-xtests/xfs/1931
-rwxr-xr-xtests/xfs/1981
-rwxr-xr-xtests/xfs/2001
-rwxr-xr-xtests/xfs/2034
-rwxr-xr-xtests/xfs/2041
-rwxr-xr-xtests/xfs/2081
-rwxr-xr-xtests/xfs/2091
-rwxr-xr-xtests/xfs/2101
-rwxr-xr-xtests/xfs/2111
-rwxr-xr-xtests/xfs/2121
-rwxr-xr-xtests/xfs/2151
-rwxr-xr-xtests/xfs/2181
-rwxr-xr-xtests/xfs/2191
-rwxr-xr-xtests/xfs/2211
-rwxr-xr-xtests/xfs/2231
-rwxr-xr-xtests/xfs/2241
-rwxr-xr-xtests/xfs/2251
-rwxr-xr-xtests/xfs/2261
-rwxr-xr-xtests/xfs/2281
-rwxr-xr-xtests/xfs/2301
-rwxr-xr-xtests/xfs/2311
-rwxr-xr-xtests/xfs/2321
-rwxr-xr-xtests/xfs/2371
-rwxr-xr-xtests/xfs/2391
-rwxr-xr-xtests/xfs/2401
-rwxr-xr-xtests/xfs/2411
-rwxr-xr-xtests/xfs/2481
-rwxr-xr-xtests/xfs/2491
-rwxr-xr-xtests/xfs/2511
-rwxr-xr-xtests/xfs/2541
-rwxr-xr-xtests/xfs/2551
-rwxr-xr-xtests/xfs/2561
-rwxr-xr-xtests/xfs/2571
-rwxr-xr-xtests/xfs/2581
-rw-r--r--tests/xfs/264.out12
-rwxr-xr-xtests/xfs/2706
-rwxr-xr-xtests/xfs/2801
-rwxr-xr-xtests/xfs/28832
-rwxr-xr-xtests/xfs/2916
-rwxr-xr-xtests/xfs/3121
-rwxr-xr-xtests/xfs/3151
-rwxr-xr-xtests/xfs/3221
-rwxr-xr-xtests/xfs/3261
-rwxr-xr-xtests/xfs/3291
-rwxr-xr-xtests/xfs/3461
-rwxr-xr-xtests/xfs/3471
-rwxr-xr-xtests/xfs/4323
-rwxr-xr-xtests/xfs/4361
-rwxr-xr-xtests/xfs/5073
-rwxr-xr-xtests/xfs/53340
-rw-r--r--tests/xfs/533.out5
-rwxr-xr-xtests/xfs/5372
-rwxr-xr-xtests/xfs/54714
-rwxr-xr-xtests/xfs/54929
-rw-r--r--tests/xfs/549.out2
-rwxr-xr-xtests/xfs/55050
-rw-r--r--tests/xfs/550.out9
-rwxr-xr-xtests/xfs/55151
-rw-r--r--tests/xfs/551.out9
-rwxr-xr-xtests/xfs/55254
-rw-r--r--tests/xfs/552.out9
-rwxr-xr-xtests/xfs/55367
-rw-r--r--tests/xfs/553.out9
240 files changed, 5767 insertions, 584 deletions
diff --git a/.gitignore b/.gitignore
index 0d44ac7f..866cccb0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -148,6 +148,7 @@ tags
/src/t_holes
/src/t_immutable
/src/t_mmap_collision
+/src/t_mmap_cow_memory_failure
/src/t_mmap_cow_race
/src/t_mmap_dio
/src/t_mmap_fallocate
@@ -173,6 +174,7 @@ tags
/src/unwritten_sync
/src/uring_read_fault
/src/usemem
+/src/uuid_ioctl
/src/writemod
/src/writev_on_pagefault
/src/xfsctl
diff --git a/check b/check
index 34cf060d..94256dcb 100755
--- a/check
+++ b/check
@@ -13,7 +13,7 @@ sum_bad=0
bad=()
notrun=()
interrupt=true
-failfast=0
+failfast=false
diff="diff -u"
showme=false
have_test_arg=false
@@ -27,6 +27,7 @@ do_report=false
DUMP_OUTPUT=false
iterations=1
istop=false
+loop_on_fail=0
# This is a global variable used to pass test failure text to reporting gunk
_err_msg=""
@@ -76,10 +77,11 @@ check options
-f failfast - halt after first test failure
-d dump test output to stdout
-b brief test summary
- -R fmt[,fmt] generate report in formats specified. Supported format: [xunit]
+ -R fmt[,fmt] generate report in formats specified. Supported formats: xunit, xunit-quiet
--large-fs optimise scratch device for large filesystems
-s section run only specified section from config file
-S section exclude the specified section from the config file
+ -L <n> loop tests <n> times following a failure, measuring aggregate pass/fail metrics
testlist options
-g group[,group...] include tests from these groups
@@ -181,10 +183,10 @@ get_all_tests()
# the function from that list.
trim_test_list()
{
- test_list="$*"
+ local test_list="$*"
rm -f $tmp.grep
- numsed=0
+ local numsed=0
for t in $test_list
do
if [ $numsed -gt 100 ]; then
@@ -209,7 +211,7 @@ _wallclock()
_timestamp()
{
- now=`date "+%T"`
+ local now=`date "+%T"`
echo -n " [$now]"
}
@@ -339,6 +341,9 @@ while [ $# -gt 0 ]; do
;;
--large-fs) export LARGE_SCRATCH_DEV=yes ;;
--extra-space=*) export SCRATCH_DEV_EMPTY_SPACE=${r#*=} ;;
+ -L) [[ $2 =~ ^[0-9]+$ ]] || usage
+ loop_on_fail=$2; shift
+ ;;
-*) usage ;;
*) # not an argument, we've got tests now.
@@ -435,7 +440,9 @@ _wrapup()
if $showme && $needwrap; then
if $do_report; then
# $showme = all selected tests are notrun (no tries)
- _make_section_report "${#notrun[*]}" "0" "${#notrun[*]}"
+ _make_section_report "$section" "${#notrun[*]}" "0" \
+ "${#notrun[*]}" \
+ "$((sect_stop - sect_start))"
fi
needwrap=false
elif $needwrap; then
@@ -496,7 +503,9 @@ _wrapup()
fi
echo "" >>$tmp.summary
if $do_report; then
- _make_section_report "${#try[*]}" "${#bad[*]}" "${#notrun[*]}"
+ _make_section_report "$section" "${#try[*]}" \
+ "${#bad[*]}" "${#notrun[*]}" \
+ "$((sect_stop - sect_start))"
fi
needwrap=false
fi
@@ -552,6 +561,72 @@ _expunge_test()
return 0
}
+# retain files which would be overwritten in subsequent reruns of the same test
+_stash_fail_loop_files() {
+ local seq_prefix="${REPORT_DIR}/${1}"
+ local cp_suffix="$2"
+
+ for i in ".full" ".dmesg" ".out.bad" ".notrun" ".core" ".hints"; do
+ rm -f "${seq_prefix}${i}${cp_suffix}"
+ if [ -f "${seq_prefix}${i}" ]; then
+ cp "${seq_prefix}${i}" "${seq_prefix}${i}${cp_suffix}"
+ fi
+ done
+}
+
+# Retain in @bad / @notrun the result of the just-run @test_seq. @try array
+# entries are added prior to execution.
+_stash_test_status() {
+ local test_seq="$1"
+ local test_status="$2"
+
+ if $do_report && [[ $test_status != "expunge" ]]; then
+ _make_testcase_report "$section" "$test_seq" \
+ "$test_status" "$((stop - start))"
+ fi
+
+ if ((${#loop_status[*]} > 0)); then
+ # continuing or completing rerun-on-failure loop
+ _stash_fail_loop_files "$test_seq" ".rerun${#loop_status[*]}"
+ loop_status+=("$test_status")
+ if ((${#loop_status[*]} > loop_on_fail)); then
+ printf "%s aggregate results across %d runs: " \
+ "$test_seq" "${#loop_status[*]}"
+ awk "BEGIN {
+ n=split(\"${loop_status[*]}\", arr);"'
+ for (i = 1; i <= n; i++)
+ stats[arr[i]]++;
+ for (x in stats)
+ printf("%s=%d (%.1f%%)",
+ (i-- > n ? x : ", " x),
+ stats[x], 100 * stats[x] / n);
+ }'
+ echo
+ loop_status=()
+ fi
+ return # only stash @bad result for initial failure in loop
+ fi
+
+ case "$test_status" in
+ fail)
+ if ((loop_on_fail > 0)); then
+ # initial failure, start rerun-on-failure loop
+ _stash_fail_loop_files "$test_seq" ".rerun0"
+ loop_status+=("$test_status")
+ fi
+ bad+=("$test_seq")
+ ;;
+ list|notrun)
+ notrun+=("$test_seq")
+ ;;
+ pass|expunge)
+ ;;
+ *)
+ echo "Unexpected test $test_seq status: $test_status"
+ ;;
+ esac
+}
+
# Can we run systemd scopes?
HAVE_SYSTEMD_SCOPES=
systemctl reset-failed "fstests-check" &>/dev/null
@@ -602,7 +677,7 @@ fi
function run_section()
{
- local section=$1
+ local section=$1 skip
OLD_FSTYP=$FSTYP
OLD_TEST_FS_MOUNT_OPTS=$TEST_FS_MOUNT_OPTS
@@ -731,18 +806,12 @@ function run_section()
seqres="$check"
_check_test_fs
- local tc_status="init"
- prev_seq=""
- for seq in $list ; do
- # Run report for previous test!
- if [ "$tc_status" == "fail" ]; then
- bad+=("$seqnum")
- fi
- if $do_report && [[ ! $tc_status =~ ^(init|expunge)$ ]]; then
- _make_testcase_report "$prev_seq" "$tc_status"
- fi
+ loop_status=() # track rerun-on-failure state
+ local tc_status ix
+ local -a _list=( $list )
+ for ((ix = 0; ix < ${#_list[*]}; !${#loop_status[*]} && ix++)); do
+ seq="${_list[$ix]}"
- prev_seq="$seq"
if [ ! -f $seq ]; then
# Try to get full name in case the user supplied only
# seq id and the test has a name. A bit of hassle to
@@ -782,20 +851,21 @@ function run_section()
if $showme; then
_expunge_test $seqnum
if [ $? -eq 1 ]; then
- tc_status="expunge"
- continue
+ tc_status="expunge"
+ else
+ echo
+ start=0
+ stop=0
+ tc_status="list"
fi
- echo
- start=0
- stop=0
- tc_status="list"
- notrun+=("$seqnum")
+ _stash_test_status "$seqnum" "$tc_status"
continue
fi
tc_status="pass"
if [ ! -f $seq ]; then
echo " - no such test?"
+ _stash_test_status "$seqnum" "$tc_status"
continue
fi
@@ -806,11 +876,14 @@ function run_section()
_expunge_test $seqnum
if [ $? -eq 1 ]; then
tc_status="expunge"
+ _stash_test_status "$seqnum" "$tc_status"
continue
fi
# record that we really tried to run this test.
- try+=("$seqnum")
+ if ((!${#loop_status[*]})); then
+ try+=("$seqnum")
+ fi
awk 'BEGIN {lasttime=" "} \
$1 == "'$seqnum'" {lasttime=" " $2 "s ... "; exit} \
@@ -818,7 +891,7 @@ function run_section()
rm -f core $seqres.notrun
start=`_wallclock`
- $timestamp && echo -n " ["`date "+%T"`"]"
+ $timestamp && _timestamp
[ ! -x $seq ] && chmod u+x $seq # ensure we can run it
$LOGGER_PROG "run xfstest $seqnum"
if [ -w /dev/kmsg ]; then
@@ -826,6 +899,7 @@ function run_section()
echo "run fstests $seqnum at $date_time" > /dev/kmsg
# _check_dmesg depends on this log in dmesg
touch ${RESULT_DIR}/check_dmesg
+ rm -f ${RESULT_DIR}/dmesg_filter
fi
_try_wipe_scratch_devs > /dev/null 2>&1
@@ -853,8 +927,8 @@ function run_section()
stop=`_wallclock`
cat $seqres.notrun
echo "========= NOTRUN $seqnum"
- notrun+=("$seqnum")
tc_status="notrun"
+ _stash_test_status "$seqnum" "$tc_status"
# Unmount the scratch fs so that we can wipe the scratch
# dev state prior to the next test run.
@@ -924,6 +998,12 @@ function run_section()
fi; } | sed -e 's/^\(.\)/ \1/'
tc_status="fail"
fi
+
+ if [ "$tc_status" == "fail" ]; then
+ echo "$seqres.full:"
+ cat $seqres.full
+ fi
+
if [ -f $seqres.hints ]; then
if [ "$tc_status" == "fail" ]; then
echo
@@ -945,16 +1025,9 @@ function run_section()
status=1
exit
fi
+ _stash_test_status "$seqnum" "$tc_status"
done
- # make sure we record the status of the last test we ran.
- if [ "$tc_status" == "fail" ]; then
- bad+=("$seqnum")
- fi
- if $do_report && [[ ! $tc_status =~ ^(init|expunge)$ ]]; then
- _make_testcase_report "$prev_seq" "$tc_status"
- fi
-
sect_stop=`_wallclock`
interrupt=false
_wrapup
diff --git a/common/btrfs b/common/btrfs
index 14ad890e..bd2639bf 100644
--- a/common/btrfs
+++ b/common/btrfs
@@ -580,3 +580,8 @@ _btrfs_buffered_read_on_mirror()
:
done
}
+
+_require_btrfs_corrupt_block()
+{
+ _require_command "$BTRFS_CORRUPT_BLOCK_PROG" btrfs-corrupt-block
+}
diff --git a/common/config b/common/config
index de3aba15..5eaae447 100644
--- a/common/config
+++ b/common/config
@@ -297,6 +297,7 @@ export BTRFS_UTIL_PROG=$(type -P btrfs)
export BTRFS_SHOW_SUPER_PROG=$(type -P btrfs-show-super)
export BTRFS_CONVERT_PROG=$(type -P btrfs-convert)
export BTRFS_TUNE_PROG=$(type -P btrfstune)
+export BTRFS_CORRUPT_BLOCK_PROG=$(type -P btrfs-corrupt-block)
export XFS_FSR_PROG=$(type -P xfs_fsr)
export MKFS_NFS_PROG="false"
export MKFS_CIFS_PROG="false"
@@ -511,6 +512,10 @@ _source_specific_fs()
;;
ext4)
[ "$MKFS_EXT4_PROG" = "" ] && _fatal "mkfs.ext4 not found"
+ . ./common/ext4
+ ;;
+ ext2|ext3|ext4dev)
+ . ./common/ext4
;;
f2fs)
[ "$MKFS_F2FS_PROG" = "" ] && _fatal "mkfs.f2fs not found"
diff --git a/common/dmerror b/common/dmerror
index 01a4c8b5..54122b12 100644
--- a/common/dmerror
+++ b/common/dmerror
@@ -4,25 +4,88 @@
#
# common functions for setting up and tearing down a dmerror device
-_dmerror_setup()
+_dmerror_setup_vars()
{
- local dm_backing_dev=$SCRATCH_DEV
+ local backing_dev="$1"
+ local tag="$2"
+ local target="$3"
- local blk_dev_size=`blockdev --getsz $dm_backing_dev`
+ test -z "$target" && target=error
+ local blk_dev_size=$(blockdev --getsz "$backing_dev")
- export DMERROR_DEV='/dev/mapper/error-test'
+ eval export "DMLINEAR_${tag}TABLE=\"0 $blk_dev_size linear $backing_dev 0\""
+ eval export "DMERROR_${tag}TABLE=\"0 $blk_dev_size $target $backing_dev 0\""
+}
- export DMLINEAR_TABLE="0 $blk_dev_size linear $dm_backing_dev 0"
+_dmerror_setup()
+{
+ local rt_target=
+ local log_target=
+
+ for arg in "$@"; do
+ case "${arg}" in
+ no_rt) rt_target=linear;;
+ no_log) log_target=linear;;
+ *) echo "${arg}: Unknown _dmerror_setup arg.";;
+ esac
+ done
+
+ # Scratch device
+ export DMERROR_DEV='/dev/mapper/error-test'
+ _dmerror_setup_vars $SCRATCH_DEV
+
+ # Realtime device. We reassign SCRATCH_RTDEV so that all the scratch
+ # helpers continue to work unmodified.
+ if [ -n "$SCRATCH_RTDEV" ]; then
+ if [ -z "$NON_ERROR_RTDEV" ]; then
+ # Set up the device switch
+ local dm_backing_dev=$SCRATCH_RTDEV
+ export NON_ERROR_RTDEV="$SCRATCH_RTDEV"
+ SCRATCH_RTDEV='/dev/mapper/error-rttest'
+ else
+ # Already set up; recreate tables
+ local dm_backing_dev="$NON_ERROR_RTDEV"
+ fi
+
+ _dmerror_setup_vars $dm_backing_dev RT $rt_target
+ fi
- export DMERROR_TABLE="0 $blk_dev_size error $dm_backing_dev 0"
+ # External log device. We reassign SCRATCH_LOGDEV so that all the
+ # scratch helpers continue to work unmodified.
+ if [ -n "$SCRATCH_LOGDEV" ]; then
+ if [ -z "$NON_ERROR_LOGDEV" ]; then
+ # Set up the device switch
+ local dm_backing_dev=$SCRATCH_LOGDEV
+ export NON_ERROR_LOGDEV="$SCRATCH_LOGDEV"
+ SCRATCH_LOGDEV='/dev/mapper/error-logtest'
+ else
+ # Already set up; recreate tables
+ local dm_backing_dev="$NON_ERROR_LOGDEV"
+ fi
+
+ _dmerror_setup_vars $dm_backing_dev LOG $log_target
+ fi
}
_dmerror_init()
{
- _dmerror_setup
+ _dmerror_setup "$@"
+
_dmsetup_remove error-test
_dmsetup_create error-test --table "$DMLINEAR_TABLE" || \
_fatal "failed to create dm linear device"
+
+ if [ -n "$NON_ERROR_RTDEV" ]; then
+ _dmsetup_remove error-rttest
+ _dmsetup_create error-rttest --table "$DMLINEAR_RTTABLE" || \
+ _fatal "failed to create dm linear rt device"
+ fi
+
+ if [ -n "$NON_ERROR_LOGDEV" ]; then
+ _dmsetup_remove error-logtest
+ _dmsetup_create error-logtest --table "$DMLINEAR_LOGTABLE" || \
+ _fatal "failed to create dm linear log device"
+ fi
}
_dmerror_mount()
@@ -39,11 +102,27 @@ _dmerror_unmount()
_dmerror_cleanup()
{
+ test -n "$NON_ERROR_LOGDEV" && $DMSETUP_PROG resume error-logtest &>/dev/null
+ test -n "$NON_ERROR_RTDEV" && $DMSETUP_PROG resume error-rttest &>/dev/null
$DMSETUP_PROG resume error-test > /dev/null 2>&1
+
$UMOUNT_PROG $SCRATCH_MNT > /dev/null 2>&1
+
+ test -n "$NON_ERROR_LOGDEV" && _dmsetup_remove error-logtest
+ test -n "$NON_ERROR_RTDEV" && _dmsetup_remove error-rttest
_dmsetup_remove error-test
unset DMERROR_DEV DMLINEAR_TABLE DMERROR_TABLE
+
+ if [ -n "$NON_ERROR_LOGDEV" ]; then
+ SCRATCH_LOGDEV="$NON_ERROR_LOGDEV"
+ unset NON_ERROR_LOGDEV DMLINEAR_LOGTABLE DMERROR_LOGTABLE
+ fi
+
+ if [ -n "$NON_ERROR_RTDEV" ]; then
+ SCRATCH_RTDEV="$NON_ERROR_RTDEV"
+ unset NON_ERROR_RTDEV DMLINEAR_RTTABLE DMERROR_RTTABLE
+ fi
}
_dmerror_load_error_table()
@@ -59,12 +138,51 @@ _dmerror_load_error_table()
suspend_opt="$*"
fi
+ # If the full environment is set up, configure ourselves for shutdown
+ type _prepare_for_eio_shutdown &>/dev/null && \
+ _prepare_for_eio_shutdown $DMERROR_DEV
+
+ # Suspend the scratch device before the log and realtime devices so
+ # that the kernel can freeze and flush the filesystem if the caller
+ # wanted a freeze.
$DMSETUP_PROG suspend $suspend_opt error-test
[ $? -ne 0 ] && _fail "dmsetup suspend failed"
+ if [ -n "$NON_ERROR_RTDEV" ]; then
+ $DMSETUP_PROG suspend $suspend_opt error-rttest
+ [ $? -ne 0 ] && _fail "failed to suspend error-rttest"
+ fi
+
+ if [ -n "$NON_ERROR_LOGDEV" ]; then
+ $DMSETUP_PROG suspend $suspend_opt error-logtest
+ [ $? -ne 0 ] && _fail "failed to suspend error-logtest"
+ fi
+
+ # Load new table
$DMSETUP_PROG load error-test --table "$DMERROR_TABLE"
load_res=$?
+ if [ -n "$NON_ERROR_RTDEV" ]; then
+ $DMSETUP_PROG load error-rttest --table "$DMERROR_RTTABLE"
+ [ $? -ne 0 ] && _fail "failed to load error table into error-rttest"
+ fi
+
+ if [ -n "$NON_ERROR_LOGDEV" ]; then
+ $DMSETUP_PROG load error-logtest --table "$DMERROR_LOGTABLE"
+ [ $? -ne 0 ] && _fail "failed to load error table into error-logtest"
+ fi
+
+ # Resume devices in the opposite order that we suspended them.
+ if [ -n "$NON_ERROR_LOGDEV" ]; then
+ $DMSETUP_PROG resume error-logtest
+ [ $? -ne 0 ] && _fail "failed to resume error-logtest"
+ fi
+
+ if [ -n "$NON_ERROR_RTDEV" ]; then
+ $DMSETUP_PROG resume error-rttest
+ [ $? -ne 0 ] && _fail "failed to resume error-rttest"
+ fi
+
$DMSETUP_PROG resume error-test
resume_res=$?
@@ -85,12 +203,47 @@ _dmerror_load_working_table()
suspend_opt="$*"
fi
+ # Suspend the scratch device before the log and realtime devices so
+ # that the kernel can freeze and flush the filesystem if the caller
+ # wanted a freeze.
$DMSETUP_PROG suspend $suspend_opt error-test
[ $? -ne 0 ] && _fail "dmsetup suspend failed"
+ if [ -n "$NON_ERROR_RTDEV" ]; then
+ $DMSETUP_PROG suspend $suspend_opt error-rttest
+ [ $? -ne 0 ] && _fail "failed to suspend error-rttest"
+ fi
+
+ if [ -n "$NON_ERROR_LOGDEV" ]; then
+ $DMSETUP_PROG suspend $suspend_opt error-logtest
+ [ $? -ne 0 ] && _fail "failed to suspend error-logtest"
+ fi
+
+ # Load new table
$DMSETUP_PROG load error-test --table "$DMLINEAR_TABLE"
load_res=$?
+ if [ -n "$NON_ERROR_RTDEV" ]; then
+ $DMSETUP_PROG load error-rttest --table "$DMLINEAR_RTTABLE"
+ [ $? -ne 0 ] && _fail "failed to load working table into error-rttest"
+ fi
+
+ if [ -n "$NON_ERROR_LOGDEV" ]; then
+ $DMSETUP_PROG load error-logtest --table "$DMLINEAR_LOGTABLE"
+ [ $? -ne 0 ] && _fail "failed to load working table into error-logtest"
+ fi
+
+ # Resume devices in the opposite order that we suspended them.
+ if [ -n "$NON_ERROR_LOGDEV" ]; then
+ $DMSETUP_PROG resume error-logtest
+ [ $? -ne 0 ] && _fail "failed to resume error-logtest"
+ fi
+
+ if [ -n "$NON_ERROR_RTDEV" ]; then
+ $DMSETUP_PROG resume error-rttest
+ [ $? -ne 0 ] && _fail "failed to resume error-rttest"
+ fi
+
$DMSETUP_PROG resume error-test
resume_res=$?
diff --git a/common/encrypt b/common/encrypt
index 8f3c46f6..f84f68b2 100644
--- a/common/encrypt
+++ b/common/encrypt
@@ -806,6 +806,7 @@ FSCRYPT_MODE_AES_256_CTS=4
FSCRYPT_MODE_AES_128_CBC=5
FSCRYPT_MODE_AES_128_CTS=6
FSCRYPT_MODE_ADIANTUM=9
+FSCRYPT_MODE_AES_256_HCTR2=10
FSCRYPT_POLICY_FLAG_DIRECT_KEY=0x04
FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64=0x08
@@ -824,6 +825,7 @@ _fscrypt_mode_name_to_num()
AES-128-CBC-ESSIV) echo $FSCRYPT_MODE_AES_128_CBC ;;
AES-128-CTS-CBC) echo $FSCRYPT_MODE_AES_128_CTS ;;
Adiantum) echo $FSCRYPT_MODE_ADIANTUM ;;
+ AES-256-HCTR2) echo $FSCRYPT_MODE_AES_256_HCTR2 ;;
*) _fail "Unknown fscrypt mode: $name" ;;
esac
}
diff --git a/common/ext4 b/common/ext4
new file mode 100644
index 00000000..f4c3c413
--- /dev/null
+++ b/common/ext4
@@ -0,0 +1,193 @@
+#
+# ext4 specific common functions
+#
+
+_setup_large_ext4_fs()
+{
+ local fs_size=$1
+ local tmp_dir=/tmp/
+
+ [ "$LARGE_SCRATCH_DEV" != yes ] && return 0
+ [ -z "$SCRATCH_DEV_EMPTY_SPACE" ] && SCRATCH_DEV_EMPTY_SPACE=0
+ [ $SCRATCH_DEV_EMPTY_SPACE -ge $fs_size ] && return 0
+
+ # Default free space in the FS is 50GB, but you can specify more via
+ # SCRATCH_DEV_EMPTY_SPACE
+ local space_to_consume=$(($fs_size - 50*1024*1024*1024 - $SCRATCH_DEV_EMPTY_SPACE))
+
+ # mount the filesystem and create 16TB - 4KB files until we consume
+ # all the necessary space.
+ _try_scratch_mount 2>&1 >$tmp_dir/mnt.err
+ local status=$?
+ if [ $status -ne 0 ]; then
+ echo "mount failed"
+ cat $tmp_dir/mnt.err >&2
+ rm -f $tmp_dir/mnt.err
+ return $status
+ fi
+ rm -f $tmp_dir/mnt.err
+
+ local file_size=$((16*1024*1024*1024*1024 - 4096))
+ local nfiles=0
+ while [ $space_to_consume -gt $file_size ]; do
+
+ xfs_io -F -f \
+ -c "truncate $file_size" \
+ -c "falloc -k 0 $file_size" \
+ $SCRATCH_MNT/.use_space.$nfiles 2>&1
+ status=$?
+ if [ $status -ne 0 ]; then
+ break;
+ fi
+
+ space_to_consume=$(( $space_to_consume - $file_size ))
+ nfiles=$(($nfiles + 1))
+ done
+
+ # consume the remaining space.
+ if [ $space_to_consume -gt 0 ]; then
+ xfs_io -F -f \
+ -c "truncate $space_to_consume" \
+ -c "falloc -k 0 $space_to_consume" \
+ $SCRATCH_MNT/.use_space.$nfiles 2>&1
+ status=$?
+ fi
+ export NUM_SPACE_FILES=$nfiles
+
+ _scratch_unmount
+ if [ $status -ne 0 ]; then
+ echo "large file prealloc failed"
+ cat $tmp_dir/mnt.err >&2
+ return $status
+ fi
+ return 0
+}
+
+_scratch_mkfs_ext4_opts()
+{
+ mkfs_opts=$*
+
+ _scratch_options mkfs
+
+ echo "$MKFS_EXT4_PROG $SCRATCH_OPTIONS $mkfs_opts"
+}
+
+_scratch_mkfs_ext4()
+{
+ local mkfs_cmd="`_scratch_mkfs_ext4_opts`"
+ local mkfs_filter="grep -v -e ^Warning: -e \"^mke2fs \" | grep -v \"^$\""
+ local tmp=`mktemp -u`
+ local mkfs_status
+
+ if [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ]; then
+ $MKFS_EXT4_PROG -F -O journal_dev $MKFS_OPTIONS $* $SCRATCH_LOGDEV 2>$tmp.mkfserr 1>$tmp.mkfsstd
+ mkjournal_status=$?
+
+ if [ $mkjournal_status -ne 0 ]; then
+ cat $tmp.mkfsstd
+ cat $tmp.mkfserr >&2
+ return $mkjournal_status
+ fi
+ fi
+
+ _scratch_do_mkfs "$mkfs_cmd" "$mkfs_filter" $* 2>$tmp.mkfserr 1>$tmp.mkfsstd
+ mkfs_status=$?
+
+ if [ $mkfs_status -eq 0 -a "$LARGE_SCRATCH_DEV" = yes ]; then
+ # manually parse the mkfs output to get the fs size in bytes
+ local fs_size=`cat $tmp.mkfsstd | awk ' \
+ /^Block size/ { split($2, a, "="); bs = a[2] ; } \
+ / inodes, / { blks = $3 } \
+ /reserved for the super user/ { resv = $1 } \
+ END { fssize = bs * blks - resv; print fssize }'`
+
+ _setup_large_ext4_fs $fs_size
+ mkfs_status=$?
+ fi
+
+ # output mkfs stdout and stderr
+ cat $tmp.mkfsstd
+ cat $tmp.mkfserr >&2
+ rm -f $tmp.mkfserr $tmp.mkfsstd
+
+ return $mkfs_status
+}
+
+_ext4_metadump()
+{
+ local device="$1"
+ local dumpfile="$2"
+ local compressopt="$3"
+
+ test -n "$E2IMAGE_PROG" || _fail "e2image not installed"
+ $E2IMAGE_PROG -Q "$device" "$dumpfile"
+ [ "$compressopt" = "compress" ] && [ -n "$DUMP_COMPRESSOR" ] &&
+ $DUMP_COMPRESSOR -f "$dumpfile" &>> "$seqres.full"
+}
+
+# this test requires the ext4 kernel support crc feature on scratch device
+#
+_require_scratch_ext4_crc()
+{
+ _scratch_mkfs_ext4 >/dev/null 2>&1
+ dumpe2fs -h $SCRATCH_DEV 2> /dev/null | grep -q metadata_csum || _notrun "metadata_csum not supported by this filesystem"
+ _try_scratch_mount >/dev/null 2>&1 \
+ || _notrun "Kernel doesn't support metadata_csum feature"
+ _scratch_unmount
+}
+
+# Check whether the specified feature whether it is supported by
+# mkfs.ext4 and the kernel.
+_require_scratch_ext4_feature()
+{
+ if [ -z "$1" ]; then
+ echo "Usage: _require_scratch_ext4_feature feature"
+ exit 1
+ fi
+ $MKFS_EXT4_PROG -F $MKFS_OPTIONS -O "$1" \
+ $SCRATCH_DEV 512m >/dev/null 2>&1 \
+ || _notrun "mkfs.ext4 doesn't support $1 feature"
+ _try_scratch_mount >/dev/null 2>&1 \
+ || _notrun "Kernel doesn't support the ext4 feature(s): $1"
+ _scratch_unmount
+}
+
+# Disable extent zeroing for ext4 on the given device
+_ext4_disable_extent_zeroout()
+{
+ local dev=${1:-$TEST_DEV}
+ local sdev=`_short_dev $dev`
+
+ [ -f /sys/fs/ext4/$sdev/extent_max_zeroout_kb ] && \
+ echo 0 >/sys/fs/ext4/$sdev/extent_max_zeroout_kb
+}
+
+_require_scratch_richacl_ext4()
+{
+ _scratch_mkfs -O richacl >/dev/null 2>&1 \
+ || _notrun "can't mkfs $FSTYP with option -O richacl"
+ _try_scratch_mount >/dev/null 2>&1 \
+ || _notrun "kernel doesn't support richacl feature on $FSTYP"
+ _scratch_unmount
+}
+
+_scratch_ext4_options()
+{
+ local type=$1
+ local log_opt=""
+
+ case $type in
+ mkfs)
+ SCRATCH_OPTIONS="$SCRATCH_OPTIONS -F"
+ log_opt="-J device=$SCRATCH_LOGDEV"
+ ;;
+ mount)
+ # As of kernel 5.19, the kernel mount option path parser only
+ # accepts direct paths to block devices--the final path
+ # component cannot be a symlink.
+ log_opt="-o journal_path=$(realpath -q "$SCRATCH_LOGDEV")"
+ ;;
+ esac
+ [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
+ SCRATCH_OPTIONS="$SCRATCH_OPTIONS ${log_opt}"
+}
diff --git a/common/fail_make_request b/common/fail_make_request
new file mode 100644
index 00000000..b5370ba6
--- /dev/null
+++ b/common/fail_make_request
@@ -0,0 +1,64 @@
+##/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# common functions for setting up and tearing down block device error injection
+
+_require_fail_make_request()
+{
+ [ -f "$DEBUGFS_MNT/fail_make_request/probability" ] \
+ || _notrun "$DEBUGFS_MNT/fail_make_request \
+ not found. Seems that CONFIG_FAULT_INJECTION_DEBUG_FS kernel config option not enabled"
+}
+
+_allow_fail_make_request()
+{
+ local prob="${1:-100}"
+ local times="${2:-9999999}"
+ local verbose="${3:-0}"
+
+ echo "Allow global fail_make_request feature"
+ echo "$prob" > $DEBUGFS_MNT/fail_make_request/probability
+ echo "$times" > $DEBUGFS_MNT/fail_make_request/times
+ echo "$verbose" > $DEBUGFS_MNT/fail_make_request/verbose
+}
+
+_disallow_fail_make_request()
+{
+ echo "Disallow global fail_make_request feature"
+ echo 0 > $DEBUGFS_MNT/fail_make_request/probability
+ echo 0 > $DEBUGFS_MNT/fail_make_request/times
+ echo 0 > $DEBUGFS_MNT/fail_make_request/verbose
+}
+
+_bdev_fail_make_request()
+{
+ local bdev="$1"
+ local status="$2"
+ local sysfs_bdev=$(_sysfs_dev $bdev)
+
+ echo " echo $status > $sysfs_bdev/make-it-fail" >> $seqres.full
+ echo "$status" > $sysfs_bdev/make-it-fail
+}
+
+_start_fail_scratch_dev()
+{
+ echo "Force SCRATCH_DEV device failure"
+
+ _prepare_for_eio_shutdown $SCRATCH_DEV
+ _bdev_fail_make_request $SCRATCH_DEV 1
+ [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
+ _bdev_fail_make_request $SCRATCH_LOGDEV 1
+ [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_RTDEV" ] && \
+ _bdev_fail_make_request $SCRATCH_RTDEV 1
+}
+
+_stop_fail_scratch_dev()
+{
+ echo "Make SCRATCH_DEV device operable again"
+
+ [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_RTDEV" ] && \
+ _bdev_fail_make_request $SCRATCH_RTDEV 0
+ [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
+ _bdev_fail_make_request $SCRATCH_LOGDEV 0
+ _bdev_fail_make_request $SCRATCH_DEV 0
+}
diff --git a/common/filter b/common/filter
index 14f6a027..28dea646 100644
--- a/common/filter
+++ b/common/filter
@@ -221,7 +221,7 @@ _filter_xfs_io_units_modified()
_filter_xfs_io_blocks_modified()
{
- BLOCK_SIZE=$(_get_block_size $SCRATCH_MNT)
+ BLOCK_SIZE=$(_get_file_block_size $SCRATCH_MNT)
_filter_xfs_io_units_modified "Block" $BLOCK_SIZE
}
@@ -457,7 +457,7 @@ _filter_busy_mount()
_filter_od()
{
- BLOCK_SIZE=$(_get_block_size $SCRATCH_MNT)
+ BLOCK_SIZE=$(_get_file_block_size $SCRATCH_MNT)
$AWK_PROG -v block_size=$BLOCK_SIZE '
/^[0-9]+/ {
offset = strtonum("0"$1);
diff --git a/common/punch b/common/punch
index b6b8a0b9..47a29c92 100644
--- a/common/punch
+++ b/common/punch
@@ -250,6 +250,7 @@ _test_generic_punch()
_8k="$((multiple * 8))k"
_12k="$((multiple * 12))k"
_20k="$((multiple * 20))k"
+ _require_congruent_file_oplen "$(dirname "$testfile")" $((multiple * 4096))
# initial test state must be defined, otherwise the first test can fail
# due ot stale file state left from previous tests.
@@ -480,7 +481,7 @@ _test_generic_punch()
if [ "$remove_testfile" ]; then
rm -f $testfile
fi
- block_size=`_get_block_size $TEST_DIR`
+ block_size=`_get_file_block_size $TEST_DIR`
$XFS_IO_PROG -f -c "truncate $block_size" \
-c "pwrite 0 $block_size" $sync_cmd \
-c "$zero_cmd 128 128" \
diff --git a/common/rc b/common/rc
index d5e6764c..a25cbcd0 100644
--- a/common/rc
+++ b/common/rc
@@ -172,30 +172,16 @@ _clear_mount_stack()
_scratch_options()
{
- local type=$1
- local rt_opt=""
- local log_opt=""
SCRATCH_OPTIONS=""
- if [ "$FSTYP" != "xfs" ]; then
- return
- fi
-
- case $type in
- mkfs)
- SCRATCH_OPTIONS="$SCRATCH_OPTIONS -f"
- rt_opt="-r"
- log_opt="-l"
+ case "$FSTYP" in
+ "xfs")
+ _scratch_xfs_options "$@"
;;
- mount)
- rt_opt="-o"
- log_opt="-o"
+ ext2|ext3|ext4|ext4dev)
+ _scratch_ext4_options "$@"
;;
esac
- [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_RTDEV" ] && \
- SCRATCH_OPTIONS="$SCRATCH_OPTIONS ${rt_opt}rtdev=$SCRATCH_RTDEV"
- [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
- SCRATCH_OPTIONS="$SCRATCH_OPTIONS ${log_opt}logdev=$SCRATCH_LOGDEV"
}
_test_options()
@@ -559,113 +545,6 @@ _scratch_do_mkfs()
return $mkfs_status
}
-_setup_large_ext4_fs()
-{
- local fs_size=$1
- local tmp_dir=/tmp/
-
- [ "$LARGE_SCRATCH_DEV" != yes ] && return 0
- [ -z "$SCRATCH_DEV_EMPTY_SPACE" ] && SCRATCH_DEV_EMPTY_SPACE=0
- [ $SCRATCH_DEV_EMPTY_SPACE -ge $fs_size ] && return 0
-
- # Default free space in the FS is 50GB, but you can specify more via
- # SCRATCH_DEV_EMPTY_SPACE
- local space_to_consume=$(($fs_size - 50*1024*1024*1024 - $SCRATCH_DEV_EMPTY_SPACE))
-
- # mount the filesystem and create 16TB - 4KB files until we consume
- # all the necessary space.
- _try_scratch_mount 2>&1 >$tmp_dir/mnt.err
- local status=$?
- if [ $status -ne 0 ]; then
- echo "mount failed"
- cat $tmp_dir/mnt.err >&2
- rm -f $tmp_dir/mnt.err
- return $status
- fi
- rm -f $tmp_dir/mnt.err
-
- local file_size=$((16*1024*1024*1024*1024 - 4096))
- local nfiles=0
- while [ $space_to_consume -gt $file_size ]; do
-
- xfs_io -F -f \
- -c "truncate $file_size" \
- -c "falloc -k 0 $file_size" \
- $SCRATCH_MNT/.use_space.$nfiles 2>&1
- status=$?
- if [ $status -ne 0 ]; then
- break;
- fi
-
- space_to_consume=$(( $space_to_consume - $file_size ))
- nfiles=$(($nfiles + 1))
- done
-
- # consume the remaining space.
- if [ $space_to_consume -gt 0 ]; then
- xfs_io -F -f \
- -c "truncate $space_to_consume" \
- -c "falloc -k 0 $space_to_consume" \
- $SCRATCH_MNT/.use_space.$nfiles 2>&1
- status=$?
- fi
- export NUM_SPACE_FILES=$nfiles
-
- _scratch_unmount
- if [ $status -ne 0 ]; then
- echo "large file prealloc failed"
- cat $tmp_dir/mnt.err >&2
- return $status
- fi
- return 0
-}
-
-_scratch_mkfs_ext4()
-{
- local mkfs_cmd="$MKFS_EXT4_PROG -F"
- local mkfs_filter="grep -v -e ^Warning: -e \"^mke2fs \" | grep -v \"^$\""
- local tmp=`mktemp -u`
- local mkfs_status
-
- [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
- $mkfs_cmd -O journal_dev $MKFS_OPTIONS $SCRATCH_LOGDEV && \
- mkfs_cmd="$mkfs_cmd -J device=$SCRATCH_LOGDEV"
-
- _scratch_do_mkfs "$mkfs_cmd" "$mkfs_filter" $* 2>$tmp.mkfserr 1>$tmp.mkfsstd
- mkfs_status=$?
-
- if [ $mkfs_status -eq 0 -a "$LARGE_SCRATCH_DEV" = yes ]; then
- # manually parse the mkfs output to get the fs size in bytes
- local fs_size=`cat $tmp.mkfsstd | awk ' \
- /^Block size/ { split($2, a, "="); bs = a[2] ; } \
- / inodes, / { blks = $3 } \
- /reserved for the super user/ { resv = $1 } \
- END { fssize = bs * blks - resv; print fssize }'`
-
- _setup_large_ext4_fs $fs_size
- mkfs_status=$?
- fi
-
- # output mkfs stdout and stderr
- cat $tmp.mkfsstd
- cat $tmp.mkfserr >&2
- rm -f $tmp.mkfserr $tmp.mkfsstd
-
- return $mkfs_status
-}
-
-_ext4_metadump()
-{
- local device="$1"
- local dumpfile="$2"
- local compressopt="$3"
-
- test -n "$E2IMAGE_PROG" || _fail "e2image not installed"
- $E2IMAGE_PROG -Q "$device" "$dumpfile"
- [ "$compressopt" = "compress" ] && [ -n "$DUMP_COMPRESSOR" ] &&
- $DUMP_COMPRESSOR -f "$dumpfile" &>> "$seqres.full"
-}
-
# Capture the metadata of a filesystem in a dump file for offline analysis.
# This is not supported by all filesystem types, so this function should only
# be used after a test has already failed.
@@ -1088,6 +967,13 @@ _scratch_mkfs_sized()
fi
;;
ext2|ext3|ext4|ext4dev)
+ # Can't use _scratch_mkfs_ext4 here because the block count has
+ # to come after the device path.
+ if [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ]; then
+ ${MKFS_PROG} -F -O journal_dev $MKFS_OPTIONS $SCRATCH_LOGDEV || \
+ _notrun "Could not make scratch logdev"
+ MKFS_OPTIONS="$MKFS_OPTIONS -J device=$SCRATCH_LOGDEV"
+ fi
${MKFS_PROG} -t $FSTYP -F $MKFS_OPTIONS -b $blocksize $SCRATCH_DEV $blocks
;;
gfs2)
@@ -1217,7 +1103,7 @@ _scratch_mkfs_blocksized()
_scratch_mkfs_xfs $MKFS_OPTIONS -b size=$blocksize
;;
ext2|ext3|ext4)
- ${MKFS_PROG} -t $FSTYP -F $MKFS_OPTIONS -b $blocksize $SCRATCH_DEV
+ _scratch_mkfs_ext4 $MKFS_OPTIONS -b $blocksize
;;
gfs2)
${MKFS_PROG} -t $FSTYP $MKFS_OPTIONS -O -b $blocksize $SCRATCH_DEV
@@ -2002,6 +1888,14 @@ _require_logdev()
$UMOUNT_PROG $SCRATCH_LOGDEV 2>/dev/null
}
+# This test requires that an external log device is not in use
+#
+_require_no_logdev()
+{
+ [ "$USE_EXTERNAL" = "yes" ] && [ -n "$SCRATCH_LOGDEV" ] && \
+ _notrun "Test not compatible with external logs, skipped this test"
+}
+
# this test requires loopback device support
#
_require_loop()
@@ -2237,33 +2131,6 @@ _require_non_zoned_device()
fi
}
-# this test requires the ext4 kernel support crc feature on scratch device
-#
-_require_scratch_ext4_crc()
-{
- _scratch_mkfs_ext4 >/dev/null 2>&1
- dumpe2fs -h $SCRATCH_DEV 2> /dev/null | grep -q metadata_csum || _notrun "metadata_csum not supported by this filesystem"
- _try_scratch_mount >/dev/null 2>&1 \
- || _notrun "Kernel doesn't support metadata_csum feature"
- _scratch_unmount
-}
-
-# Check whether the specified feature whether it is supported by
-# mkfs.ext4 and the kernel.
-_require_scratch_ext4_feature()
-{
- if [ -z "$1" ]; then
- echo "Usage: _require_scratch_ext4_feature feature"
- exit 1
- fi
- $MKFS_EXT4_PROG -F $MKFS_OPTIONS -O "$1" \
- $SCRATCH_DEV 512m >/dev/null 2>&1 \
- || _notrun "mkfs.ext4 doesn't support $1 feature"
- _try_scratch_mount >/dev/null 2>&1 \
- || _notrun "Kernel doesn't support the ext4 feature(s): $1"
- _scratch_unmount
-}
-
# this test requires that external log/realtime devices are not in use
#
_require_nonexternal()
@@ -2626,7 +2493,7 @@ _require_xfs_io_command()
param_checked="$param"
;;
"fpunch" | "fcollapse" | "zero" | "fzero" | "finsert" | "funshare")
- local blocksize=$(_get_block_size $TEST_DIR)
+ local blocksize=$(_get_file_block_size $TEST_DIR)
testio=`$XFS_IO_PROG -F -f -c "pwrite 0 $((5 * $blocksize))" \
-c "fsync" -c "$command $blocksize $((2 * $blocksize))" \
$testfile 2>&1`
@@ -2879,23 +2746,6 @@ _require_debugfs()
[ -d "$DEBUGFS_MNT/boot_params" ] || _notrun "Debugfs not mounted"
}
-_require_fail_make_request()
-{
- [ -f "$DEBUGFS_MNT/fail_make_request/probability" ] \
- || _notrun "$DEBUGFS_MNT/fail_make_request \
- not found. Seems that CONFIG_FAULT_INJECTION_DEBUG_FS kernel config option not enabled"
-}
-
-# Disable extent zeroing for ext4 on the given device
-_ext4_disable_extent_zeroout()
-{
- local dev=${1:-$TEST_DEV}
- local sdev=`_short_dev $dev`
-
- [ -f /sys/fs/ext4/$sdev/extent_max_zeroout_kb ] && \
- echo 0 >/sys/fs/ext4/$sdev/extent_max_zeroout_kb
-}
-
# The default behavior of SEEK_HOLE is to always return EOF.
# Filesystems that implement non-default behavior return the offset
# of holes with SEEK_HOLE. There is no way to query the filesystem
@@ -2993,15 +2843,6 @@ _require_scratch_richacl_xfs()
_scratch_unmount
}
-_require_scratch_richacl_ext4()
-{
- _scratch_mkfs -O richacl >/dev/null 2>&1 \
- || _notrun "can't mkfs $FSTYP with option -O richacl"
- _try_scratch_mount >/dev/null 2>&1 \
- || _notrun "kernel doesn't support richacl feature on $FSTYP"
- _scratch_unmount
-}
-
_require_scratch_richacl_support()
{
_scratch_mount
@@ -4330,8 +4171,25 @@ _check_dmesg_for()
# lockdep.
_check_dmesg_filter()
{
+ local extra_filter=
+ local filter_file="${RESULT_DIR}/dmesg_filter"
+
+ test -e "$filter_file" && extra_filter="-f $filter_file"
+
egrep -v -e "BUG: MAX_LOCKDEP_CHAIN_HLOCKS too low" \
- -e "BUG: MAX_STACK_TRACE_ENTRIES too low"
+ -e "BUG: MAX_STACK_TRACE_ENTRIES too low" \
+ $extra_filter
+}
+
+# Add a simple expression to the default dmesg filter
+_add_dmesg_filter()
+{
+ local regexp="$1"
+ local filter_file="${RESULT_DIR}/dmesg_filter"
+
+ if [ ! -e "$filter_file" ] || ! grep -q "$regexp" "$filter_file"; then
+ echo "$regexp" >> "${RESULT_DIR}/dmesg_filter"
+ fi
}
# check dmesg log for WARNING/Oops/etc.
@@ -4371,6 +4229,20 @@ _check_dmesg()
fi
}
+# Make whatever configuration changes we need ahead of testing fs shutdowns due
+# to unexpected IO errors while updating metadata. The sole parameter should
+# be the fs device, e.g. $SCRATCH_DEV.
+_prepare_for_eio_shutdown()
+{
+ local dev="$1"
+
+ case "$FSTYP" in
+ "xfs")
+ _xfs_prepare_for_eio_shutdown "$dev"
+ ;;
+ esac
+}
+
# capture the kmemleak report
_capture_kmemleak()
{
@@ -4557,6 +4429,32 @@ _get_file_block_size()
esac
}
+# Given a file path and a byte length of a file operation under test, ensure
+# that the length is an integer multiple of the file's allocation unit size.
+# In other words, skip the test unless (oplen ≡ alloc_unit mod 0). This is
+# intended for file remapping operations.
+_require_congruent_file_oplen()
+{
+ local file="$1"
+ local alloc_unit=$(_get_file_block_size "$file")
+ local oplen="$2"
+
+ case $FSTYP in
+ nfs*|cifs|9p|virtiofs|ceph|glusterfs|overlay|pvfs2)
+ # Network filesystems don't know about (or tell the client
+ # about) the underlying file allocation unit and they generally
+ # pass the file IO request to the underlying filesystem, so we
+ # don't have anything to check here.
+ return
+ ;;
+ esac
+
+ test $alloc_unit -gt $oplen && \
+ _notrun "$1: file alloc unit $alloc_unit larger than op length $oplen"
+ test $((oplen % alloc_unit)) -eq 0 || \
+ _notrun "$1: file alloc unit $alloc_unit not congruent with op length $oplen"
+}
+
# Get the minimum block size of an fs.
_get_block_size()
{
@@ -4607,7 +4505,7 @@ run_fsx()
#
# Usage example:
# _require_fs_sysfs error/fail_at_unmount
-_require_fs_sysfs()
+_has_fs_sysfs()
{
local attr=$1
local dname
@@ -4623,9 +4521,18 @@ _require_fs_sysfs()
_fail "Usage: _require_fs_sysfs <sysfs_attr_path>"
fi
- if [ ! -e /sys/fs/${FSTYP}/${dname}/${attr} ];then
- _notrun "This test requires /sys/fs/${FSTYP}/${dname}/${attr}"
- fi
+ test -e /sys/fs/${FSTYP}/${dname}/${attr}
+}
+
+# Require the existence of a sysfs entry at /sys/fs/$FSTYP/DEV/$ATTR
+_require_fs_sysfs()
+{
+ _has_fs_sysfs "$@" && return
+
+ local attr=$1
+ local dname=$(_short_dev $TEST_DEV)
+
+ _notrun "This test requires /sys/fs/${FSTYP}/${dname}/${attr}"
}
_require_statx()
@@ -4789,6 +4696,11 @@ _dmsetup_remove()
_dmsetup_create()
{
+ # Wait for udev to settle so that the dm creation doesn't fail because
+ # some udev subprogram opened one of the block devices mentioned in the
+ # table string w/ O_EXCL. Do it again at the end so that an immediate
+ # device open won't also fail.
+ $UDEV_SETTLE_PROG >/dev/null 2>&1
$DMSETUP_PROG create "$@" >>$seqres.full 2>&1 || return 1
$DMSETUP_PROG mknodes >/dev/null 2>&1
$UDEV_SETTLE_PROG >/dev/null 2>&1
diff --git a/common/report b/common/report
index 84d9e0a7..64f9c866 100644
--- a/common/report
+++ b/common/report
@@ -4,26 +4,10 @@
# List of xfstests's enviroment variables to include reports
## TODO automate list population inside common/conf
-REPORT_ENV_LIST="$REPORT_ENV_LIST SECTION"
-REPORT_ENV_LIST="$REPORT_ENV_LIST FSTYP"
-REPORT_ENV_LIST="$REPORT_ENV_LIST PLATFORM"
-REPORT_ENV_LIST="$REPORT_ENV_LIST MKFS_OPTIONS"
-REPORT_ENV_LIST="$REPORT_ENV_LIST MOUNT_OPTIONS"
-
-REPORT_ENV_LIST="$REPORT_ENV_LIST HOST_OPTIONS"
-REPORT_ENV_LIST="$REPORT_ENV_LIST CHECK_OPTIONS"
-REPORT_ENV_LIST="$REPORT_ENV_LIST XFS_MKFS_OPTIONS"
-REPORT_ENV_LIST="$REPORT_ENV_LIST TIME_FACTOR"
-REPORT_ENV_LIST="$REPORT_ENV_LIST LOAD_FACTOR"
-
-REPORT_ENV_LIST="$REPORT_ENV_LIST TEST_DIR"
-REPORT_ENV_LIST="$REPORT_ENV_LIST TEST_DEV"
-REPORT_ENV_LIST="$REPORT_ENV_LIST SCRATCH_DEV"
-REPORT_ENV_LIST="$REPORT_ENV_LIST SCRATCH_MNT"
-
-REPORT_ENV_LIST="$REPORT_ENV_LIST OVL_UPPER"
-REPORT_ENV_LIST="$REPORT_ENV_LIST OVL_LOWER"
-REPORT_ENV_LIST="$REPORT_ENV_LIST OVL_WORK"
+REPORT_ENV_LIST=("SECTION" "FSTYP" "PLATFORM" "MKFS_OPTIONS" "MOUNT_OPTIONS" \
+ "HOST_OPTIONS" "CHECK_OPTIONS" "XFS_MKFS_OPTIONS" \
+ "TIME_FACTOR" "LOAD_FACTOR" "TEST_DIR" "TEST_DEV" \
+ "SCRATCH_DEV" "SCRATCH_MNT" "OVL_UPPER" "OVL_LOWER" "OVL_WORK")
encode_xml()
{
@@ -49,11 +33,11 @@ _xunit_add_property()
_xunit_make_section_report()
{
# xfstest:section ==> xunit:testsuite
- local tests_count="$1"
- local bad_count="$2"
- local notrun_count="$3"
- local sect_name=$section
- local sect_time=`expr $sect_stop - $sect_start`
+ local sect_name="$1"
+ local tests_count="$2"
+ local bad_count="$3"
+ local notrun_count="$4"
+ local sect_time="$5"
if [ $sect_name == '-no-sections-' ]; then
sect_name='global'
@@ -70,7 +54,7 @@ _xunit_make_section_report()
# Properties
echo -e "\t<properties>" >> $REPORT_DIR/result.xml
- for p in $REPORT_ENV_LIST;do
+ for p in "${REPORT_ENV_LIST[@]}"; do
_xunit_add_property "$p"
done
echo -e "\t</properties>" >> $REPORT_DIR/result.xml
@@ -83,17 +67,20 @@ _xunit_make_section_report()
_xunit_make_testcase_report()
{
- local test_seq="$1"
- local test_status="$2"
- local test_time=`expr $stop - $start`
- local strip="$SRC_DIR/"
- local test_name=${test_seq#$strip}
- local sect_name=$section
+ local sect_name="$1"
+ local test_name="$2"
+ local test_status="$3"
+ local test_time="$4"
+ local report_format="$5"
+ local quiet
+
+ if [ "$report_format" = xunit-quiet ]; then
+ quiet=yes
+ fi
# TODO: other places may also win if no-section mode will be named like 'default/global'
if [ $sect_name == '-no-sections-' ]; then
sect_name='global'
-
fi
local report=$tmp.report.xunit.$sect_name.xml
@@ -102,8 +89,9 @@ _xunit_make_testcase_report()
"pass")
;;
"notrun")
- if [ -f $seqres.notrun ]; then
- local msg=`cat $seqres.notrun | encode_xml`
+ local notrun_file="${REPORT_DIR}/${test_name}.notrun"
+ if [ -f "$notrun_file" ]; then
+ local msg=`cat "$notrun_file" | encode_xml`
echo -e "\t\t<skipped message=\"$msg\" />" >> $report
else
echo -e "\t\t<skipped/>" >> $report
@@ -113,27 +101,33 @@ _xunit_make_testcase_report()
echo -e "\t\t<skipped/>" >> $report
;;
"fail")
+ local out_src="${SRC_DIR}/${test_name}.out"
+ local full_file="${REPORT_DIR}/${test_name}.full"
+ local dmesg_file="${REPORT_DIR}/${test_name}.dmesg"
+ local outbad_file="${REPORT_DIR}/${test_name}.out.bad"
if [ -z "$_err_msg" ]; then
- _err_msg="Test $sequm failed, reason unknown"
+ _err_msg="Test $test_name failed, reason unknown"
fi
echo -e "\t\t<failure message=\"$_err_msg\" type=\"TestFail\" />" >> $report
- if [ -s $seqres.full ]; then
+ if [ -z "$quiet" -a -s "$full_file" ]; then
echo -e "\t\t<system-out>" >> $report
printf '<![CDATA[\n' >>$report
- cat $seqres.full | tr -dc '[:print:][:space:]' | encode_xml >>$report
+ cat "$full_file" | tr -dc '[:print:][:space:]' | encode_xml >>$report
printf ']]>\n' >>$report
echo -e "\t\t</system-out>" >> $report
fi
- if [ -f $seqres.dmesg ]; then
+ if [ -n "$quiet" ]; then
+ :
+ elif [ -f "$dmesg_file" ]; then
echo -e "\t\t<system-err>" >> $report
printf '<![CDATA[\n' >>$report
- cat $seqres.dmesg | tr -dc '[:print:][:space:]' | encode_xml >>$report
+ cat "$dmesg_file" | tr -dc '[:print:][:space:]' | encode_xml >>$report
printf ']]>\n' >>$report
echo -e "\t\t</system-err>" >> $report
- elif [ -s $seqres.out.bad ]; then
+ elif [ -s "$outbad_file" ]; then
echo -e "\t\t<system-err>" >> $report
printf '<![CDATA[\n' >>$report
- $diff $test_seq.out $seqres.out.bad | encode_xml >>$report
+ $diff "$out_src" "$outbad_file" | encode_xml >>$report
printf ']]>\n' >>$report
echo -e "\t\t</system-err>" >> $report
fi
@@ -150,13 +144,17 @@ _xunit_make_testcase_report()
# Common report generator entry points
_make_section_report()
{
- local tests_count="$1"
- local bad_count="$2"
- local notrun_count="$3"
+ local sect_name="$1"
+ local tests_count="$2"
+ local bad_count="$3"
+ local notrun_count="$4"
+ local sect_time="$5"
for report in $REPORT_LIST; do
case "$report" in
- "xunit")
- _xunit_make_section_report "$tests_count" "$bad_count" "$notrun_count"
+ "xunit"|"xunit-quiet")
+ _xunit_make_section_report "$sect_name" "$tests_count" \
+ "$bad_count" "$notrun_count" \
+ "$sect_time"
;;
*)
_dump_err "format '$report' is not supported"
@@ -167,12 +165,15 @@ _make_section_report()
_make_testcase_report()
{
- local test_seq="$1"
- local test_status="$2"
+ local sect_name="$1"
+ local test_seq="$2"
+ local test_status="$3"
+ local test_time="$4"
for report in $REPORT_LIST; do
case "$report" in
- "xunit")
- _xunit_make_testcase_report "$test_seq" "$test_status"
+ "xunit"|"xunit-quiet")
+ _xunit_make_testcase_report "$sect_name" "$test_seq" \
+ "$test_status" "$test_time" "$report"
;;
*)
_dump_err "report format '$report' is not supported"
@@ -184,7 +185,7 @@ _make_testcase_report()
_assert_report_list() {
for report in $REPORT_LIST; do
case "$report" in
- "xunit")
+ "xunit"|"xunit-quiet")
;;
*)
_fatal "report format '$report' is not supported"
diff --git a/common/verity b/common/verity
index 38eea157..65a39d3e 100644
--- a/common/verity
+++ b/common/verity
@@ -3,6 +3,16 @@
#
# Functions for setting up and testing fs-verity
+# btrfs will return IO errors on corrupted data with or without fs-verity.
+# to really test fs-verity, use nodatasum.
+if [ "$FSTYP" == "btrfs" ]; then
+ if [ -z "$MOUNT_OPTIONS" ]; then
+ export MOUNT_OPTIONS="-o nodatasum"
+ else
+ export MOUNT_OPTIONS+=" -o nodatasum"
+ fi
+fi
+
_require_scratch_verity()
{
_require_scratch
@@ -141,12 +151,24 @@ _require_fsverity_dump_metadata()
_fail "Unexpected output from 'fsverity dump_metadata': $(<"$tmpfile")"
}
+# Check for userspace tools needed to corrupt verity data or metadata.
+_require_fsverity_corruption()
+{
+ _require_xfs_io_command "fiemap"
+ if [ $FSTYP == "btrfs" ]; then
+ _require_btrfs_corrupt_block
+ fi
+}
+
_scratch_mkfs_verity()
{
case $FSTYP in
ext4|f2fs)
_scratch_mkfs -O verity
;;
+ btrfs)
+ _scratch_mkfs
+ ;;
*)
_notrun "No verity support for $FSTYP"
;;
@@ -308,8 +330,34 @@ _fsv_scratch_corrupt_merkle_tree()
(( offset += ($(_get_filesize $file) + 65535) & ~65535 ))
_fsv_scratch_corrupt_bytes $file $offset
;;
+ btrfs)
+ local ino=$(stat -c '%i' $file)
+ _scratch_unmount
+ local byte=""
+ while read -n 1 byte; do
+ local ascii=$(printf "%d" "'$byte'")
+ # This command will find a Merkle tree item for the inode (-I $ino,37,0)
+ # in the default filesystem tree (-r 5) and corrupt one byte (-b 1) at
+ # $offset (-o $offset) with the ascii representation of the byte we read
+ # (-v $ascii)
+ $BTRFS_CORRUPT_BLOCK_PROG -r 5 -I $ino,37,0 -v $ascii -o $offset -b 1 $SCRATCH_DEV
+ (( offset += 1 ))
+ done
+ _scratch_mount
+ ;;
*)
_fail "_fsv_scratch_corrupt_merkle_tree() unimplemented on $FSTYP"
;;
esac
}
+
+_require_fsverity_max_file_size_limit()
+{
+ case $FSTYP in
+ btrfs|ext4|f2fs)
+ ;;
+ *)
+ _notrun "$FSTYP does not store verity data past EOF; no special file size limit"
+ ;;
+ esac
+}
diff --git a/common/xfs b/common/xfs
index 9f84dffb..ae81b3fe 100644
--- a/common/xfs
+++ b/common/xfs
@@ -265,6 +265,29 @@ _xfs_check()
return $status
}
+_scratch_xfs_options()
+{
+ local type=$1
+ local rt_opt=""
+ local log_opt=""
+
+ case $type in
+ mkfs)
+ SCRATCH_OPTIONS="$SCRATCH_OPTIONS -f"
+ rt_opt="-r"
+ log_opt="-l"
+ ;;
+ mount)
+ rt_opt="-o"
+ log_opt="-o"
+ ;;
+ esac
+ [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_RTDEV" ] && \
+ SCRATCH_OPTIONS="$SCRATCH_OPTIONS ${rt_opt}rtdev=$SCRATCH_RTDEV"
+ [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
+ SCRATCH_OPTIONS="$SCRATCH_OPTIONS ${log_opt}logdev=$SCRATCH_LOGDEV"
+}
+
_scratch_xfs_db_options()
{
SCRATCH_OPTIONS=""
@@ -781,7 +804,7 @@ _reset_xfs_sysfs_error_handling()
_get_fs_sysfs_attr $dev error/metadata/${e}/max_retries
_set_fs_sysfs_attr $dev \
- error/metadata/${e}/retry_timeout_seconds 0
+ error/metadata/${e}/retry_timeout_seconds -1
echo -n "error/metadata/${e}/retry_timeout_seconds="
_get_fs_sysfs_attr $dev \
error/metadata/${e}/retry_timeout_seconds
@@ -800,6 +823,42 @@ _scratch_xfs_unmount_dirty()
_scratch_unmount
}
+# Prepare a mounted filesystem for an IO error shutdown test by disabling retry
+# for metadata writes. This prevents a (rare) log livelock when:
+#
+# - The log has given out all available grant space, preventing any new
+# writers from tripping over IO errors (and shutting down the fs/log),
+# - All log buffers were written to disk, and
+# - The log tail is pinned because the AIL keeps hitting EIO trying to write
+# committed changes back into the filesystem.
+#
+# Real users might want the default behavior of the AIL retrying writes forever
+# but for testing purposes we don't want to wait.
+#
+# The sole parameter should be the filesystem data device, e.g. $SCRATCH_DEV.
+_xfs_prepare_for_eio_shutdown()
+{
+ local dev="$1"
+ local ctlfile="error/fail_at_unmount"
+
+ # Once we enable IO errors, it's possible that a writer thread will
+ # trip over EIO, cancel the transaction, and shut down the system.
+ # This is expected behavior, so we need to remove the "Internal error"
+ # message from the list of things that can cause the test to be marked
+ # as failed.
+ _add_dmesg_filter "Internal error"
+
+ # Don't retry any writes during the (presumably) post-shutdown unmount
+ _has_fs_sysfs "$ctlfile" && _set_fs_sysfs_attr $dev "$ctlfile" 1
+
+ # Disable retry of metadata writes that fail with EIO
+ for ctl in max_retries retry_timeout_seconds; do
+ ctlfile="error/metadata/EIO/$ctl"
+
+ _has_fs_sysfs "$ctlfile" && _set_fs_sysfs_attr $dev "$ctlfile" 0
+ done
+}
+
# Skip if we are running an older binary without the stricter input checks.
# Make multiple checks to be sure that there is no regression on the one
# selected feature check, which would skew the result.
diff --git a/src/Makefile b/src/Makefile
index 165db952..cd7e92e3 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -19,7 +19,7 @@ TARGETS = dirstress fill fill2 getpagesize holes lstat64 \
t_ofd_locks t_mmap_collision mmap-write-concurrent \
t_get_file_time t_create_short_dirs t_create_long_dirs t_enospc \
t_mmap_writev_overlap checkpoint_journal mmap-rw-fault allocstale \
- dio_mmap_torture
+ t_mmap_cow_memory_failure dio_mmap_torture
LINUX_TARGETS = xfsctl bstat t_mtab getdevicesize preallo_rw_pattern_reader \
preallo_rw_pattern_writer ftrunc trunc fs_perms testx looptest \
@@ -32,14 +32,15 @@ LINUX_TARGETS = xfsctl bstat t_mtab getdevicesize preallo_rw_pattern_reader \
dio-invalidate-cache stat_test t_encrypted_d_revalidate \
attr_replace_test swapon mkswap t_attr_corruption t_open_tmpfiles \
fscrypt-crypt-util bulkstat_null_ocount splice-test chprojid_fail \
- detached_mounts_propagation ext4_resize t_readdir_3 splice2pipe
+ detached_mounts_propagation ext4_resize t_readdir_3 splice2pipe \
+ uuid_ioctl
EXTRA_EXECS = dmerror fill2attr fill2fs fill2fs_check scaleread.sh \
btrfs_crc32c_forged_name.py
SUBDIRS = log-writes perf
-LLDLIBS = $(LIBHANDLE) $(LIBACL) -lpthread -lrt
+LLDLIBS = $(LIBHANDLE) $(LIBACL) -lpthread -lrt -luuid
ifeq ($(HAVE_XLOG_ASSIGN_LSN), true)
LINUX_TARGETS += loggen
diff --git a/src/fscrypt-crypt-util.c b/src/fscrypt-crypt-util.c
index ffb9534d..087ae09a 100644
--- a/src/fscrypt-crypt-util.c
+++ b/src/fscrypt-crypt-util.c
@@ -37,7 +37,8 @@
/*
* Define to enable the tests of the crypto code in this file. If enabled, you
* must link this program with OpenSSL (-lcrypto) v1.1.0 or later, and your
- * kernel needs CONFIG_CRYPTO_USER_API_SKCIPHER=y and CONFIG_CRYPTO_ADIANTUM=y.
+ * kernel needs CONFIG_CRYPTO_USER_API_SKCIPHER=y, CONFIG_CRYPTO_ADIANTUM=y, and
+ * CONFIG_CRYPTO_HCTR2=y.
*/
#undef ENABLE_ALG_TESTS
@@ -54,7 +55,8 @@ static void usage(FILE *fp)
"resulting ciphertext (or plaintext) to stdout.\n"
"\n"
"CIPHER can be AES-256-XTS, AES-256-CTS-CBC, AES-128-CBC-ESSIV, AES-128-CTS-CBC,\n"
-"or Adiantum. MASTER_KEY must be a hex string long enough for the cipher.\n"
+"Adiantum, or AES-256-HCTR2. MASTER_KEY must be a hex string long enough for\n"
+"the cipher.\n"
"\n"
"WARNING: this program is only meant for testing, not for \"real\" use!\n"
"\n"
@@ -271,7 +273,59 @@ static void rand_bytes(u8 *buf, size_t count)
while (count--)
*buf++ = rand();
}
-#endif
+
+#include <linux/if_alg.h>
+#include <sys/socket.h>
+#define SOL_ALG 279
+static void af_alg_crypt(int algfd, int op, const u8 *key, size_t keylen,
+ const u8 *iv, size_t ivlen,
+ const u8 *src, u8 *dst, size_t datalen)
+{
+ size_t controllen = CMSG_SPACE(sizeof(int)) +
+ CMSG_SPACE(sizeof(struct af_alg_iv) + ivlen);
+ u8 *control = xmalloc(controllen);
+ struct iovec iov = { .iov_base = (u8 *)src, .iov_len = datalen };
+ struct msghdr msg = {
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ .msg_control = control,
+ .msg_controllen = controllen,
+ };
+ struct cmsghdr *cmsg;
+ struct af_alg_iv *algiv;
+ int reqfd;
+
+ memset(control, 0, controllen);
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+ cmsg->cmsg_level = SOL_ALG;
+ cmsg->cmsg_type = ALG_SET_OP;
+ *(int *)CMSG_DATA(cmsg) = op;
+
+ cmsg = CMSG_NXTHDR(&msg, cmsg);
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct af_alg_iv) + ivlen);
+ cmsg->cmsg_level = SOL_ALG;
+ cmsg->cmsg_type = ALG_SET_IV;
+ algiv = (struct af_alg_iv *)CMSG_DATA(cmsg);
+ algiv->ivlen = ivlen;
+ memcpy(algiv->iv, iv, ivlen);
+
+ if (setsockopt(algfd, SOL_ALG, ALG_SET_KEY, key, keylen) != 0)
+ die_errno("can't set key on AF_ALG socket");
+
+ reqfd = accept(algfd, NULL, NULL);
+ if (reqfd < 0)
+ die_errno("can't accept() AF_ALG socket");
+ if (sendmsg(reqfd, &msg, 0) != datalen)
+ die_errno("can't sendmsg() AF_ALG request socket");
+ if (xread(reqfd, dst, datalen) != datalen)
+ die("short read from AF_ALG request socket");
+ close(reqfd);
+
+ free(control);
+}
+#endif /* ENABLE_ALG_TESTS */
/*----------------------------------------------------------------------------*
* Finite field arithmetic *
@@ -296,7 +350,7 @@ typedef struct {
} ble128;
/* Multiply a GF(2^128) element by the polynomial 'x' */
-static inline void gf2_128_mul_x(ble128 *t)
+static inline void gf2_128_mul_x_xts(ble128 *t)
{
u64 lo = le64_to_cpu(t->lo);
u64 hi = le64_to_cpu(t->hi);
@@ -305,6 +359,38 @@ static inline void gf2_128_mul_x(ble128 *t)
t->lo = cpu_to_le64((lo << 1) ^ ((hi & (1ULL << 63)) ? 0x87 : 0));
}
+static inline void gf2_128_mul_x_polyval(ble128 *t)
+{
+ u64 lo = le64_to_cpu(t->lo);
+ u64 hi = le64_to_cpu(t->hi);
+ u64 lo_reducer = (hi & (1ULL << 63)) ? 1 : 0;
+ u64 hi_reducer = (hi & (1ULL << 63)) ? 0xc2ULL << 56 : 0;
+
+ t->hi = cpu_to_le64(((hi << 1) | (lo >> 63)) ^ hi_reducer);
+ t->lo = cpu_to_le64((lo << 1) ^ lo_reducer);
+}
+
+static void gf2_128_mul_polyval(ble128 *r, const ble128 *b)
+{
+ int i;
+ ble128 p;
+ u64 lo = le64_to_cpu(b->lo);
+ u64 hi = le64_to_cpu(b->hi);
+
+ memset(&p, 0, sizeof(p));
+ for (i = 0; i < 64; i++) {
+ if (lo & (1ULL << i))
+ xor((u8 *)&p, (u8 *)&p, (u8 *)r, sizeof(p));
+ gf2_128_mul_x_polyval(r);
+ }
+ for (i = 0; i < 64; i++) {
+ if (hi & (1ULL << i))
+ xor((u8 *)&p, (u8 *)&p, (u8 *)r, sizeof(p));
+ gf2_128_mul_x_polyval(r);
+ }
+ *r = p;
+}
+
/*----------------------------------------------------------------------------*
* Group arithmetic *
*----------------------------------------------------------------------------*/
@@ -905,6 +991,47 @@ static void test_hkdf_sha512(void)
#endif /* ENABLE_ALG_TESTS */
/*----------------------------------------------------------------------------*
+ * POLYVAL *
+ *----------------------------------------------------------------------------*/
+
+/*
+ * Reference: "AES-GCM-SIV: Nonce Misuse-Resistant Authenticated Encryption"
+ * https://datatracker.ietf.org/doc/html/rfc8452
+ */
+
+#define POLYVAL_KEY_SIZE 16
+#define POLYVAL_BLOCK_SIZE 16
+
+static void polyval_update(const u8 key[POLYVAL_KEY_SIZE],
+ const u8 *msg, size_t msglen,
+ u8 accumulator[POLYVAL_BLOCK_SIZE])
+{
+ ble128 h;
+ ble128 aligned_accumulator;
+ // x^{-128} = x^127 + x^124 + x^121 + x^114 + 1
+ static const ble128 inv128 = {
+ cpu_to_le64(1),
+ cpu_to_le64(0x9204ULL << 48)
+ };
+
+ /* Partial block support is not necessary for HCTR2 */
+ ASSERT(msglen % POLYVAL_BLOCK_SIZE == 0);
+
+ memcpy(&h, key, POLYVAL_BLOCK_SIZE);
+ memcpy(&aligned_accumulator, accumulator, POLYVAL_BLOCK_SIZE);
+ gf2_128_mul_polyval(&h, &inv128);
+
+ while (msglen > 0) {
+ xor((u8 *)&aligned_accumulator, (u8 *)&aligned_accumulator, msg,
+ POLYVAL_BLOCK_SIZE);
+ gf2_128_mul_polyval(&aligned_accumulator, &h);
+ msg += POLYVAL_BLOCK_SIZE;
+ msglen -= POLYVAL_BLOCK_SIZE;
+ }
+ memcpy(accumulator, &aligned_accumulator, POLYVAL_BLOCK_SIZE);
+}
+
+/*----------------------------------------------------------------------------*
* AES encryption modes *
*----------------------------------------------------------------------------*/
@@ -927,7 +1054,7 @@ static void aes_256_xts_crypt(const u8 key[2 * AES_256_KEY_SIZE],
else
aes_encrypt(&cipher_key, &dst[i], &dst[i]);
xor(&dst[i], &dst[i], (const u8 *)&t, AES_BLOCK_SIZE);
- gf2_128_mul_x(&t);
+ gf2_128_mul_x_xts(&t);
}
}
@@ -1176,6 +1303,167 @@ static void aes_128_cts_cbc_decrypt(const u8 key[AES_128_KEY_SIZE],
aes_cts_cbc_decrypt(key, AES_128_KEY_SIZE, iv, src, dst, nbytes);
}
+/*
+ * Reference: "Length-preserving encryption with HCTR2"
+ * https://ia.cr/2021/1441
+ */
+
+static void aes_256_xctr_crypt(const u8 key[AES_256_KEY_SIZE],
+ const u8 iv[AES_BLOCK_SIZE], const u8 *src,
+ u8 *dst, size_t nbytes)
+{
+ struct aes_key k;
+ union {
+ u8 bytes[AES_BLOCK_SIZE];
+ __le64 ctr;
+ } blk;
+ size_t i;
+
+ aes_setkey(&k, key, AES_256_KEY_SIZE);
+
+ for (i = 0; i < nbytes; i += AES_BLOCK_SIZE) {
+ memcpy(blk.bytes, iv, AES_BLOCK_SIZE);
+ blk.ctr ^= cpu_to_le64((i / AES_BLOCK_SIZE) + 1);
+ aes_encrypt(&k, blk.bytes, blk.bytes);
+ xor(&dst[i], blk.bytes, &src[i], MIN(AES_BLOCK_SIZE, nbytes - i));
+ }
+}
+
+/*
+ * Reference: "Length-preserving encryption with HCTR2"
+ * https://ia.cr/2021/1441
+ */
+
+#define HCTR2_IV_SIZE 32
+static void hctr2_hash_iv(const u8 hbar[POLYVAL_KEY_SIZE],
+ const u8 iv[HCTR2_IV_SIZE], size_t msglen,
+ u8 digest[POLYVAL_BLOCK_SIZE])
+{
+ le128 tweaklen_blk = {
+ .lo = cpu_to_le64(HCTR2_IV_SIZE * 8 * 2 + 2 +
+ (msglen % AES_BLOCK_SIZE != 0))
+ };
+
+ memset(digest, 0, POLYVAL_BLOCK_SIZE);
+ polyval_update(hbar, (u8 *)&tweaklen_blk, POLYVAL_BLOCK_SIZE, digest);
+ polyval_update(hbar, iv, HCTR2_IV_SIZE, digest);
+}
+
+static void hctr2_hash_message(const u8 hbar[POLYVAL_KEY_SIZE],
+ const u8 *msg, size_t msglen,
+ u8 digest[POLYVAL_BLOCK_SIZE])
+{
+ size_t remainder = msglen % AES_BLOCK_SIZE;
+ u8 padded_block[POLYVAL_BLOCK_SIZE] = {0};
+
+ polyval_update(hbar, msg, msglen - remainder, digest);
+ if (remainder) {
+ memcpy(padded_block, &msg[msglen - remainder], remainder);
+ padded_block[remainder] = 1;
+ polyval_update(hbar, padded_block, POLYVAL_BLOCK_SIZE, digest);
+ }
+}
+
+static void aes_256_hctr2_crypt(const u8 key[AES_256_KEY_SIZE],
+ const u8 iv[HCTR2_IV_SIZE], const u8 *src,
+ u8 *dst, size_t nbytes, bool decrypting)
+{
+ struct aes_key k;
+ u8 hbar[AES_BLOCK_SIZE] = {0};
+ u8 L[AES_BLOCK_SIZE] = {1};
+ size_t bulk_bytes = nbytes - AES_BLOCK_SIZE;
+ u8 digest[POLYVAL_BLOCK_SIZE];
+ const u8 *M = src;
+ const u8 *N = src + AES_BLOCK_SIZE;
+ u8 MM[AES_BLOCK_SIZE];
+ u8 UU[AES_BLOCK_SIZE];
+ u8 S[AES_BLOCK_SIZE];
+ u8 *U = dst;
+ u8 *V = dst + AES_BLOCK_SIZE;
+
+ ASSERT(nbytes >= AES_BLOCK_SIZE);
+ aes_setkey(&k, key, AES_256_KEY_SIZE);
+
+ aes_encrypt(&k, hbar, hbar);
+ aes_encrypt(&k, L, L);
+
+ hctr2_hash_iv(hbar, iv, bulk_bytes, digest);
+ hctr2_hash_message(hbar, N, bulk_bytes, digest);
+
+ xor(MM, M, digest, AES_BLOCK_SIZE);
+
+ if (decrypting)
+ aes_decrypt(&k, MM, UU);
+ else
+ aes_encrypt(&k, MM, UU);
+
+ xor(S, MM, UU, AES_BLOCK_SIZE);
+ xor(S, L, S, AES_BLOCK_SIZE);
+
+ aes_256_xctr_crypt(key, S, N, V, bulk_bytes);
+
+ hctr2_hash_iv(hbar, iv, bulk_bytes, digest);
+ hctr2_hash_message(hbar, V, bulk_bytes, digest);
+
+ xor(U, UU, digest, AES_BLOCK_SIZE);
+}
+
+static void aes_256_hctr2_encrypt(const u8 key[AES_256_KEY_SIZE],
+ const u8 iv[HCTR2_IV_SIZE], const u8 *src,
+ u8 *dst, size_t nbytes)
+{
+ aes_256_hctr2_crypt(key, iv, src, dst, nbytes, false);
+}
+
+static void aes_256_hctr2_decrypt(const u8 key[AES_256_KEY_SIZE],
+ const u8 iv[HCTR2_IV_SIZE], const u8 *src,
+ u8 *dst, size_t nbytes)
+{
+ aes_256_hctr2_crypt(key, iv, src, dst, nbytes, true);
+}
+
+#ifdef ENABLE_ALG_TESTS
+#include <linux/if_alg.h>
+#include <sys/socket.h>
+static void test_aes_256_hctr2(void)
+{
+ int algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
+ struct sockaddr_alg addr = {
+ .salg_type = "skcipher",
+ .salg_name = "hctr2(aes)",
+ };
+ unsigned long num_tests = NUM_ALG_TEST_ITERATIONS;
+
+ if (algfd < 0)
+ die_errno("can't create AF_ALG socket");
+ if (bind(algfd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
+ die_errno("can't bind AF_ALG socket to HCTR2 algorithm");
+
+ while (num_tests--) {
+ u8 key[AES_256_KEY_SIZE];
+ u8 iv[HCTR2_IV_SIZE];
+ u8 ptext[4096];
+ u8 ctext[sizeof(ptext)];
+ u8 ref_ctext[sizeof(ptext)];
+ u8 decrypted[sizeof(ptext)];
+ const size_t datalen = 16 + (rand() % (sizeof(ptext) - 15));
+
+ rand_bytes(key, sizeof(key));
+ rand_bytes(iv, sizeof(iv));
+ rand_bytes(ptext, datalen);
+
+ aes_256_hctr2_encrypt(key, iv, ptext, ctext, datalen);
+ af_alg_crypt(algfd, ALG_OP_ENCRYPT, key, sizeof(key),
+ iv, sizeof(iv), ptext, ref_ctext, datalen);
+ ASSERT(memcmp(ctext, ref_ctext, datalen) == 0);
+
+ aes_256_hctr2_decrypt(key, iv, ctext, decrypted, datalen);
+ ASSERT(memcmp(ptext, decrypted, datalen) == 0);
+ }
+ close(algfd);
+}
+#endif /* ENABLE_ALG_TESTS */
+
/*----------------------------------------------------------------------------*
* XChaCha12 stream cipher *
*----------------------------------------------------------------------------*/
@@ -1503,58 +1791,6 @@ static void adiantum_decrypt(const u8 key[ADIANTUM_KEY_SIZE],
}
#ifdef ENABLE_ALG_TESTS
-#include <linux/if_alg.h>
-#include <sys/socket.h>
-#define SOL_ALG 279
-static void af_alg_crypt(int algfd, int op, const u8 *key, size_t keylen,
- const u8 *iv, size_t ivlen,
- const u8 *src, u8 *dst, size_t datalen)
-{
- size_t controllen = CMSG_SPACE(sizeof(int)) +
- CMSG_SPACE(sizeof(struct af_alg_iv) + ivlen);
- u8 *control = xmalloc(controllen);
- struct iovec iov = { .iov_base = (u8 *)src, .iov_len = datalen };
- struct msghdr msg = {
- .msg_iov = &iov,
- .msg_iovlen = 1,
- .msg_control = control,
- .msg_controllen = controllen,
- };
- struct cmsghdr *cmsg;
- struct af_alg_iv *algiv;
- int reqfd;
-
- memset(control, 0, controllen);
-
- cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_len = CMSG_LEN(sizeof(int));
- cmsg->cmsg_level = SOL_ALG;
- cmsg->cmsg_type = ALG_SET_OP;
- *(int *)CMSG_DATA(cmsg) = op;
-
- cmsg = CMSG_NXTHDR(&msg, cmsg);
- cmsg->cmsg_len = CMSG_LEN(sizeof(struct af_alg_iv) + ivlen);
- cmsg->cmsg_level = SOL_ALG;
- cmsg->cmsg_type = ALG_SET_IV;
- algiv = (struct af_alg_iv *)CMSG_DATA(cmsg);
- algiv->ivlen = ivlen;
- memcpy(algiv->iv, iv, ivlen);
-
- if (setsockopt(algfd, SOL_ALG, ALG_SET_KEY, key, keylen) != 0)
- die_errno("can't set key on AF_ALG socket");
-
- reqfd = accept(algfd, NULL, NULL);
- if (reqfd < 0)
- die_errno("can't accept() AF_ALG socket");
- if (sendmsg(reqfd, &msg, 0) != datalen)
- die_errno("can't sendmsg() AF_ALG request socket");
- if (xread(reqfd, dst, datalen) != datalen)
- die("short read from AF_ALG request socket");
- close(reqfd);
-
- free(control);
-}
-
static void test_adiantum(void)
{
int algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
@@ -1679,6 +1915,12 @@ static const struct fscrypt_cipher {
.keysize = AES_128_KEY_SIZE,
.min_input_size = AES_BLOCK_SIZE,
}, {
+ .name = "AES-256-HCTR2",
+ .encrypt = aes_256_hctr2_encrypt,
+ .decrypt = aes_256_hctr2_decrypt,
+ .keysize = AES_256_KEY_SIZE,
+ .min_input_size = AES_BLOCK_SIZE,
+ }, {
.name = "Adiantum",
.encrypt = adiantum_encrypt,
.decrypt = adiantum_decrypt,
@@ -2036,6 +2278,7 @@ int main(int argc, char *argv[])
test_aes_256_xts();
test_aes_256_cts_cbc();
test_adiantum();
+ test_aes_256_hctr2();
#endif
while ((c = getopt_long(argc, argv, "", longopts, NULL)) != -1) {
diff --git a/src/seek_sanity_test.c b/src/seek_sanity_test.c
index 1030d0c5..78f835e8 100644
--- a/src/seek_sanity_test.c
+++ b/src/seek_sanity_test.c
@@ -40,6 +40,28 @@ static void get_file_system(int fd)
}
}
+/* Compute the file allocation unit size for an XFS file. */
+static int detect_xfs_alloc_unit(int fd)
+{
+ struct fsxattr fsx;
+ struct xfs_fsop_geom fsgeom;
+ int ret;
+
+ ret = ioctl(fd, XFS_IOC_FSGEOMETRY, &fsgeom);
+ if (ret)
+ return -1;
+
+ ret = ioctl(fd, XFS_IOC_FSGETXATTR, &fsx);
+ if (ret)
+ return -1;
+
+ alloc_size = fsgeom.blocksize;
+ if (fsx.fsx_xflags & XFS_XFLAG_REALTIME)
+ alloc_size *= fsgeom.rtextsize;
+
+ return 0;
+}
+
static int get_io_sizes(int fd)
{
off_t pos = 0, offset = 1;
@@ -47,6 +69,10 @@ static int get_io_sizes(int fd)
int shift, ret;
int pagesz = sysconf(_SC_PAGE_SIZE);
+ ret = detect_xfs_alloc_unit(fd);
+ if (!ret)
+ goto done;
+
ret = fstat(fd, &buf);
if (ret) {
fprintf(stderr, " ERROR %d: Failed to find io blocksize\n",
@@ -54,16 +80,8 @@ static int get_io_sizes(int fd)
return ret;
}
- /*
- * st_blksize is typically also the allocation size. However, XFS
- * rounds this up to the page size, so if the stat blocksize is exactly
- * one page, use this iterative algorithm to see if SEEK_DATA will hint
- * at a more precise answer based on the filesystem's (pre)allocation
- * decisions.
- */
+ /* st_blksize is typically also the allocation size */
alloc_size = buf.st_blksize;
- if (alloc_size != pagesz)
- goto done;
/* try to discover the actual alloc size */
while (pos == 0 && offset < alloc_size) {
diff --git a/src/t_mmap_cow_memory_failure.c b/src/t_mmap_cow_memory_failure.c
new file mode 100644
index 00000000..bb3fd3fb
--- /dev/null
+++ b/src/t_mmap_cow_memory_failure.c
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2022 Fujitsu Limited. All Rights Reserved. */
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <semaphore.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <sys/sem.h>
+#include <time.h>
+#include <unistd.h>
+
+sem_t *sem;
+
+void sigbus_handler(int signal)
+{
+ printf("Process is killed by signal: %d\n", signal);
+ sem_post(sem);
+}
+
+void mmap_read_file(char *filename, off_t offset, size_t size)
+{
+ int fd;
+ char *map, *dummy;
+ struct timespec ts;
+
+ fd = open(filename, O_RDWR);
+ map = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, offset);
+ dummy = malloc(size);
+
+ /* make sure page fault happens */
+ memcpy(dummy, map, size);
+
+ /* ready */
+ sem_post(sem);
+
+ usleep(200000);
+
+ clock_gettime(CLOCK_REALTIME, &ts);
+ ts.tv_sec += 3;
+ /* wait for injection done */
+ sem_timedwait(sem, &ts);
+
+ free(dummy);
+ munmap(map, size);
+ close(fd);
+}
+
+void mmap_read_file_then_poison(char *filename, off_t offset, size_t size,
+ off_t poisonOffset, size_t poisonSize)
+{
+ int fd, error;
+ char *map, *dummy;
+
+ /* wait for parent preparation done */
+ sem_wait(sem);
+
+ fd = open(filename, O_RDWR);
+ map = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, offset);
+ dummy = malloc(size);
+
+ /* make sure page fault happens */
+ memcpy(dummy, map, size);
+
+ printf("Inject poison...\n");
+ error = madvise(map + poisonOffset, poisonSize, MADV_HWPOISON);
+ if (error)
+ printf("madvise() has fault: %d, errno: %d\n", error, errno);
+
+ free(dummy);
+ munmap(map, size);
+ close(fd);
+}
+
+int main(int argc, char *argv[])
+{
+ char *pReadFile = NULL, *pPoisonFile = NULL;
+ size_t mmapSize, poisonSize;
+ off_t mmapOffset = 0, poisonOffset = 0;
+ long pagesize = sysconf(_SC_PAGESIZE);
+ int c;
+ pid_t pid;
+
+ if (pagesize < 1) {
+ fprintf(stderr, "sysconf(_SC_PAGESIZE): failed to get page size\n");
+ abort();
+ }
+
+ /* default mmap / poison size, in unit of System Page Size */
+ mmapSize = poisonSize = pagesize;
+
+ while ((c = getopt(argc, argv, "o::s::O::S::R:P:")) != -1) {
+ switch (c) {
+ /* mmap offset */
+ case 'o':
+ mmapOffset = atoi(optarg) * pagesize;
+ break;
+ /* mmap size */
+ case 's':
+ mmapSize = atoi(optarg) * pagesize;
+ break;
+ /* madvice offset */
+ case 'O':
+ poisonOffset = atoi(optarg) * pagesize;
+ break;
+ /* madvice size */
+ case 'S':
+ poisonSize = atoi(optarg) * pagesize;
+ break;
+ /* filename for mmap read */
+ case 'R':
+ pReadFile = optarg;
+ break;
+ /* filename for poison read */
+ case 'P':
+ pPoisonFile = optarg;
+ break;
+ default:
+ printf("Unknown option: %c\n", c);
+ exit(1);
+ }
+ }
+
+ if (!pReadFile || !pPoisonFile) {
+ printf("Usage: \n"
+ " %s [-o mmapOffset] [-s mmapSize] [-O mmapOffset] [-S mmapSize] -R readFile -P poisonFile\n"
+ " (offset and size are both in unit of System Page Size: %ld)\n",
+ basename(argv[0]), pagesize);
+ exit(0);
+ }
+ if (poisonSize < mmapSize)
+ mmapSize = poisonSize;
+
+ /* fork and mmap files */
+ pid = fork();
+ if (pid == 0) {
+ /* handle SIGBUS */
+ signal(SIGBUS, sigbus_handler);
+ sem = sem_open("sync", O_CREAT, 0666, 0);
+
+ /* mread & do memory failure on poison file */
+ mmap_read_file_then_poison(pPoisonFile, mmapOffset, mmapSize,
+ poisonOffset, poisonSize);
+
+ sem_close(sem);
+ } else {
+ sem = sem_open("sync", O_CREAT, 0666, 0);
+
+ /* mread read file, wait for child process to be killed */
+ mmap_read_file(pReadFile, mmapOffset, mmapSize);
+ sem_close(sem);
+ }
+ exit(0);
+}
diff --git a/src/t_ofd_locks.c b/src/t_ofd_locks.c
index e3b15ddc..e77f2659 100644
--- a/src/t_ofd_locks.c
+++ b/src/t_ofd_locks.c
@@ -187,6 +187,8 @@ int main(int argc, char **argv)
struct sembuf sop;
int opt, ret, retry;
+ //avoid libcap errno bug
+ errno = 0;
while((opt = getopt(argc, argv, "sgrwo:l:PRWtFd")) != -1) {
switch(opt) {
case 's':
diff --git a/src/uuid_ioctl.c b/src/uuid_ioctl.c
new file mode 100644
index 00000000..89a9b5d8
--- /dev/null
+++ b/src/uuid_ioctl.c
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 Google, Inc. All Rights Reserved.
+ *
+ * Test program which uses the raw ext4 set_fsuuid ioctl directly.
+ * SYNOPSIS:
+ * $0 COMMAND MOUNT_POINT [UUID]
+ *
+ * COMMAND must be either "get" or "set".
+ * The UUID must be a 16 octet sequence represented as 32 hexadecimal digits in
+ * canonical textual representation, e.g. output from `uuidgen`.
+ *
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <uuid/uuid.h>
+#include <linux/fs.h>
+
+struct fsuuid {
+ __u32 fsu_len;
+ __u32 fsu_flags;
+ __u8 fsu_uuid[];
+};
+
+#ifndef EXT4_IOC_GETFSUUID
+#define EXT4_IOC_GETFSUUID _IOR('f', 44, struct fsuuid)
+#endif
+
+#ifndef EXT4_IOC_SETFSUUID
+#define EXT4_IOC_SETFSUUID _IOW('f', 44, struct fsuuid)
+#endif
+
+int main(int argc, char **argv)
+{
+ int error, fd;
+ struct fsuuid *fsuuid = NULL;
+
+ if (argc < 3) {
+ fprintf(stderr, "Invalid arguments\n");
+ return 1;
+ }
+
+ fd = open(argv[2], O_RDONLY);
+ if (!fd) {
+ perror(argv[2]);
+ return 1;
+ }
+
+ fsuuid = malloc(sizeof(*fsuuid) + sizeof(uuid_t));
+ if (!fsuuid) {
+ perror("malloc");
+ return 1;
+ }
+ fsuuid->fsu_len = sizeof(uuid_t);
+ fsuuid->fsu_flags = 0;
+
+ if (strcmp(argv[1], "get") == 0) {
+ uuid_t uuid;
+ char uuid_str[37];
+
+ if (ioctl(fd, EXT4_IOC_GETFSUUID, fsuuid)) {
+ fprintf(stderr, "%s while trying to get fs uuid\n",
+ strerror(errno));
+ return 1;
+ }
+
+ memcpy(&uuid, fsuuid->fsu_uuid, sizeof(uuid));
+ uuid_unparse(uuid, uuid_str);
+ printf("%s\n", uuid_str);
+ } else if (strcmp(argv[1], "set") == 0) {
+ uuid_t uuid;
+
+ if (argc != 4) {
+ fprintf(stderr, "UUID argument missing.\n");
+ return 1;
+ }
+
+ error = uuid_parse(argv[3], uuid);
+ if (error < 0) {
+ fprintf(stderr, "Invalid UUID. The UUID should be in "
+ "canonical format. Example: "
+ "8c628557-6987-42b2-ba16-b7cc79ddfb43\n");
+ return 1;
+ }
+
+ memcpy(&fsuuid->fsu_uuid, uuid, sizeof(uuid));
+ if (ioctl(fd, EXT4_IOC_SETFSUUID, fsuuid)) {
+ fprintf(stderr, "%s while trying to set fs uuid\n",
+ strerror(errno));
+ return 1;
+ }
+ } else {
+ fprintf(stderr, "Invalid command\n");
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/src/vfs/idmapped-mounts.c b/src/vfs/idmapped-mounts.c
index 63297d5f..c010dfa1 100644
--- a/src/vfs/idmapped-mounts.c
+++ b/src/vfs/idmapped-mounts.c
@@ -7664,6 +7664,1193 @@ out:
return fret;
}
+/* The current_umask() is stripped from the mode directly in the vfs if the
+ * filesystem either doesn't support acls or the filesystem has been
+ * mounted without posic acl support.
+ *
+ * If the filesystem does support acls then current_umask() stripping is
+ * deferred to posix_acl_create(). So when the filesystem calls
+ * posix_acl_create() and there are no acls set or not supported then
+ * current_umask() will be stripped.
+ *
+ * Use umask(S_IXGRP) to check whether inode strip S_ISGID works correctly
+ * in idmapped situation.
+ *
+ * Test for commit ac6800e279a2 ("fs: Add missing umask strip in vfs_tmpfile")
+ * and 1639a49ccdce ("fs: move S_ISGID stripping into the vfs_*() helpers").
+ */
+static int setgid_create_umask_idmapped(const struct vfstest_info *info)
+{
+ int fret = -1;
+ int file1_fd = -EBADF, open_tree_fd = -EBADF;
+ struct mount_attr attr = {
+ .attr_set = MOUNT_ATTR_IDMAP,
+ };
+ pid_t pid;
+ int tmpfile_fd = -EBADF;
+ bool supported = false;
+ char path[PATH_MAX];
+ mode_t mode;
+
+ if (!caps_supported())
+ return 0;
+
+ if (fchmod(info->t_dir1_fd, S_IRUSR |
+ S_IWUSR |
+ S_IRGRP |
+ S_IWGRP |
+ S_IROTH |
+ S_IWOTH |
+ S_IXUSR |
+ S_IXGRP |
+ S_IXOTH |
+ S_ISGID), 0) {
+ log_stderr("failure: fchmod");
+ goto out;
+ }
+
+ /* Verify that the sid bits got raised. */
+ if (!is_setgid(info->t_dir1_fd, "", AT_EMPTY_PATH)) {
+ log_stderr("failure: is_setgid");
+ goto out;
+ }
+
+ /* Changing mount properties on a detached mount. */
+ attr.userns_fd = get_userns_fd(0, 10000, 10000);
+ if (attr.userns_fd < 0) {
+ log_stderr("failure: get_userns_fd");
+ goto out;
+ }
+
+ open_tree_fd = sys_open_tree(info->t_dir1_fd, "",
+ AT_EMPTY_PATH |
+ AT_NO_AUTOMOUNT |
+ AT_SYMLINK_NOFOLLOW |
+ OPEN_TREE_CLOEXEC |
+ OPEN_TREE_CLONE);
+ if (open_tree_fd < 0) {
+ log_stderr("failure: sys_open_tree");
+ goto out;
+ }
+
+ if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
+ log_stderr("failure: sys_mount_setattr");
+ goto out;
+ }
+
+ supported = openat_tmpfile_supported(open_tree_fd);
+
+ pid = fork();
+ if (pid < 0) {
+ log_stderr("failure: fork");
+ goto out;
+ }
+ if (pid == 0) {
+ /* Only umask with S_IXGRP because inode strip S_ISGID will check mode
+ * whether has group execute or search permission.
+ */
+ umask(S_IXGRP);
+ mode = umask(S_IXGRP);
+ if (!(mode & S_IXGRP))
+ die("failure: umask");
+
+ if (!switch_ids(10000, 11000))
+ die("failure: switch fsids");
+
+ /* create regular file via open() */
+ file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
+ if (file1_fd < 0)
+ die("failure: create");
+
+ /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
+ * bit needs to be stripped.
+ */
+ if (is_setgid(open_tree_fd, FILE1, 0))
+ die("failure: is_setgid");
+
+ if (is_ixgrp(open_tree_fd, FILE1, 0))
+ die("failure: is_ixgrp");
+
+ /* create directory */
+ if (mkdirat(open_tree_fd, DIR1, 0000))
+ die("failure: create");
+
+ if (xfs_irix_sgid_inherit_enabled(info->t_fstype)) {
+ /* We're not in_group_p(). */
+ if (is_setgid(open_tree_fd, DIR1, 0))
+ die("failure: is_setgid");
+ } else {
+ /* Directories always inherit the setgid bit. */
+ if (!is_setgid(open_tree_fd, DIR1, 0))
+ die("failure: is_setgid");
+ }
+
+ if (is_ixgrp(open_tree_fd, DIR1, 0))
+ die("failure: is_ixgrp");
+
+ /* create a special file via mknodat() vfs_create */
+ if (mknodat(open_tree_fd, FILE2, S_IFREG | S_ISGID | S_IXGRP, 0))
+ die("failure: mknodat");
+
+ if (is_setgid(open_tree_fd, FILE2, 0))
+ die("failure: is_setgid");
+
+ if (is_ixgrp(open_tree_fd, FILE2, 0))
+ die("failure: is_ixgrp");
+
+ /* create a whiteout device via mknodat() vfs_mknod */
+ if (mknodat(open_tree_fd, CHRDEV1, S_IFCHR | S_ISGID | S_IXGRP, 0))
+ die("failure: mknodat");
+
+ if (is_setgid(open_tree_fd, CHRDEV1, 0))
+ die("failure: is_setgid");
+
+ if (is_ixgrp(open_tree_fd, CHRDEV1, 0))
+ die("failure: is_ixgrp");
+
+ /*
+ * In setgid directories newly created files always inherit the
+ * gid from the parent directory. Verify that the file is owned
+ * by gid 10000, not by gid 11000.
+ */
+ if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
+ die("failure: check ownership");
+
+ /*
+ * In setgid directories newly created directories always
+ * inherit the gid from the parent directory. Verify that the
+ * directory is owned by gid 10000, not by gid 11000.
+ */
+ if (!expected_uid_gid(open_tree_fd, DIR1, 0, 10000, 10000))
+ die("failure: check ownership");
+
+ if (!expected_uid_gid(open_tree_fd, FILE2, 0, 10000, 10000))
+ die("failure: check ownership");
+
+ if (!expected_uid_gid(open_tree_fd, CHRDEV1, 0, 10000, 10000))
+ die("failure: check ownership");
+
+ if (unlinkat(open_tree_fd, FILE1, 0))
+ die("failure: delete");
+
+ if (unlinkat(open_tree_fd, DIR1, AT_REMOVEDIR))
+ die("failure: delete");
+
+ if (unlinkat(open_tree_fd, FILE2, 0))
+ die("failure: delete");
+
+ if (unlinkat(open_tree_fd, CHRDEV1, 0))
+ die("failure: delete");
+
+ /* create tmpfile via filesystem tmpfile api */
+ if (supported) {
+ tmpfile_fd = openat(open_tree_fd, ".", O_TMPFILE | O_RDWR, S_IXGRP | S_ISGID);
+ if (tmpfile_fd < 0)
+ die("failure: create");
+ /* link the temporary file into the filesystem, making it permanent */
+ snprintf(path, PATH_MAX, "/proc/self/fd/%d", tmpfile_fd);
+ if (linkat(AT_FDCWD, path, open_tree_fd, FILE3, AT_SYMLINK_FOLLOW))
+ die("failure: linkat");
+ if (close(tmpfile_fd))
+ die("failure: close");
+ if (is_setgid(open_tree_fd, FILE3, 0))
+ die("failure: is_setgid");
+ if (is_ixgrp(open_tree_fd, FILE3, 0))
+ die("failure: is_ixgrp");
+ if (!expected_uid_gid(open_tree_fd, FILE3, 0, 10000, 10000))
+ die("failure: check ownership");
+ if (unlinkat(open_tree_fd, FILE3, 0))
+ die("failure: delete");
+ }
+
+ exit(EXIT_SUCCESS);
+ }
+ if (wait_for_pid(pid))
+ goto out;
+
+ fret = 0;
+ log_debug("Ran test");
+out:
+ safe_close(attr.userns_fd);
+ safe_close(file1_fd);
+ safe_close(open_tree_fd);
+
+ return fret;
+}
+
+/* The current_umask() is stripped from the mode directly in the vfs if the
+ * filesystem either doesn't support acls or the filesystem has been
+ * mounted without posic acl support.
+ *
+ * If the filesystem does support acls then current_umask() stripping is
+ * deferred to posix_acl_create(). So when the filesystem calls
+ * posix_acl_create() and there are no acls set or not supported then
+ * current_umask() will be stripped.
+ *
+ * Use umask(S_IXGRP) to check whether inode strip S_ISGID works correctly
+ * in idmapped_in_userns situation.
+ *
+ * Test for commit ac6800e279a2 ("fs: Add missing umask strip in vfs_tmpfile")
+ * and 1639a49ccdce ("fs: move S_ISGID stripping into the vfs_*() helpers").
+ */
+static int setgid_create_umask_idmapped_in_userns(const struct vfstest_info *info)
+{
+ int fret = -1;
+ int file1_fd = -EBADF, open_tree_fd = -EBADF;
+ struct mount_attr attr = {
+ .attr_set = MOUNT_ATTR_IDMAP,
+ };
+ pid_t pid;
+ int tmpfile_fd = -EBADF;
+ bool supported = false;
+ char path[PATH_MAX];
+ mode_t mode;
+
+ if (!caps_supported())
+ return 0;
+
+ if (fchmod(info->t_dir1_fd, S_IRUSR |
+ S_IWUSR |
+ S_IRGRP |
+ S_IWGRP |
+ S_IROTH |
+ S_IWOTH |
+ S_IXUSR |
+ S_IXGRP |
+ S_IXOTH |
+ S_ISGID), 0) {
+ log_stderr("failure: fchmod");
+ goto out;
+ }
+
+ /* Verify that the sid bits got raised. */
+ if (!is_setgid(info->t_dir1_fd, "", AT_EMPTY_PATH)) {
+ log_stderr("failure: is_setgid");
+ goto out;
+ }
+
+ /* Changing mount properties on a detached mount. */
+ attr.userns_fd = get_userns_fd(0, 10000, 10000);
+ if (attr.userns_fd < 0) {
+ log_stderr("failure: get_userns_fd");
+ goto out;
+ }
+
+ open_tree_fd = sys_open_tree(info->t_dir1_fd, "",
+ AT_EMPTY_PATH |
+ AT_NO_AUTOMOUNT |
+ AT_SYMLINK_NOFOLLOW |
+ OPEN_TREE_CLOEXEC |
+ OPEN_TREE_CLONE);
+ if (open_tree_fd < 0) {
+ log_stderr("failure: sys_open_tree");
+ goto out;
+ }
+
+ if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
+ log_stderr("failure: sys_mount_setattr");
+ goto out;
+ }
+
+ supported = openat_tmpfile_supported(open_tree_fd);
+
+ /*
+ * Below we verify that setgid inheritance for a newly created file or
+ * directory works correctly. As part of this we need to verify that
+ * newly created files or directories inherit their gid from their
+ * parent directory. So we change the parent directorie's gid to 1000
+ * and create a file with fs{g,u}id 0 and verify that the newly created
+ * file and directory inherit gid 1000, not 0.
+ */
+ if (fchownat(info->t_dir1_fd, "", -1, 1000, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
+ log_stderr("failure: fchownat");
+ goto out;
+ }
+
+ pid = fork();
+ if (pid < 0) {
+ log_stderr("failure: fork");
+ goto out;
+ }
+ if (pid == 0) {
+ if (!caps_supported()) {
+ log_debug("skip: capability library not installed");
+ exit(EXIT_SUCCESS);
+ }
+
+ /* Only umask with S_IXGRP because inode strip S_ISGID will check mode
+ * whether has group execute or search permission.
+ */
+ umask(S_IXGRP);
+ mode = umask(S_IXGRP);
+ if (!(mode & S_IXGRP))
+ die("failure: umask");
+
+ if (!switch_userns(attr.userns_fd, 0, 0, false))
+ die("failure: switch_userns");
+
+ if (!caps_down_fsetid())
+ die("failure: caps_down_fsetid");
+
+ /* create regular file via open() */
+ file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
+ if (file1_fd < 0)
+ die("failure: create");
+
+ /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
+ * bit needs to be stripped.
+ */
+ if (is_setgid(open_tree_fd, FILE1, 0))
+ die("failure: is_setgid");
+
+ if (is_ixgrp(open_tree_fd, FILE1, 0))
+ die("failure: is_ixgrp");
+
+ /* create directory */
+ if (mkdirat(open_tree_fd, DIR1, 0000))
+ die("failure: create");
+
+ if (xfs_irix_sgid_inherit_enabled(info->t_fstype)) {
+ /* We're not in_group_p(). */
+ if (is_setgid(open_tree_fd, DIR1, 0))
+ die("failure: is_setgid");
+ } else {
+ /* Directories always inherit the setgid bit. */
+ if (!is_setgid(open_tree_fd, DIR1, 0))
+ die("failure: is_setgid");
+ }
+
+ if (is_ixgrp(open_tree_fd, DIR1, 0))
+ die("failure: is_ixgrp");
+
+ /* create a special file via mknodat() vfs_create */
+ if (mknodat(open_tree_fd, FILE2, S_IFREG | S_ISGID | S_IXGRP, 0))
+ die("failure: mknodat");
+
+ if (is_setgid(open_tree_fd, FILE2, 0))
+ die("failure: is_setgid");
+
+ if (is_ixgrp(open_tree_fd, FILE2, 0))
+ die("failure: is_ixgrp");
+
+ /* create a whiteout device via mknodat() vfs_mknod */
+ if (mknodat(open_tree_fd, CHRDEV1, S_IFCHR | S_ISGID | S_IXGRP, 0))
+ die("failure: mknodat");
+
+ if (is_setgid(open_tree_fd, CHRDEV1, 0))
+ die("failure: is_setgid");
+
+ if (is_ixgrp(open_tree_fd, CHRDEV1, 0))
+ die("failure: is_ixgrp");
+
+ /*
+ * In setgid directories newly created files always inherit the
+ * gid from the parent directory. Verify that the file is owned
+ * by gid 1000, not by gid 0.
+ */
+ if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 1000))
+ die("failure: check ownership");
+
+ /*
+ * In setgid directories newly created directories always
+ * inherit the gid from the parent directory. Verify that the
+ * directory is owned by gid 1000, not by gid 0.
+ */
+ if (!expected_uid_gid(open_tree_fd, DIR1, 0, 0, 1000))
+ die("failure: check ownership");
+
+ if (!expected_uid_gid(open_tree_fd, FILE2, 0, 0, 1000))
+ die("failure: check ownership");
+
+ if (!expected_uid_gid(open_tree_fd, CHRDEV1, 0, 0, 1000))
+ die("failure: check ownership");
+
+ if (unlinkat(open_tree_fd, FILE1, 0))
+ die("failure: delete");
+
+ if (unlinkat(open_tree_fd, DIR1, AT_REMOVEDIR))
+ die("failure: delete");
+
+ if (unlinkat(open_tree_fd, FILE2, 0))
+ die("failure: delete");
+
+ if (unlinkat(open_tree_fd, CHRDEV1, 0))
+ die("failure: delete");
+
+ /* create tmpfile via filesystem tmpfile api */
+ if (supported) {
+ tmpfile_fd = openat(open_tree_fd, ".", O_TMPFILE | O_RDWR, S_IXGRP | S_ISGID);
+ if (tmpfile_fd < 0)
+ die("failure: create");
+ /* link the temporary file into the filesystem, making it permanent */
+ snprintf(path, PATH_MAX, "/proc/self/fd/%d", tmpfile_fd);
+ if (linkat(AT_FDCWD, path, open_tree_fd, FILE3, AT_SYMLINK_FOLLOW))
+ die("failure: linkat");
+ if (close(tmpfile_fd))
+ die("failure: close");
+ if (is_setgid(open_tree_fd, FILE3, 0))
+ die("failure: is_setgid");
+ if (is_ixgrp(open_tree_fd, FILE3, 0))
+ die("failure: is_ixgrp");
+ if (!expected_uid_gid(open_tree_fd, FILE3, 0, 0, 1000))
+ die("failure: check ownership");
+ if (unlinkat(open_tree_fd, FILE3, 0))
+ die("failure: delete");
+ }
+
+ exit(EXIT_SUCCESS);
+ }
+ if (wait_for_pid(pid))
+ goto out;
+
+ fret = 0;
+ log_debug("Ran test");
+out:
+ safe_close(attr.userns_fd);
+ safe_close(file1_fd);
+ safe_close(open_tree_fd);
+
+ return fret;
+}
+
+/*
+ * If the parent directory has a default acl then permissions are based off
+ * of that and current_umask() is ignored. Specifically, if the ACL has an
+ * ACL_MASK entry, the group permissions correspond to the permissions of
+ * the ACL_MASK entry. Otherwise, if the ACL has no ACL_MASK entry, the
+ * group permissions correspond to the permissions of the ACL_GROUP_OBJ
+ * entry.
+ *
+ * Use setfacl to check whether inode strip S_ISGID works correctly under
+ * the above two situations when enabling idmapped.
+ *
+ * Test for commit
+ * 1639a49ccdce ("fs: move S_ISGID stripping into the vfs_*() helpers").
+ */
+static int setgid_create_acl_idmapped(const struct vfstest_info *info)
+{
+ int fret = -1;
+ int file1_fd = -EBADF, open_tree_fd = -EBADF;
+ struct mount_attr attr = {
+ .attr_set = MOUNT_ATTR_IDMAP,
+ };
+ pid_t pid;
+ int tmpfile_fd = -EBADF;
+ bool supported = false;
+ char path[PATH_MAX];
+ mode_t mode;
+
+ if (!caps_supported())
+ return 0;
+
+ if (fchmod(info->t_dir1_fd, S_IRUSR |
+ S_IWUSR |
+ S_IRGRP |
+ S_IWGRP |
+ S_IROTH |
+ S_IWOTH |
+ S_IXUSR |
+ S_IXGRP |
+ S_IXOTH |
+ S_ISGID), 0) {
+ log_stderr("failure: fchmod");
+ goto out;
+ }
+
+ /* Verify that the sid bits got raised. */
+ if (!is_setgid(info->t_dir1_fd, "", AT_EMPTY_PATH)) {
+ log_stderr("failure: is_setgid");
+ goto out;
+ }
+
+ /* Changing mount properties on a detached mount. */
+ attr.userns_fd = get_userns_fd(0, 10000, 10000);
+ if (attr.userns_fd < 0) {
+ log_stderr("failure: get_userns_fd");
+ goto out;
+ }
+
+ open_tree_fd = sys_open_tree(info->t_dir1_fd, "",
+ AT_EMPTY_PATH |
+ AT_NO_AUTOMOUNT |
+ AT_SYMLINK_NOFOLLOW |
+ OPEN_TREE_CLOEXEC |
+ OPEN_TREE_CLONE);
+ if (open_tree_fd < 0) {
+ log_stderr("failure: sys_open_tree");
+ goto out;
+ }
+
+ if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
+ log_stderr("failure: sys_mount_setattr");
+ goto out;
+ }
+
+ supported = openat_tmpfile_supported(open_tree_fd);
+
+ pid = fork();
+ if (pid < 0) {
+ log_stderr("failure: fork");
+ goto out;
+ }
+ if (pid == 0) {
+ umask(S_IXGRP);
+ mode = umask(S_IXGRP);
+ if (!(mode & S_IXGRP))
+ die("failure: umask");
+
+ /* The group permissions correspond to the permissions of the
+ * ACL_MASK entry. Use setfacl to set ACL mask(m) as rw, so now
+ * the group permissions is rw. Also, umask doesn't affect
+ * group permissions because umask will be ignored if having
+ * acl.
+ */
+ snprintf(t_buf, sizeof(t_buf), "setfacl -d -m u::rwx,g::rw,o::rwx,m:rw %s/%s", info->t_mountpoint, T_DIR1);
+ if (system(t_buf))
+ die("failure: system");
+
+ if (!switch_ids(10000, 11000))
+ die("failure: switch fsids");
+
+ /* create regular file via open() */
+ file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
+ if (file1_fd < 0)
+ die("failure: create");
+
+ /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
+ * bit needs to be stripped.
+ */
+ if (is_setgid(open_tree_fd, FILE1, 0))
+ die("failure: is_setgid");
+
+ if (is_ixgrp(open_tree_fd, FILE1, 0))
+ die("failure: is_ixgrp");
+
+ /* create directory */
+ if (mkdirat(open_tree_fd, DIR1, 0000))
+ die("failure: create");
+
+ if (xfs_irix_sgid_inherit_enabled(info->t_fstype)) {
+ /* We're not in_group_p(). */
+ if (is_setgid(open_tree_fd, DIR1, 0))
+ die("failure: is_setgid");
+ } else {
+ /* Directories always inherit the setgid bit. */
+ if (!is_setgid(open_tree_fd, DIR1, 0))
+ die("failure: is_setgid");
+ }
+
+ if (is_ixgrp(open_tree_fd, DIR1, 0))
+ die("failure: is_ixgrp");
+
+ /* create a special file via mknodat() vfs_create */
+ if (mknodat(open_tree_fd, FILE2, S_IFREG | S_ISGID | S_IXGRP, 0))
+ die("failure: mknodat");
+
+ if (is_setgid(open_tree_fd, FILE2, 0))
+ die("failure: is_setgid");
+
+ if (is_ixgrp(open_tree_fd, FILE2, 0))
+ die("failure: is_ixgrp");
+
+ /* create a whiteout device via mknodat() vfs_mknod */
+ if (mknodat(open_tree_fd, CHRDEV1, S_IFCHR | S_ISGID | S_IXGRP, 0))
+ die("failure: mknodat");
+
+ if (is_setgid(open_tree_fd, CHRDEV1, 0))
+ die("failure: is_setgid");
+
+ if (is_ixgrp(open_tree_fd, CHRDEV1, 0))
+ die("failure: is_ixgrp");
+
+ /*
+ * In setgid directories newly created files always inherit the
+ * gid from the parent directory. Verify that the file is owned
+ * by gid 10000, not by gid 11000.
+ */
+ if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
+ die("failure: check ownership");
+
+ /*
+ * In setgid directories newly created directories always
+ * inherit the gid from the parent directory. Verify that the
+ * directory is owned by gid 10000, not by gid 11000.
+ */
+ if (!expected_uid_gid(open_tree_fd, DIR1, 0, 10000, 10000))
+ die("failure: check ownership");
+
+ if (!expected_uid_gid(open_tree_fd, FILE2, 0, 10000, 10000))
+ die("failure: check ownership");
+
+ if (!expected_uid_gid(open_tree_fd, CHRDEV1, 0, 10000, 10000))
+ die("failure: check ownership");
+
+ if (unlinkat(open_tree_fd, FILE1, 0))
+ die("failure: delete");
+
+ if (unlinkat(open_tree_fd, DIR1, AT_REMOVEDIR))
+ die("failure: delete");
+
+ if (unlinkat(open_tree_fd, FILE2, 0))
+ die("failure: delete");
+
+ if (unlinkat(open_tree_fd, CHRDEV1, 0))
+ die("failure: delete");
+
+ /* create tmpfile via filesystem tmpfile api */
+ if (supported) {
+ tmpfile_fd = openat(open_tree_fd, ".", O_TMPFILE | O_RDWR, S_IXGRP | S_ISGID);
+ if (tmpfile_fd < 0)
+ die("failure: create");
+ /* link the temporary file into the filesystem, making it permanent */
+ snprintf(path, PATH_MAX, "/proc/self/fd/%d", tmpfile_fd);
+ if (linkat(AT_FDCWD, path, open_tree_fd, FILE3, AT_SYMLINK_FOLLOW))
+ die("failure: linkat");
+ if (close(tmpfile_fd))
+ die("failure: close");
+ if (is_setgid(open_tree_fd, FILE3, 0))
+ die("failure: is_setgid");
+ if (is_ixgrp(open_tree_fd, FILE3, 0))
+ die("failure: is_ixgrp");
+ if (!expected_uid_gid(open_tree_fd, FILE3, 0, 10000, 10000))
+ die("failure: check ownership");
+ if (unlinkat(open_tree_fd, FILE3, 0))
+ die("failure: delete");
+ }
+
+ exit(EXIT_SUCCESS);
+ }
+ if (wait_for_pid(pid))
+ goto out;
+
+ pid = fork();
+ if (pid < 0) {
+ log_stderr("failure: fork");
+ goto out;
+ }
+ if (pid == 0) {
+ umask(S_IXGRP);
+ mode = umask(S_IXGRP);
+ if (!(mode & S_IXGRP))
+ die("failure: umask");
+
+ /* The group permissions correspond to the permissions of the
+ * ACL_GROUP_OBJ entry. Don't use setfacl to set ACL_MASK, so
+ * the group permissions is equal to ACL_GROUP_OBJ(g)
+ * entry(rwx). Also, umask doesn't affect group permissions
+ * because umask will be ignored if having acl.
+ */
+ snprintf(t_buf, sizeof(t_buf), "setfacl -d -m u::rwx,g::rwx,o::rwx, %s/%s", info->t_mountpoint, T_DIR1);
+ if (system(t_buf))
+ die("failure: system");
+
+ if (!switch_ids(10000, 11000))
+ die("failure: switch fsids");
+
+ /* create regular file via open() */
+ file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
+ if (file1_fd < 0)
+ die("failure: create");
+
+ /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
+ * bit needs to be stripped.
+ */
+ if (is_setgid(open_tree_fd, FILE1, 0))
+ die("failure: is_setgid");
+
+ if (!is_ixgrp(open_tree_fd, FILE1, 0))
+ die("failure: is_ixgrp");
+
+ /* create directory */
+ if (mkdirat(open_tree_fd, DIR1, 0000))
+ die("failure: create");
+
+ if (xfs_irix_sgid_inherit_enabled(info->t_fstype)) {
+ /* We're not in_group_p(). */
+ if (is_setgid(open_tree_fd, DIR1, 0))
+ die("failure: is_setgid");
+ } else {
+ /* Directories always inherit the setgid bit. */
+ if (!is_setgid(open_tree_fd, DIR1, 0))
+ die("failure: is_setgid");
+ }
+
+ if (is_ixgrp(open_tree_fd, DIR1, 0))
+ die("failure: is_ixgrp");
+
+ /* create a special file via mknodat() vfs_create */
+ if (mknodat(open_tree_fd, FILE2, S_IFREG | S_ISGID | S_IXGRP, 0))
+ die("failure: mknodat");
+
+ if (is_setgid(open_tree_fd, FILE2, 0))
+ die("failure: is_setgid");
+
+ if (!is_ixgrp(open_tree_fd, FILE2, 0))
+ die("failure: is_ixgrp");
+
+ /* create a whiteout device via mknodat() vfs_mknod */
+ if (mknodat(open_tree_fd, CHRDEV1, S_IFCHR | S_ISGID | S_IXGRP, 0))
+ die("failure: mknodat");
+
+ if (is_setgid(open_tree_fd, CHRDEV1, 0))
+ die("failure: is_setgid");
+
+ if (!is_ixgrp(open_tree_fd, CHRDEV1, 0))
+ die("failure: is_ixgrp");
+
+ /*
+ * In setgid directories newly created files always inherit the
+ * gid from the parent directory. Verify that the file is owned
+ * by gid 10000, not by gid 11000.
+ */
+ if (!expected_uid_gid(open_tree_fd, FILE1, 0, 10000, 10000))
+ die("failure: check ownership");
+
+ /*
+ * In setgid directories newly created directories always
+ * inherit the gid from the parent directory. Verify that the
+ * directory is owned by gid 10000, not by gid 11000.
+ */
+ if (!expected_uid_gid(open_tree_fd, DIR1, 0, 10000, 10000))
+ die("failure: check ownership");
+
+ if (!expected_uid_gid(open_tree_fd, FILE2, 0, 10000, 10000))
+ die("failure: check ownership");
+
+ if (!expected_uid_gid(open_tree_fd, CHRDEV1, 0, 10000, 10000))
+ die("failure: check ownership");
+
+ if (unlinkat(open_tree_fd, FILE1, 0))
+ die("failure: delete");
+
+ if (unlinkat(open_tree_fd, DIR1, AT_REMOVEDIR))
+ die("failure: delete");
+
+ if (unlinkat(open_tree_fd, FILE2, 0))
+ die("failure: delete");
+
+ if (unlinkat(open_tree_fd, CHRDEV1, 0))
+ die("failure: delete");
+
+ /* create tmpfile via filesystem tmpfile api */
+ if (supported) {
+ tmpfile_fd = openat(open_tree_fd, ".", O_TMPFILE | O_RDWR, S_IXGRP | S_ISGID);
+ if (tmpfile_fd < 0)
+ die("failure: create");
+ /* link the temporary file into the filesystem, making it permanent */
+ snprintf(path, PATH_MAX, "/proc/self/fd/%d", tmpfile_fd);
+ if (linkat(AT_FDCWD, path, open_tree_fd, FILE3, AT_SYMLINK_FOLLOW))
+ die("failure: linkat");
+ if (close(tmpfile_fd))
+ die("failure: close");
+ if (is_setgid(open_tree_fd, FILE3, 0))
+ die("failure: is_setgid");
+ if (!is_ixgrp(open_tree_fd, FILE3, 0))
+ die("failure: is_ixgrp");
+ if (!expected_uid_gid(open_tree_fd, FILE3, 0, 10000, 10000))
+ die("failure: check ownership");
+ if (unlinkat(open_tree_fd, FILE3, 0))
+ die("failure: delete");
+ }
+
+ exit(EXIT_SUCCESS);
+ }
+ if (wait_for_pid(pid))
+ goto out;
+
+ fret = 0;
+ log_debug("Ran test");
+out:
+ safe_close(attr.userns_fd);
+ safe_close(file1_fd);
+ safe_close(open_tree_fd);
+
+ return fret;
+}
+
+/*
+ * If the parent directory has a default acl then permissions are based off
+ * of that and current_umask() is ignored. Specifically, if the ACL has an
+ * ACL_MASK entry, the group permissions correspond to the permissions of
+ * the ACL_MASK entry. Otherwise, if the ACL has no ACL_MASK entry, the
+ * group permissions correspond to the permissions of the ACL_GROUP_OBJ
+ * entry.
+ *
+ * Use setfacl to check whether inode strip S_ISGID works correctly under
+ * the above two situations when enabling userns and idmapped feature.
+ *
+ * Test for commit
+ * 1639a49ccdce ("fs: move S_ISGID stripping into the vfs_*() helpers").
+ */
+static int setgid_create_acl_idmapped_in_userns(const struct vfstest_info *info)
+{
+ int fret = -1;
+ int file1_fd = -EBADF, open_tree_fd = -EBADF;
+ struct mount_attr attr = {
+ .attr_set = MOUNT_ATTR_IDMAP,
+ };
+ pid_t pid;
+ int tmpfile_fd = -EBADF;
+ bool supported = false;
+ char path[PATH_MAX];
+ mode_t mode;
+
+ if (!caps_supported())
+ return 0;
+
+ if (fchmod(info->t_dir1_fd, S_IRUSR |
+ S_IWUSR |
+ S_IRGRP |
+ S_IWGRP |
+ S_IROTH |
+ S_IWOTH |
+ S_IXUSR |
+ S_IXGRP |
+ S_IXOTH |
+ S_ISGID), 0) {
+ log_stderr("failure: fchmod");
+ goto out;
+ }
+
+ /* Verify that the sid bits got raised. */
+ if (!is_setgid(info->t_dir1_fd, "", AT_EMPTY_PATH)) {
+ log_stderr("failure: is_setgid");
+ goto out;
+ }
+
+ /* Changing mount properties on a detached mount. */
+ attr.userns_fd = get_userns_fd(0, 10000, 10000);
+ if (attr.userns_fd < 0) {
+ log_stderr("failure: get_userns_fd");
+ goto out;
+ }
+
+ open_tree_fd = sys_open_tree(info->t_dir1_fd, "",
+ AT_EMPTY_PATH |
+ AT_NO_AUTOMOUNT |
+ AT_SYMLINK_NOFOLLOW |
+ OPEN_TREE_CLOEXEC |
+ OPEN_TREE_CLONE);
+ if (open_tree_fd < 0) {
+ log_stderr("failure: sys_open_tree");
+ goto out;
+ }
+
+ if (sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr))) {
+ log_stderr("failure: sys_mount_setattr");
+ goto out;
+ }
+
+ supported = openat_tmpfile_supported(open_tree_fd);
+
+ /*
+ * Below we verify that setgid inheritance for a newly created file or
+ * directory works correctly. As part of this we need to verify that
+ * newly created files or directories inherit their gid from their
+ * parent directory. So we change the parent directorie's gid to 1000
+ * and create a file with fs{g,u}id 0 and verify that the newly created
+ * file and directory inherit gid 1000, not 0.
+ */
+ if (fchownat(info->t_dir1_fd, "", -1, 1000, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) {
+ log_stderr("failure: fchownat");
+ goto out;
+ }
+
+ pid = fork();
+ if (pid < 0) {
+ log_stderr("failure: fork");
+ goto out;
+ }
+ if (pid == 0) {
+ umask(S_IXGRP);
+ mode = umask(S_IXGRP);
+ if (!(mode & S_IXGRP))
+ die("failure: umask");
+
+ /* The group permissions correspond to the permissions of the
+ * ACL_MASK entry. Use setfacl to set ACL mask(m) as rw, so now
+ * the group permissions is rw. Also, umask doesn't affect
+ * group permissions because umask will be ignored if having
+ * acl.
+ */
+ snprintf(t_buf, sizeof(t_buf), "setfacl -d -m u::rwx,g::rw,o::rwx,m:rw %s/%s", info->t_mountpoint, T_DIR1);
+ if (system(t_buf))
+ die("failure: system");
+
+ if (!caps_supported()) {
+ log_debug("skip: capability library not installed");
+ exit(EXIT_SUCCESS);
+ }
+
+ if (!switch_userns(attr.userns_fd, 0, 0, false))
+ die("failure: switch_userns");
+
+ if (!caps_down_fsetid())
+ die("failure: caps_down_fsetid");
+
+ /* create regular file via open() */
+ file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
+ if (file1_fd < 0)
+ die("failure: create");
+
+ /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
+ * bit needs to be stripped.
+ */
+ if (is_setgid(open_tree_fd, FILE1, 0))
+ die("failure: is_setgid");
+
+ if (is_ixgrp(open_tree_fd, FILE1, 0))
+ die("failure: is_ixgrp");
+
+ /* create directory */
+ if (mkdirat(open_tree_fd, DIR1, 0000))
+ die("failure: create");
+
+ if (xfs_irix_sgid_inherit_enabled(info->t_fstype)) {
+ /* We're not in_group_p(). */
+ if (is_setgid(open_tree_fd, DIR1, 0))
+ die("failure: is_setgid");
+ } else {
+ /* Directories always inherit the setgid bit. */
+ if (!is_setgid(open_tree_fd, DIR1, 0))
+ die("failure: is_setgid");
+ }
+
+ if (is_ixgrp(open_tree_fd, DIR1, 0))
+ die("failure: is_ixgrp");
+
+ /* create a special file via mknodat() vfs_create */
+ if (mknodat(open_tree_fd, FILE2, S_IFREG | S_ISGID | S_IXGRP, 0))
+ die("failure: mknodat");
+
+ if (is_setgid(open_tree_fd, FILE2, 0))
+ die("failure: is_setgid");
+
+ if (is_ixgrp(open_tree_fd, FILE2, 0))
+ die("failure: is_ixgrp");
+
+ /* create a whiteout device via mknodat() vfs_mknod */
+ if (mknodat(open_tree_fd, CHRDEV1, S_IFCHR | S_ISGID | S_IXGRP, 0))
+ die("failure: mknodat");
+
+ if (is_setgid(open_tree_fd, CHRDEV1, 0))
+ die("failure: is_setgid");
+
+ if (is_ixgrp(open_tree_fd, CHRDEV1, 0))
+ die("failure: is_ixgrp");
+
+ /*
+ * In setgid directories newly created files always inherit the
+ * gid from the parent directory. Verify that the file is owned
+ * by gid 1000, not by gid 0.
+ */
+ if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 1000))
+ die("failure: check ownership");
+
+ /*
+ * In setgid directories newly created directories always
+ * inherit the gid from the parent directory. Verify that the
+ * directory is owned by gid 1000, not by gid 0.
+ */
+ if (!expected_uid_gid(open_tree_fd, DIR1, 0, 0, 1000))
+ die("failure: check ownership");
+
+ if (!expected_uid_gid(open_tree_fd, FILE2, 0, 0, 1000))
+ die("failure: check ownership");
+
+ if (!expected_uid_gid(open_tree_fd, CHRDEV1, 0, 0, 1000))
+ die("failure: check ownership");
+
+ if (unlinkat(open_tree_fd, FILE1, 0))
+ die("failure: delete");
+
+ if (unlinkat(open_tree_fd, DIR1, AT_REMOVEDIR))
+ die("failure: delete");
+
+ if (unlinkat(open_tree_fd, FILE2, 0))
+ die("failure: delete");
+
+ if (unlinkat(open_tree_fd, CHRDEV1, 0))
+ die("failure: delete");
+
+ /* create tmpfile via filesystem tmpfile api */
+ if (supported) {
+ tmpfile_fd = openat(open_tree_fd, ".", O_TMPFILE | O_RDWR, S_IXGRP | S_ISGID);
+ if (tmpfile_fd < 0)
+ die("failure: create");
+ /* link the temporary file into the filesystem, making it permanent */
+ snprintf(path, PATH_MAX, "/proc/self/fd/%d", tmpfile_fd);
+ if (linkat(AT_FDCWD, path, open_tree_fd, FILE3, AT_SYMLINK_FOLLOW))
+ die("failure: linkat");
+ if (close(tmpfile_fd))
+ die("failure: close");
+ if (is_setgid(open_tree_fd, FILE3, 0))
+ die("failure: is_setgid");
+ if (is_ixgrp(open_tree_fd, FILE3, 0))
+ die("failure: is_ixgrp");
+ if (!expected_uid_gid(open_tree_fd, FILE3, 0, 0, 1000))
+ die("failure: check ownership");
+ if (unlinkat(open_tree_fd, FILE3, 0))
+ die("failure: delete");
+ }
+
+ exit(EXIT_SUCCESS);
+ }
+ if (wait_for_pid(pid))
+ goto out;
+
+ pid = fork();
+ if (pid < 0) {
+ log_stderr("failure: fork");
+ goto out;
+ }
+ if (pid == 0) {
+ umask(S_IXGRP);
+ mode = umask(S_IXGRP);
+ if (!(mode & S_IXGRP))
+ die("failure: umask");
+
+ /* The group permissions correspond to the permissions of the
+ * ACL_GROUP_OBJ entry. Don't use setfacl to set ACL_MASK, so
+ * the group permissions is equal to ACL_GROUP_OBJ(g)
+ * entry(rwx). Also, umask doesn't affect group permissions
+ * because umask will be ignored if having acl.
+ */
+ snprintf(t_buf, sizeof(t_buf), "setfacl -d -m u::rwx,g::rwx,o::rwx, %s/%s", info->t_mountpoint, T_DIR1);
+ if (system(t_buf))
+ die("failure: system");
+
+ if (!caps_supported()) {
+ log_debug("skip: capability library not installed");
+ exit(EXIT_SUCCESS);
+ }
+
+ if (!switch_userns(attr.userns_fd, 0, 0, false))
+ die("failure: switch_userns");
+
+ if (!caps_down_fsetid())
+ die("failure: caps_down_fsetid");
+
+ /* create regular file via open() */
+ file1_fd = openat(open_tree_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
+ if (file1_fd < 0)
+ die("failure: create");
+
+ /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
+ * bit needs to be stripped.
+ */
+ if (is_setgid(open_tree_fd, FILE1, 0))
+ die("failure: is_setgid");
+
+ if (!is_ixgrp(open_tree_fd, FILE1, 0))
+ die("failure: is_ixgrp");
+
+ /* create directory */
+ if (mkdirat(open_tree_fd, DIR1, 0000))
+ die("failure: create");
+
+ if (xfs_irix_sgid_inherit_enabled(info->t_fstype)) {
+ /* We're not in_group_p(). */
+ if (is_setgid(open_tree_fd, DIR1, 0))
+ die("failure: is_setgid");
+ } else {
+ /* Directories always inherit the setgid bit. */
+ if (!is_setgid(open_tree_fd, DIR1, 0))
+ die("failure: is_setgid");
+ }
+
+ if (is_ixgrp(open_tree_fd, DIR1, 0))
+ die("failure: is_ixgrp");
+
+ /* create a special file via mknodat() vfs_create */
+ if (mknodat(open_tree_fd, FILE2, S_IFREG | S_ISGID | S_IXGRP, 0))
+ die("failure: mknodat");
+
+ if (is_setgid(open_tree_fd, FILE2, 0))
+ die("failure: is_setgid");
+
+ if (!is_ixgrp(open_tree_fd, FILE2, 0))
+ die("failure: is_ixgrp");
+ /* create a whiteout device via mknodat() vfs_mknod */
+ if (mknodat(open_tree_fd, CHRDEV1, S_IFCHR | S_ISGID | S_IXGRP, 0))
+ die("failure: mknodat");
+
+ if (is_setgid(open_tree_fd, CHRDEV1, 0))
+ die("failure: is_setgid");
+
+ if (!is_ixgrp(open_tree_fd, CHRDEV1, 0))
+ die("failure: is_ixgrp");
+
+ /*
+ * In setgid directories newly created files always inherit the
+ * gid from the parent directory. Verify that the file is owned
+ * by gid 1000, not by gid 0.
+ */
+ if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 1000))
+ die("failure: check ownership");
+
+ /*
+ * In setgid directories newly created directories always
+ * inherit the gid from the parent directory. Verify that the
+ * directory is owned by gid 1000, not by gid 0.
+ */
+ if (!expected_uid_gid(open_tree_fd, DIR1, 0, 0, 1000))
+ die("failure: check ownership");
+
+ if (!expected_uid_gid(open_tree_fd, FILE2, 0, 0, 1000))
+ die("failure: check ownership");
+
+ if (!expected_uid_gid(open_tree_fd, CHRDEV1, 0, 0, 1000))
+ die("failure: check ownership");
+
+ if (unlinkat(open_tree_fd, FILE1, 0))
+ die("failure: delete");
+
+ if (unlinkat(open_tree_fd, DIR1, AT_REMOVEDIR))
+ die("failure: delete");
+
+ if (unlinkat(open_tree_fd, FILE2, 0))
+ die("failure: delete");
+
+ if (unlinkat(open_tree_fd, CHRDEV1, 0))
+ die("failure: delete");
+
+ /* create tmpfile via filesystem tmpfile api */
+ if (supported) {
+ tmpfile_fd = openat(open_tree_fd, ".", O_TMPFILE | O_RDWR, S_IXGRP | S_ISGID);
+ if (tmpfile_fd < 0)
+ die("failure: create");
+ /* link the temporary file into the filesystem, making it permanent */
+ snprintf(path, PATH_MAX, "/proc/self/fd/%d", tmpfile_fd);
+ if (linkat(AT_FDCWD, path, open_tree_fd, FILE3, AT_SYMLINK_FOLLOW))
+ die("failure: linkat");
+ if (close(tmpfile_fd))
+ die("failure: close");
+ if (is_setgid(open_tree_fd, FILE3, 0))
+ die("failure: is_setgid");
+ if (!is_ixgrp(open_tree_fd, FILE3, 0))
+ die("failure: is_ixgrp");
+ if (!expected_uid_gid(open_tree_fd, FILE3, 0, 0, 1000))
+ die("failure: check ownership");
+ if (unlinkat(open_tree_fd, FILE3, 0))
+ die("failure: delete");
+ }
+
+ exit(EXIT_SUCCESS);
+ }
+ if (wait_for_pid(pid))
+ goto out;
+
+ fret = 0;
+ log_debug("Ran test");
+out:
+ safe_close(attr.userns_fd);
+ safe_close(file1_fd);
+ safe_close(open_tree_fd);
+
+ return fret;
+}
+
static const struct test_struct t_idmapped_mounts[] = {
{ acls, true, "posix acls on regular mounts", },
{ create_in_userns, true, "create operations in user namespace", },
@@ -7745,3 +8932,23 @@ const struct test_suite s_setxattr_fix_705191b03d50 = {
.tests = t_setxattr_fix_705191b03d50,
.nr_tests = ARRAY_SIZE(t_setxattr_fix_705191b03d50),
};
+
+static const struct test_struct t_setgid_create_umask_idmapped_mounts[] = {
+ { setgid_create_umask_idmapped, T_REQUIRE_IDMAPPED_MOUNTS, "create operations by using umask in directories with setgid bit set on idmapped mount", },
+ { setgid_create_umask_idmapped_in_userns, T_REQUIRE_IDMAPPED_MOUNTS, "create operations by using umask in directories with setgid bit set on idmapped mount inside userns", },
+};
+
+const struct test_suite s_setgid_create_umask_idmapped_mounts = {
+ .tests = t_setgid_create_umask_idmapped_mounts,
+ .nr_tests = ARRAY_SIZE(t_setgid_create_umask_idmapped_mounts),
+};
+
+static const struct test_struct t_setgid_create_acl_idmapped_mounts[] = {
+ { setgid_create_acl_idmapped, T_REQUIRE_IDMAPPED_MOUNTS, "create operations by using acl in directories with setgid bit set on idmapped mount", },
+ { setgid_create_acl_idmapped_in_userns, T_REQUIRE_IDMAPPED_MOUNTS, "create operations by using acl in directories with setgid bit set on idmapped mount inside userns", },
+};
+
+const struct test_suite s_setgid_create_acl_idmapped_mounts = {
+ .tests = t_setgid_create_acl_idmapped_mounts,
+ .nr_tests = ARRAY_SIZE(t_setgid_create_acl_idmapped_mounts),
+};
diff --git a/src/vfs/idmapped-mounts.h b/src/vfs/idmapped-mounts.h
index ff21ea2c..3b0f0825 100644
--- a/src/vfs/idmapped-mounts.h
+++ b/src/vfs/idmapped-mounts.h
@@ -14,5 +14,7 @@ extern const struct test_suite s_fscaps_in_ancestor_userns;
extern const struct test_suite s_nested_userns;
extern const struct test_suite s_setattr_fix_968219708108;
extern const struct test_suite s_setxattr_fix_705191b03d50;
+extern const struct test_suite s_setgid_create_umask_idmapped_mounts;
+extern const struct test_suite s_setgid_create_acl_idmapped_mounts;
#endif /* __IDMAPPED_MOUNTS_H */
diff --git a/src/vfs/utils.c b/src/vfs/utils.c
index 1388edda..6db7a11d 100644
--- a/src/vfs/utils.c
+++ b/src/vfs/utils.c
@@ -809,6 +809,20 @@ bool is_sticky(int dfd, const char *path, int flags)
return (st.st_mode & S_ISVTX) > 0;
}
+/*is_ixgrp - check whether file or directory is S_IXGRP */
+bool is_ixgrp(int dfd, const char *path, int flags)
+{
+ int ret;
+ struct stat st;
+
+ ret = fstatat(dfd, path, &st, flags);
+ if (ret < 0)
+ return false;
+
+ errno = 0; /* Don't report misleading errno. */
+ return (st.st_mode & S_IXGRP);
+}
+
bool switch_resids(uid_t uid, gid_t gid)
{
if (setresgid(gid, gid, gid))
diff --git a/src/vfs/utils.h b/src/vfs/utils.h
index 7fb702fd..c0dbe370 100644
--- a/src/vfs/utils.h
+++ b/src/vfs/utils.h
@@ -368,6 +368,7 @@ extern bool expected_file_size(int dfd, const char *path, int flags,
extern bool is_setid(int dfd, const char *path, int flags);
extern bool is_setgid(int dfd, const char *path, int flags);
extern bool is_sticky(int dfd, const char *path, int flags);
+extern bool is_ixgrp(int dfd, const char *path, int flags);
extern bool openat_tmpfile_supported(int dirfd);
#endif /* __IDMAP_UTILS_H */
diff --git a/src/vfs/vfstest.c b/src/vfs/vfstest.c
index 29ac0bec..20ade869 100644
--- a/src/vfs/vfstest.c
+++ b/src/vfs/vfstest.c
@@ -27,6 +27,8 @@
#include "missing.h"
#include "utils.h"
+static char t_buf[PATH_MAX];
+
static void init_vfstest_info(struct vfstest_info *info)
{
info->t_overflowuid = 65534;
@@ -1733,6 +1735,515 @@ out:
return fret;
}
+/* The current_umask() is stripped from the mode directly in the vfs if the
+ * filesystem either doesn't support acls or the filesystem has been
+ * mounted without posic acl support.
+ *
+ * If the filesystem does support acls then current_umask() stripping is
+ * deferred to posix_acl_create(). So when the filesystem calls
+ * posix_acl_create() and there are no acls set or not supported then
+ * current_umask() will be stripped.
+ *
+ * Use umask(S_IXGRP) to check whether inode strip S_ISGID works correctly.
+ *
+ * test for commit ac6800e279a2 ("fs: Add missing umask strip in vfs_tmpfile")
+ * and 1639a49ccdce ("fs: move S_ISGID stripping into the vfs_*() helpers").
+ */
+static int setgid_create_umask(const struct vfstest_info *info)
+{
+ int fret = -1;
+ int file1_fd = -EBADF;
+ int tmpfile_fd = -EBADF;
+ pid_t pid;
+ bool supported = false;
+ mode_t mode;
+
+ if (!caps_supported())
+ return 0;
+
+ if (fchmod(info->t_dir1_fd, S_IRUSR |
+ S_IWUSR |
+ S_IRGRP |
+ S_IWGRP |
+ S_IROTH |
+ S_IWOTH |
+ S_IXUSR |
+ S_IXGRP |
+ S_IXOTH |
+ S_ISGID), 0) {
+ log_stderr("failure: fchmod");
+ goto out;
+ }
+
+ /* Verify that the setgid bit got raised. */
+ if (!is_setgid(info->t_dir1_fd, "", AT_EMPTY_PATH)) {
+ log_stderr("failure: is_setgid");
+ goto out;
+ }
+
+ supported = openat_tmpfile_supported(info->t_dir1_fd);
+
+ pid = fork();
+ if (pid < 0) {
+ log_stderr("failure: fork");
+ goto out;
+ }
+ if (pid == 0) {
+ umask(S_IXGRP);
+ mode = umask(S_IXGRP);
+ if (!(mode & S_IXGRP))
+ die("failure: umask");
+
+ if (!switch_ids(0, 10000))
+ die("failure: switch_ids");
+
+ if (!caps_down_fsetid())
+ die("failure: caps_down_fsetid");
+
+ /* create regular file via open() */
+ file1_fd = openat(info->t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
+ if (file1_fd < 0)
+ die("failure: create");
+
+ /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
+ * bit needs to be stripped.
+ */
+ if (is_setgid(info->t_dir1_fd, FILE1, 0))
+ die("failure: is_setgid");
+
+ if (is_ixgrp(info->t_dir1_fd, FILE1, 0))
+ die("failure: is_ixgrp");
+
+ if (mkdirat(info->t_dir1_fd, DIR1, 0000))
+ die("failure: create");
+
+ if (xfs_irix_sgid_inherit_enabled(info->t_fstype)) {
+ /* We're not in_group_p(). */
+ if (is_setgid(info->t_dir1_fd, DIR1, 0))
+ die("failure: is_setgid");
+ } else {
+ /* Directories always inherit the setgid bit. */
+ if (!is_setgid(info->t_dir1_fd, DIR1, 0))
+ die("failure: is_setgid");
+ }
+
+ if (is_ixgrp(info->t_dir1_fd, DIR1, 0))
+ die("failure: is_ixgrp");
+
+ /* create a special file via mknodat() vfs_create */
+ if (mknodat(info->t_dir1_fd, FILE2, S_IFREG | S_ISGID | S_IXGRP, 0))
+ die("failure: mknodat");
+
+ if (is_setgid(info->t_dir1_fd, FILE2, 0))
+ die("failure: is_setgid");
+
+ if (is_ixgrp(info->t_dir1_fd, FILE2, 0))
+ die("failure: is_ixgrp");
+
+ /* create a character device via mknodat() vfs_mknod */
+ if (mknodat(info->t_dir1_fd, CHRDEV1, S_IFCHR | S_ISGID | S_IXGRP, makedev(5, 1)))
+ die("failure: mknodat");
+
+ if (is_setgid(info->t_dir1_fd, CHRDEV1, 0))
+ die("failure: is_setgid");
+
+ if (is_ixgrp(info->t_dir1_fd, CHRDEV1, 0))
+ die("failure: is_ixgrp");
+
+ /*
+ * In setgid directories newly created files always inherit the
+ * gid from the parent directory. Verify that the file is owned
+ * by gid 0, not by gid 10000.
+ */
+ if (!expected_uid_gid(info->t_dir1_fd, FILE1, 0, 0, 0))
+ die("failure: check ownership");
+
+ /*
+ * In setgid directories newly created directories always
+ * inherit the gid from the parent directory. Verify that the
+ * directory is owned by gid 0, not by gid 10000.
+ */
+ if (!expected_uid_gid(info->t_dir1_fd, DIR1, 0, 0, 0))
+ die("failure: check ownership");
+
+ if (!expected_uid_gid(info->t_dir1_fd, FILE2, 0, 0, 0))
+ die("failure: check ownership");
+
+ if (!expected_uid_gid(info->t_dir1_fd, CHRDEV1, 0, 0, 0))
+ die("failure: check ownership");
+
+ if (unlinkat(info->t_dir1_fd, FILE1, 0))
+ die("failure: delete");
+
+ if (unlinkat(info->t_dir1_fd, DIR1, AT_REMOVEDIR))
+ die("failure: delete");
+
+ if (unlinkat(info->t_dir1_fd, FILE2, 0))
+ die("failure: delete");
+
+ if (unlinkat(info->t_dir1_fd, CHRDEV1, 0))
+ die("failure: delete");
+
+ /* create tmpfile via filesystem tmpfile api */
+ if (supported) {
+ tmpfile_fd = openat(info->t_dir1_fd, ".", O_TMPFILE | O_RDWR, S_IXGRP | S_ISGID);
+ if (tmpfile_fd < 0)
+ die("failure: create");
+ /* link the temporary file into the filesystem, making it permanent */
+ if (linkat(tmpfile_fd, "", info->t_dir1_fd, FILE3, AT_EMPTY_PATH))
+ die("failure: linkat");
+ if (close(tmpfile_fd))
+ die("failure: close");
+ if (is_setgid(info->t_dir1_fd, FILE3, 0))
+ die("failure: is_setgid");
+ if (is_ixgrp(info->t_dir1_fd, FILE3, 0))
+ die("failure: is_ixgrp");
+ if (unlinkat(info->t_dir1_fd, FILE3, 0))
+ die("failure: delete");
+ }
+
+ exit(EXIT_SUCCESS);
+ }
+ if (wait_for_pid(pid))
+ goto out;
+
+ fret = 0;
+ log_debug("Ran test");
+out:
+ safe_close(file1_fd);
+ return fret;
+}
+
+/*
+ * If the parent directory has a default acl then permissions are based off
+ * of that and current_umask() is ignored. Specifically, if the ACL has an
+ * ACL_MASK entry, the group permissions correspond to the permissions of
+ * the ACL_MASK entry. Otherwise, if the ACL has no ACL_MASK entry, the
+ * group permissions correspond to the permissions of the ACL_GROUP_OBJ
+ * entry.
+ *
+ * Use setfacl to check whether inode strip S_ISGID works correctly under
+ * the above two situations.
+ *
+ * Test for commit
+ * 1639a49ccdce ("fs: move S_ISGID stripping into the vfs_*() helpers").
+ */
+static int setgid_create_acl(const struct vfstest_info *info)
+{
+ int fret = -1;
+ int file1_fd = -EBADF;
+ int tmpfile_fd = -EBADF;
+ pid_t pid;
+ bool supported = false;
+ mode_t mode;
+
+ if (!caps_supported())
+ return 0;
+
+ if (fchmod(info->t_dir1_fd, S_IRUSR |
+ S_IWUSR |
+ S_IRGRP |
+ S_IWGRP |
+ S_IROTH |
+ S_IWOTH |
+ S_IXUSR |
+ S_IXGRP |
+ S_IXOTH |
+ S_ISGID), 0) {
+ log_stderr("failure: fchmod");
+ goto out;
+ }
+
+ /* Verify that the setgid bit got raised. */
+ if (!is_setgid(info->t_dir1_fd, "", AT_EMPTY_PATH)) {
+ log_stderr("failure: is_setgid");
+ goto out;
+ }
+
+ supported = openat_tmpfile_supported(info->t_dir1_fd);
+
+ pid = fork();
+ if (pid < 0) {
+ log_stderr("failure: fork");
+ goto out;
+ }
+ if (pid == 0) {
+ umask(S_IXGRP);
+ mode = umask(S_IXGRP);
+ if (!(mode & S_IXGRP))
+ die("failure: umask");
+
+ /* The group permissions correspond to the permissions of the
+ * ACL_MASK entry. Use setfacl to set ACL mask(m) as rw, so now
+ * the group permissions is rw. Also, umask doesn't affect
+ * group permissions because umask will be ignored if having
+ * acl.
+ */
+ snprintf(t_buf, sizeof(t_buf), "setfacl -d -m u::rwx,g::rw,o::rwx,m:rw %s/%s", info->t_mountpoint, T_DIR1);
+ if (system(t_buf))
+ die("failure: system");
+
+ if (!switch_ids(0, 10000))
+ die("failure: switch_ids");
+
+ if (!caps_down_fsetid())
+ die("failure: caps_down_fsetid");
+
+ /* create regular file via open() */
+ file1_fd = openat(info->t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
+ if (file1_fd < 0)
+ die("failure: create");
+
+ /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
+ * bit needs to be stripped.
+ */
+ if (is_setgid(info->t_dir1_fd, FILE1, 0))
+ die("failure: is_setgid");
+
+ if (is_ixgrp(info->t_dir1_fd, FILE1, 0))
+ die("failure: is_ixgrp");
+
+ /* create directory */
+ if (mkdirat(info->t_dir1_fd, DIR1, 0000))
+ die("failure: create");
+
+ if (xfs_irix_sgid_inherit_enabled(info->t_fstype)) {
+ /* We're not in_group_p(). */
+ if (is_setgid(info->t_dir1_fd, DIR1, 0))
+ die("failure: is_setgid");
+ } else {
+ /* Directories always inherit the setgid bit. */
+ if (!is_setgid(info->t_dir1_fd, DIR1, 0))
+ die("failure: is_setgid");
+ }
+
+ if (is_ixgrp(info->t_dir1_fd, DIR1, 0))
+ die("failure: is_ixgrp");
+
+ /* create a special file via mknodat() vfs_create */
+ if (mknodat(info->t_dir1_fd, FILE2, S_IFREG | S_ISGID | S_IXGRP, 0))
+ die("failure: mknodat");
+
+ if (is_setgid(info->t_dir1_fd, FILE2, 0))
+ die("failure: is_setgid");
+
+ if (is_ixgrp(info->t_dir1_fd, FILE2, 0))
+ die("failure: is_ixgrp");
+
+ /* create a character device via mknodat() vfs_mknod */
+ if (mknodat(info->t_dir1_fd, CHRDEV1, S_IFCHR | S_ISGID | S_IXGRP, makedev(5, 1)))
+ die("failure: mknodat");
+
+ if (is_setgid(info->t_dir1_fd, CHRDEV1, 0))
+ die("failure: is_setgid");
+
+ if (is_ixgrp(info->t_dir1_fd, CHRDEV1, 0))
+ die("failure: is_ixgrp");
+
+ /*
+ * In setgid directories newly created files always inherit the
+ * gid from the parent directory. Verify that the file is owned
+ * by gid 0, not by gid 10000.
+ */
+ if (!expected_uid_gid(info->t_dir1_fd, FILE1, 0, 0, 0))
+ die("failure: check ownership");
+
+ /*
+ * In setgid directories newly created directories always
+ * inherit the gid from the parent directory. Verify that the
+ * directory is owned by gid 0, not by gid 10000.
+ */
+ if (!expected_uid_gid(info->t_dir1_fd, DIR1, 0, 0, 0))
+ die("failure: check ownership");
+
+ if (!expected_uid_gid(info->t_dir1_fd, FILE2, 0, 0, 0))
+ die("failure: check ownership");
+
+ if (!expected_uid_gid(info->t_dir1_fd, CHRDEV1, 0, 0, 0))
+ die("failure: check ownership");
+
+ if (unlinkat(info->t_dir1_fd, FILE1, 0))
+ die("failure: delete");
+
+ if (unlinkat(info->t_dir1_fd, DIR1, AT_REMOVEDIR))
+ die("failure: delete");
+
+ if (unlinkat(info->t_dir1_fd, FILE2, 0))
+ die("failure: delete");
+
+ if (unlinkat(info->t_dir1_fd, CHRDEV1, 0))
+ die("failure: delete");
+
+ /* create tmpfile via filesystem tmpfile api */
+ if (supported) {
+ tmpfile_fd = openat(info->t_dir1_fd, ".", O_TMPFILE | O_RDWR, S_IXGRP | S_ISGID);
+ if (tmpfile_fd < 0)
+ die("failure: create");
+ /* link the temporary file into the filesystem, making it permanent */
+ if (linkat(tmpfile_fd, "", info->t_dir1_fd, FILE3, AT_EMPTY_PATH))
+ die("failure: linkat");
+ if (close(tmpfile_fd))
+ die("failure: close");
+ if (is_setgid(info->t_dir1_fd, FILE3, 0))
+ die("failure: is_setgid");
+ if (is_ixgrp(info->t_dir1_fd, FILE3, 0))
+ die("failure: is_ixgrp");
+ if (!expected_uid_gid(info->t_dir1_fd, FILE3, 0, 0, 0))
+ die("failure: check ownership");
+ if (unlinkat(info->t_dir1_fd, FILE3, 0))
+ die("failure: delete");
+ }
+
+ exit(EXIT_SUCCESS);
+ }
+ if (wait_for_pid(pid))
+ goto out;
+
+ pid = fork();
+ if (pid < 0) {
+ log_stderr("failure: fork");
+ goto out;
+ }
+ if (pid == 0) {
+ umask(S_IXGRP);
+ mode = umask(S_IXGRP);
+ if (!(mode & S_IXGRP))
+ die("failure: umask");
+
+ /* The group permissions correspond to the permissions of the
+ * ACL_GROUP_OBJ entry. Don't use setfacl to set ACL_MASK, so
+ * the group permissions is equal to ACL_GROUP_OBJ(g)
+ * entry(rwx). Also, umask doesn't affect group permissions
+ * because umask will be ignored if having acl.
+ */
+ snprintf(t_buf, sizeof(t_buf), "setfacl -d -m u::rwx,g::rwx,o::rwx, %s/%s", info->t_mountpoint, T_DIR1);
+ if (system(t_buf))
+ die("failure: system");
+
+ if (!switch_ids(0, 10000))
+ die("failure: switch_ids");
+
+ if (!caps_down_fsetid())
+ die("failure: caps_down_fsetid");
+
+ /* create regular file via open() */
+ file1_fd = openat(info->t_dir1_fd, FILE1, O_CREAT | O_EXCL | O_CLOEXEC, S_IXGRP | S_ISGID);
+ if (file1_fd < 0)
+ die("failure: create");
+
+ /* Neither in_group_p() nor capable_wrt_inode_uidgid() so setgid
+ * bit needs to be stripped.
+ */
+ if (is_setgid(info->t_dir1_fd, FILE1, 0))
+ die("failure: is_setgid");
+
+ if (!is_ixgrp(info->t_dir1_fd, FILE1, 0))
+ die("failure: is_ixgrp");
+
+ /* create directory */
+ if (mkdirat(info->t_dir1_fd, DIR1, 0000))
+ die("failure: create");
+
+ if (xfs_irix_sgid_inherit_enabled(info->t_fstype)) {
+ /* We're not in_group_p(). */
+ if (is_setgid(info->t_dir1_fd, DIR1, 0))
+ die("failure: is_setgid");
+ } else {
+ /* Directories always inherit the setgid bit. */
+ if (!is_setgid(info->t_dir1_fd, DIR1, 0))
+ die("failure: is_setgid");
+ }
+
+ if (is_ixgrp(info->t_dir1_fd, DIR1, 0))
+ die("failure: is_ixgrp");
+
+ /* create a special file via mknodat() vfs_create */
+ if (mknodat(info->t_dir1_fd, FILE2, S_IFREG | S_ISGID | S_IXGRP, 0))
+ die("failure: mknodat");
+
+ if (is_setgid(info->t_dir1_fd, FILE2, 0))
+ die("failure: is_setgid");
+
+ if (!is_ixgrp(info->t_dir1_fd, FILE2, 0))
+ die("failure: is_ixgrp");
+
+ /* create a character device via mknodat() vfs_mknod */
+ if (mknodat(info->t_dir1_fd, CHRDEV1, S_IFCHR | S_ISGID | S_IXGRP, makedev(5, 1)))
+ die("failure: mknodat");
+
+ if (is_setgid(info->t_dir1_fd, CHRDEV1, 0))
+ die("failure: is_setgid");
+
+ if (!is_ixgrp(info->t_dir1_fd, CHRDEV1, 0))
+ die("failure: is_ixgrp");
+
+ /*
+ * In setgid directories newly created files always inherit the
+ * gid from the parent directory. Verify that the file is owned
+ * by gid 0, not by gid 10000.
+ */
+ if (!expected_uid_gid(info->t_dir1_fd, FILE1, 0, 0, 0))
+ die("failure: check ownership");
+
+ /*
+ * In setgid directories newly created directories always
+ * inherit the gid from the parent directory. Verify that the
+ * directory is owned by gid 0, not by gid 10000.
+ */
+ if (!expected_uid_gid(info->t_dir1_fd, DIR1, 0, 0, 0))
+ die("failure: check ownership");
+
+ if (!expected_uid_gid(info->t_dir1_fd, FILE2, 0, 0, 0))
+ die("failure: check ownership");
+
+ if (!expected_uid_gid(info->t_dir1_fd, CHRDEV1, 0, 0, 0))
+ die("failure: check ownership");
+
+ if (unlinkat(info->t_dir1_fd, FILE1, 0))
+ die("failure: delete");
+
+ if (unlinkat(info->t_dir1_fd, DIR1, AT_REMOVEDIR))
+ die("failure: delete");
+
+ if (unlinkat(info->t_dir1_fd, FILE2, 0))
+ die("failure: delete");
+
+ if (unlinkat(info->t_dir1_fd, CHRDEV1, 0))
+ die("failure: delete");
+
+ /* create tmpfile via filesystem tmpfile api */
+ if (supported) {
+ tmpfile_fd = openat(info->t_dir1_fd, ".", O_TMPFILE | O_RDWR, S_IXGRP | S_ISGID);
+ if (tmpfile_fd < 0)
+ die("failure: create");
+ /* link the temporary file into the filesystem, making it permanent */
+ if (linkat(tmpfile_fd, "", info->t_dir1_fd, FILE3, AT_EMPTY_PATH))
+ die("failure: linkat");
+ if (close(tmpfile_fd))
+ die("failure: close");
+ if (is_setgid(info->t_dir1_fd, FILE3, 0))
+ die("failure: is_setgid");
+ if (!is_ixgrp(info->t_dir1_fd, FILE3, 0))
+ die("failure: is_ixgrp");
+ if (!expected_uid_gid(info->t_dir1_fd, FILE3, 0, 0, 0))
+ die("failure: check ownership");
+ if (unlinkat(info->t_dir1_fd, FILE3, 0))
+ die("failure: delete");
+ }
+
+ exit(EXIT_SUCCESS);
+ }
+ if (wait_for_pid(pid))
+ goto out;
+
+ fret = 0;
+ log_debug("Ran test");
+out:
+ safe_close(file1_fd);
+
+ return fret;
+}
+
static int setattr_truncate(const struct vfstest_info *info)
{
int fret = -1;
@@ -1807,6 +2318,8 @@ static void usage(void)
fprintf(stderr, "--test-btrfs Run btrfs specific idmapped mount testsuite\n");
fprintf(stderr, "--test-setattr-fix-968219708108 Run setattr regression tests\n");
fprintf(stderr, "--test-setxattr-fix-705191b03d50 Run setxattr regression tests\n");
+ fprintf(stderr, "--test-setgid-create-umask Run setgid with umask tests\n");
+ fprintf(stderr, "--test-setgid-create-acl Run setgid with acl tests\n");
_exit(EXIT_SUCCESS);
}
@@ -1825,6 +2338,8 @@ static const struct option longopts[] = {
{"test-btrfs", no_argument, 0, 'b'},
{"test-setattr-fix-968219708108", no_argument, 0, 'i'},
{"test-setxattr-fix-705191b03d50", no_argument, 0, 'j'},
+ {"test-setgid-create-umask", no_argument, 0, 'u'},
+ {"test-setgid-create-acl", no_argument, 0, 'l'},
{NULL, 0, 0, 0},
};
@@ -1850,6 +2365,24 @@ static const struct test_suite s_basic = {
.nr_tests = ARRAY_SIZE(t_basic),
};
+static const struct test_struct t_setgid_create_umask[] = {
+ { setgid_create_umask, 0, "create operations in directories with setgid bit set under umask", },
+};
+
+static const struct test_suite s_setgid_create_umask = {
+ .tests = t_setgid_create_umask,
+ .nr_tests = ARRAY_SIZE(t_setgid_create_umask),
+};
+
+static const struct test_struct t_setgid_create_acl[] = {
+ { setgid_create_acl, 0, "create operations in directories with setgid bit set under posix acl", },
+};
+
+static const struct test_suite s_setgid_create_acl = {
+ .tests = t_setgid_create_acl,
+ .nr_tests = ARRAY_SIZE(t_setgid_create_acl),
+};
+
static bool run_test(struct vfstest_info *info, const struct test_struct suite[], size_t suite_size)
{
int i;
@@ -1947,7 +2480,8 @@ int main(int argc, char *argv[])
bool idmapped_mounts_supported = false, test_btrfs = false,
test_core = false, test_fscaps_regression = false,
test_nested_userns = false, test_setattr_fix_968219708108 = false,
- test_setxattr_fix_705191b03d50 = false;
+ test_setxattr_fix_705191b03d50 = false,
+ test_setgid_create_umask = false, test_setgid_create_acl = false;
init_vfstest_info(&info);
@@ -1989,6 +2523,12 @@ int main(int argc, char *argv[])
case 'j':
test_setxattr_fix_705191b03d50 = true;
break;
+ case 'u':
+ test_setgid_create_umask = true;
+ break;
+ case 'l':
+ test_setgid_create_acl = true;
+ break;
case 'h':
/* fallthrough */
default:
@@ -2066,6 +2606,22 @@ int main(int argc, char *argv[])
!run_suite(&info, &s_setxattr_fix_705191b03d50))
goto out;
+ if (test_setgid_create_umask) {
+ if (!run_suite(&info, &s_setgid_create_umask))
+ goto out;
+
+ if (!run_suite(&info, &s_setgid_create_umask_idmapped_mounts))
+ goto out;
+ }
+
+ if (test_setgid_create_acl) {
+ if (!run_suite(&info, &s_setgid_create_acl))
+ goto out;
+
+ if (!run_suite(&info, &s_setgid_create_acl_idmapped_mounts))
+ goto out;
+ }
+
fret = EXIT_SUCCESS;
out:
diff --git a/tests/btrfs/088 b/tests/btrfs/088
index d9c5528b..59972ae7 100755
--- a/tests/btrfs/088
+++ b/tests/btrfs/088
@@ -18,27 +18,23 @@ _begin_fstest auto quick metadata
# Import common functions.
. ./common/filter
+. ./common/fail_make_request
# real QA test starts here
_supported_fs btrfs
_require_scratch
_require_fail_make_request
-SYSFS_BDEV=`_sysfs_dev $SCRATCH_DEV`
-
enable_io_failure()
{
- echo 100 > $DEBUGFS_MNT/fail_make_request/probability
- echo 1000 > $DEBUGFS_MNT/fail_make_request/times
- echo 0 > $DEBUGFS_MNT/fail_make_request/verbose
- echo 1 > $SYSFS_BDEV/make-it-fail
+ _allow_fail_make_request 100 1000 > /dev/null
+ _start_fail_scratch_dev > /dev/null
}
disable_io_failure()
{
- echo 0 > $SYSFS_BDEV/make-it-fail
- echo 0 > $DEBUGFS_MNT/fail_make_request/probability
- echo 0 > $DEBUGFS_MNT/fail_make_request/times
+ _stop_fail_scratch_dev > /dev/null
+ _disallow_fail_make_request > /dev/null
}
# We will abort a btrfs transaction later, which always produces a warning in
diff --git a/tests/btrfs/150 b/tests/btrfs/150
index c5e9c709..a7d7d9cc 100755
--- a/tests/btrfs/150
+++ b/tests/btrfs/150
@@ -15,6 +15,7 @@ _begin_fstest auto quick dangerous read_repair
# Import common functions.
. ./common/filter
+. ./common/fail_make_request
# real QA test starts here
@@ -25,22 +26,18 @@ _require_fail_make_request
_require_scratch_dev_pool 2
_scratch_dev_pool_get 2
-SYSFS_BDEV=`_sysfs_dev $SCRATCH_DEV`
enable_io_failure()
{
- echo 100 > $DEBUGFS_MNT/fail_make_request/probability
- echo 1000 > $DEBUGFS_MNT/fail_make_request/times
- echo 0 > $DEBUGFS_MNT/fail_make_request/verbose
+ _allow_fail_make_request 100 1000 > /dev/null
echo 1 > $DEBUGFS_MNT/fail_make_request/task-filter
- echo 1 > $SYSFS_BDEV/make-it-fail
+ _start_fail_scratch_dev > /dev/null
}
disable_io_failure()
{
- echo 0 > $DEBUGFS_MNT/fail_make_request/probability
- echo 0 > $DEBUGFS_MNT/fail_make_request/times
+ _disallow_fail_make_request > /dev/null
echo 0 > $DEBUGFS_MNT/fail_make_request/task-filter
- echo 0 > $SYSFS_BDEV/make-it-fail
+ _stop_fail_scratch_dev > /dev/null
}
_check_minimal_fs_size $(( 1024 * 1024 * 1024 ))
diff --git a/tests/btrfs/202 b/tests/btrfs/202
index c1fa3c3f..5f0429f1 100755
--- a/tests/btrfs/202
+++ b/tests/btrfs/202
@@ -11,6 +11,7 @@ _begin_fstest auto quick subvol snapshot
. ./common/filter
_supported_fs btrfs
+_require_scratch
_scratch_mkfs >> $seqres.full 2>&1
_scratch_mount
diff --git a/tests/btrfs/215 b/tests/btrfs/215
index 928f365c..3daa696a 100755
--- a/tests/btrfs/215
+++ b/tests/btrfs/215
@@ -24,6 +24,7 @@ get_physical()
# Modify as appropriate.
_supported_fs btrfs
+_require_scratch
# Overwriting data is forbidden on a zoned block device
_require_non_zoned_device $SCRATCH_DEV
diff --git a/tests/btrfs/253 b/tests/btrfs/253
index fbbb81fa..c746f41e 100755
--- a/tests/btrfs/253
+++ b/tests/btrfs/253
@@ -81,6 +81,8 @@ alloc_size() {
_supported_fs btrfs
_require_test
_require_scratch
+# The chunk size on zoned mode is fixed to the zone size
+_require_non_zoned_device "$SCRATCH_DEV"
# Delete log file if it exists.
rm -f "${seqres}.full"
diff --git a/tests/btrfs/257 b/tests/btrfs/257
index 5c5cdcc3..3092495f 100755
--- a/tests/btrfs/257
+++ b/tests/btrfs/257
@@ -27,6 +27,9 @@ _begin_fstest auto quick defrag prealloc
_supported_fs btrfs
_require_scratch
+# We rely on specific extent layout, don't run on compress
+_require_btrfs_no_compress
+
# Needs 4K sectorsize
_require_btrfs_support_sectorsize 4096
_require_xfs_io_command "falloc"
diff --git a/tests/btrfs/261 b/tests/btrfs/261
new file mode 100755
index 00000000..21567052
--- /dev/null
+++ b/tests/btrfs/261
@@ -0,0 +1,87 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2022 SUSE Linux Products GmbH. All Rights Reserved.
+#
+# FS QA Test 261
+#
+# Make sure btrfs raid profiles can handling one corrupted device
+# without affecting the consistency of the fs.
+#
+. ./common/preamble
+_begin_fstest auto volume raid
+
+_supported_fs btrfs
+_require_scratch_dev_pool 4
+_btrfs_get_profile_configs replace-missing
+_require_fssum
+
+prepare_fs()
+{
+ local mkfs_opts=$1
+
+ # We don't want too large fs which can take too long to populate
+ # And the extra redirection of stderr is to avoid the RAID56 warning
+ # message to polluate the golden output
+ _scratch_pool_mkfs $mkfs_opts -b 1G >> $seqres.full 2>&1
+ if [ $? -ne 0 ]; then
+ _fail "mkfs $mkfs_opts failed"
+ fi
+
+ # Disable compression, as compressed read repair is known to have problems
+ _scratch_mount -o compress=no
+
+ # Fill some part of the fs first
+ $XFS_IO_PROG -f -c "pwrite -S 0xfe 0 400M" $SCRATCH_MNT/garbage > /dev/null 2>&1
+
+ # Then use fsstress to generate some extra contents.
+ # Disable setattr related operations, as it may set NODATACOW which will
+ # not allow us to use btrfs checksum to verify the content.
+ $FSSTRESS_PROG -f setattr=0 -d $SCRATCH_MNT -w -n 3000 > /dev/null 2>&1
+ sync
+
+ # Save the fssum of this fs
+ $FSSUM_PROG -A -f -w $tmp.saved_fssum $SCRATCH_MNT
+ _scratch_unmount
+}
+
+workload()
+{
+ local mkfs_opts=$1
+ local num_devs=$2
+
+ _scratch_dev_pool_get 4
+ echo "=== Testing profile $mkfs_opts ===" >> $seqres.full
+ rm -f -- $tmp.saved_fssum
+ prepare_fs "$mkfs_opts"
+
+ # $SCRATCH_DEV is always the first device of dev pool.
+ # Corrupt the disk but keep the primary superblock.
+ $XFS_IO_PROG -c "pwrite 1M 1023M" $SCRATCH_DEV > /dev/null 2>&1
+
+ _scratch_mount
+
+ # All content should be fine
+ $FSSUM_PROG -r $tmp.saved_fssum $SCRATCH_MNT > /dev/null
+
+ # Scrub to fix the fs, this is known to report various correctable
+ # errors
+ $BTRFS_UTIL_PROG scrub start -B $SCRATCH_MNT >> $seqres.full 2>&1
+
+ # Make sure above scrub fixed the fs
+ $BTRFS_UTIL_PROG scrub start -Br $SCRATCH_MNT >> $seqres.full
+ if [ $? -ne 0 ]; then
+ echo "scrub failed to fix the fs for profile $mkfs_opts"
+ fi
+ _scratch_unmount
+ _scratch_dev_pool_put
+}
+
+for t in "${_btrfs_profile_configs[@]}"; do
+ workload "$t"
+done
+
+echo "Silence is golden"
+
+# success, all done
+status=0
+exit
diff --git a/tests/btrfs/261.out b/tests/btrfs/261.out
new file mode 100644
index 00000000..679ddc0f
--- /dev/null
+++ b/tests/btrfs/261.out
@@ -0,0 +1,2 @@
+QA output created by 261
+Silence is golden
diff --git a/tests/btrfs/268 b/tests/btrfs/268
index 5043bb02..9dc14a18 100755
--- a/tests/btrfs/268
+++ b/tests/btrfs/268
@@ -14,6 +14,7 @@ _begin_fstest auto quick read_repair
. ./common/filter
_supported_fs btrfs
+_require_scratch
_require_odirect
_require_non_zoned_device "${SCRATCH_DEV}" # no overwrites on zoned devices
_require_scratch_dev_pool 2
diff --git a/tests/btrfs/269 b/tests/btrfs/269
index 3c11da3f..ad8f7286 100755
--- a/tests/btrfs/269
+++ b/tests/btrfs/269
@@ -18,6 +18,7 @@ _begin_fstest auto quick read_repair
. ./common/filter
_supported_fs btrfs
+_require_scratch
_require_odirect
_require_non_zoned_device "${SCRATCH_DEV}" # no overwrites on zoned devices
_require_scratch_dev_pool 4
diff --git a/tests/btrfs/270 b/tests/btrfs/270
index 4229a02c..221ef7d2 100755
--- a/tests/btrfs/270
+++ b/tests/btrfs/270
@@ -7,11 +7,12 @@
# Regression test for btrfs buffered read repair of compressed data.
#
. ./common/preamble
-_begin_fstest auto quick read_repair
+_begin_fstest auto quick read_repair compress
. ./common/filter
_supported_fs btrfs
+_require_scratch
_require_btrfs_command inspect-internal dump-tree
_require_non_zoned_device "${SCRATCH_DEV}" # no overwrites on zoned devices
_require_scratch_dev_pool 2
@@ -60,7 +61,9 @@ _scratch_unmount
echo "step 2......corrupt file extent"
echo " corrupt stripe #1, devid $devid devpath $devpath physical $physical" \
>> $seqres.full
-$XFS_IO_PROG -d -c "pwrite -S 0xbb -b 64K $physical 64K" $devpath > /dev/null
+dd if=$devpath of=$TEST_DIR/$seq.dump.good skip=$physical bs=1 count=4096 \
+ 2>/dev/null
+$XFS_IO_PROG -c "pwrite -S 0xbb -b 4K $physical 4K" $devpath > /dev/null
_scratch_mount
@@ -70,8 +73,9 @@ _btrfs_buffered_read_on_mirror 1 2 "$SCRATCH_MNT/foobar" 0 128K
_scratch_unmount
echo "step 4......check if the repair worked"
-$XFS_IO_PROG -c "pread -v -b 512 $physical 512" $devpath |\
- _filter_xfs_io_offset
+dd if=$devpath of=$TEST_DIR/$seq.dump skip=$physical bs=1 count=4096 \
+ 2>/dev/null
+cmp -bl $TEST_DIR/$seq.dump.good $TEST_DIR/$seq.dump
_scratch_dev_pool_put
# success, all done
diff --git a/tests/btrfs/270.out b/tests/btrfs/270.out
index 53a80692..6d744c02 100644
--- a/tests/btrfs/270.out
+++ b/tests/btrfs/270.out
@@ -5,37 +5,3 @@ XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
step 2......corrupt file extent
step 3......repair the bad copy
step 4......check if the repair worked
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
-read 512/512 bytes
-XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
diff --git a/tests/btrfs/271 b/tests/btrfs/271
new file mode 100755
index 00000000..c7c95b3e
--- /dev/null
+++ b/tests/btrfs/271
@@ -0,0 +1,60 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2022 Christoph Hellwig.
+#
+# FS QA Test btrfs/271
+#
+# Test btrfs write error propagation and reporting on the raid1 profile.
+#
+. ./common/preamble
+_begin_fstest auto quick raid
+
+. ./common/filter
+. ./common/fail_make_request
+
+_supported_fs btrfs
+_require_scratch
+_require_fail_make_request
+_require_scratch_dev_pool 2
+_scratch_dev_pool_get 2
+
+_check_minimal_fs_size $(( 1024 * 1024 * 1024 ))
+_scratch_pool_mkfs "-d raid1 -b 1G" >> $seqres.full 2>&1
+
+_scratch_mount
+
+dev2=`echo $SCRATCH_DEV_POOL | $AWK_PROG '{print $2}'`
+
+pagesize=$(get_page_size)
+blocksize=$(_get_block_size $SCRATCH_MNT)
+sectors_per_page=$(($pagesize / $blocksize))
+
+_allow_fail_make_request
+
+echo "Step 1: writing with one failing mirror:"
+_bdev_fail_make_request $SCRATCH_DEV 1
+$XFS_IO_PROG -f -c "pwrite -W -S 0xaa 0 8K" $SCRATCH_MNT/foobar | _filter_xfs_io
+_bdev_fail_make_request $SCRATCH_DEV 0
+
+errs=$($BTRFS_UTIL_PROG device stats $SCRATCH_DEV | \
+ $AWK_PROG '/write_io_errs/ { print $2 }')
+if [ $errs -ne $((4 * $sectors_per_page)) ]; then
+ _fail "Errors: $errs expected: 4"
+fi
+
+echo "Step 2: verify that the data reads back fine:"
+$XFS_IO_PROG -c "pread -v 0 8K" $SCRATCH_MNT/foobar | _filter_xfs_io_offset
+
+echo "Step 3: writing with two failing mirrors (should fail):"
+_bdev_fail_make_request $SCRATCH_DEV 1
+_bdev_fail_make_request $dev2 1
+$XFS_IO_PROG -f -c "pwrite -W -S 0xbb 0 8K" $SCRATCH_MNT/foobar | _filter_xfs_io
+_bdev_fail_make_request $dev2 0
+_bdev_fail_make_request $SCRATCH_DEV 0
+
+_disallow_fail_make_request
+
+_scratch_dev_pool_put
+# success, all done
+status=0
+exit
diff --git a/tests/btrfs/271.out b/tests/btrfs/271.out
new file mode 100644
index 00000000..d58c92f2
--- /dev/null
+++ b/tests/btrfs/271.out
@@ -0,0 +1,523 @@
+QA output created by 271
+Allow global fail_make_request feature
+Step 1: writing with one failing mirror:
+wrote 8192/8192 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Step 2: verify that the data reads back fine:
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+XXXXXXXX: aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ................
+read 8192/8192 bytes
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Step 3: writing with two failing mirrors (should fail):
+fsync: Input/output error
+Disallow global fail_make_request feature
diff --git a/tests/btrfs/272 b/tests/btrfs/272
new file mode 100755
index 00000000..a49ec076
--- /dev/null
+++ b/tests/btrfs/272
@@ -0,0 +1,88 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2022 BingJing Chang.
+#
+# FS QA Test No. btrfs/272
+#
+# Regression test for btrfs incremental send issue where a link instruction
+# is sent against an existing path, causing btrfs receive to fail.
+#
+# This issue is fixed by the following linux kernel btrfs patch:
+#
+# commit 3aa5bd367fa5a3 ("btrfs: send: fix sending link commands for
+# existing file paths")
+#
+. ./common/preamble
+_begin_fstest auto quick send
+
+# real QA test starts here
+_supported_fs btrfs
+_fixed_by_kernel_commit 3aa5bd367fa5a3 \
+ "btrfs: send: fix sending link commands for existing file paths"
+_require_test
+_require_scratch
+_require_fssum
+
+send_files_dir=$TEST_DIR/btrfs-test-$seq
+
+rm -fr $send_files_dir
+mkdir $send_files_dir
+
+_scratch_mkfs >>$seqres.full 2>&1
+_scratch_mount
+
+# Create a file and 2000 hard links to the same inode
+_run_btrfs_util_prog subvolume create $SCRATCH_MNT/vol
+touch $SCRATCH_MNT/vol/foo
+for i in {1..2000}; do
+ link $SCRATCH_MNT/vol/foo $SCRATCH_MNT/vol/$i
+done
+
+# Create a snapshot for a full send operation
+_run_btrfs_util_prog subvolume snapshot -r $SCRATCH_MNT/vol $SCRATCH_MNT/snap1
+_run_btrfs_util_prog send -f $send_files_dir/1.snap $SCRATCH_MNT/snap1
+
+# Remove 2000 hard links and re-create the last 1000 links
+for i in {1..2000}; do
+ rm $SCRATCH_MNT/vol/$i
+done
+for i in {1001..2000}; do
+ link $SCRATCH_MNT/vol/foo $SCRATCH_MNT/vol/$i
+done
+
+# Create another snapshot for an incremental send operation
+_run_btrfs_util_prog subvolume snapshot -r $SCRATCH_MNT/vol $SCRATCH_MNT/snap2
+_run_btrfs_util_prog send -p $SCRATCH_MNT/snap1 -f $send_files_dir/2.snap \
+ $SCRATCH_MNT/snap2
+
+$FSSUM_PROG -A -f -w $send_files_dir/1.fssum $SCRATCH_MNT/snap1
+$FSSUM_PROG -A -f -w $send_files_dir/2.fssum \
+ -x $SCRATCH_MNT/snap2/snap1 $SCRATCH_MNT/snap2
+
+# Recreate the filesystem by receiving both send streams and verify we get
+# the same content that the original filesystem had.
+_scratch_unmount
+_scratch_mkfs >>$seqres.full 2>&1
+_scratch_mount
+
+# Add the first snapshot to the new filesystem by applying the first send
+# stream.
+_run_btrfs_util_prog receive -f $send_files_dir/1.snap $SCRATCH_MNT
+
+# The incremental receive operation below used to fail with the following
+# error:
+#
+# ERROR: link 1238 -> foo failed: File exists
+#
+# This is because the path "1238" was stored as an extended ref item in the
+# original snapshot but as a normal ref item in the next snapshot. The send
+# operation cannot handle the duplicated paths, which are stored in
+# different ways, well, so it decides to issue a link operation for the
+# existing path. This results in the receiver to fail with the above error.
+_run_btrfs_util_prog receive -f $send_files_dir/2.snap $SCRATCH_MNT
+
+$FSSUM_PROG -r $send_files_dir/1.fssum $SCRATCH_MNT/snap1
+$FSSUM_PROG -r $send_files_dir/2.fssum $SCRATCH_MNT/snap2
+
+status=0
+exit
diff --git a/tests/btrfs/272.out b/tests/btrfs/272.out
new file mode 100644
index 00000000..b009b87a
--- /dev/null
+++ b/tests/btrfs/272.out
@@ -0,0 +1,3 @@
+QA output created by 272
+OK
+OK
diff --git a/tests/btrfs/277 b/tests/btrfs/277
new file mode 100755
index 00000000..f5684fde
--- /dev/null
+++ b/tests/btrfs/277
@@ -0,0 +1,115 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2022 Meta, Inc. All Rights Reserved.
+#
+# FS QA Test 277
+#
+# Test sendstreams involving fs-verity enabled files.
+#
+. ./common/preamble
+_begin_fstest auto quick verity send
+
+# Override the default cleanup function.
+_cleanup()
+{
+ cd /
+ _restore_fsverity_signatures
+ rm -r -f $tmp.*
+}
+
+# Import common functions.
+. ./common/filter
+. ./common/verity
+
+# real QA test starts here
+
+# Modify as appropriate.
+_supported_fs btrfs
+_require_scratch_verity
+_require_fsverity_builtin_signatures
+_require_command "$SETCAP_PROG" setcap
+_require_command "$GETCAP_PROG" getcap
+
+subv=$SCRATCH_MNT/subv
+fsv_file=$subv/file.fsv
+keyfile=$tmp.key.pem
+certfile=$tmp.cert.pem
+certfileder=$tmp.cert.der
+sigfile=$tmp.sig
+stream=$tmp.fsv.ss
+
+_test_send_verity() {
+ local sig=$1
+ local salt=$2
+ local extra_args=""
+
+ _scratch_mkfs >> $seqres.full
+ _scratch_mount
+ echo -e "\nverity send/recv test: sig: $sig salt: $salt"
+ _disable_fsverity_signatures
+
+ echo "create subvolume"
+ $BTRFS_UTIL_PROG subvolume create $subv >> $seqres.full
+ echo "create file"
+ $XFS_IO_PROG -fc "pwrite -q -S 0x58 0 12288" $fsv_file
+ if $salt; then
+ extra_args+=" --salt=deadbeef"
+ fi
+ if $sig; then
+ echo "generate keys and cert"
+ _fsv_generate_cert $keyfile $certfile $certfileder
+ echo "clear keyring"
+ _fsv_clear_keyring
+ echo "load cert into keyring"
+ _fsv_load_cert $certfileder
+ echo "require signatures"
+ _enable_fsverity_signatures
+ echo "sign file digest"
+ _fsv_sign $fsv_file $sigfile --key=$keyfile --cert=$certfile \
+ $extra_args | _filter_scratch >> $seqres.full
+ extra_args+=" --signature=$sigfile"
+ fi
+ echo "enable verity"
+ _fsv_enable $fsv_file $extra_args
+ cat $fsv_file > $tmp.file-before
+ _fsv_measure $fsv_file > $tmp.digest-before
+
+ # ensure send plays nice with other properties that are set when
+ # finishing the file during send, like chmod and capabilities.
+ echo "modify other properties"
+ chmod a+x $fsv_file
+ $SETCAP_PROG "cap_sys_ptrace+ep cap_sys_nice+ep" $fsv_file
+ $GETCAP_PROG $fsv_file > $tmp.cap-before
+
+ echo "set subvolume read only"
+ $BTRFS_UTIL_PROG property set $subv ro true
+ echo "send subvolume"
+ $BTRFS_UTIL_PROG send $subv -f $stream -q >> $seqres.full
+
+ echo "blow away fs"
+ _scratch_unmount
+ _scratch_mkfs >> $seqres.full
+ _scratch_mount
+
+ echo "receive sendstream"
+ $BTRFS_UTIL_PROG receive $SCRATCH_MNT -f $stream -q >> $seqres.full
+
+ echo "check received subvolume..."
+ _scratch_cycle_mount
+ _fsv_measure $fsv_file > $tmp.digest-after
+ $GETCAP_PROG $fsv_file > $tmp.cap-after
+ diff $tmp.file-before $fsv_file
+ diff $tmp.digest-before $tmp.digest-after
+ diff $tmp.cap-before $tmp.cap-after
+ _scratch_unmount
+ echo OK
+}
+
+_test_send_verity false false # no sig; no salt
+_test_send_verity false true # no sig; salt
+_test_send_verity true false # sig; no salt
+_test_send_verity true true # sig; salt
+
+# success, all done
+status=0
+exit
diff --git a/tests/btrfs/277.out b/tests/btrfs/277.out
new file mode 100644
index 00000000..5f778cf4
--- /dev/null
+++ b/tests/btrfs/277.out
@@ -0,0 +1,59 @@
+QA output created by 277
+
+verity send/recv test: sig: false salt: false
+create subvolume
+create file
+enable verity
+modify other properties
+set subvolume read only
+send subvolume
+blow away fs
+receive sendstream
+check received subvolume...
+OK
+
+verity send/recv test: sig: false salt: true
+create subvolume
+create file
+enable verity
+modify other properties
+set subvolume read only
+send subvolume
+blow away fs
+receive sendstream
+check received subvolume...
+OK
+
+verity send/recv test: sig: true salt: false
+create subvolume
+create file
+generate keys and cert
+clear keyring
+load cert into keyring
+require signatures
+sign file digest
+enable verity
+modify other properties
+set subvolume read only
+send subvolume
+blow away fs
+receive sendstream
+check received subvolume...
+OK
+
+verity send/recv test: sig: true salt: true
+create subvolume
+create file
+generate keys and cert
+clear keyring
+load cert into keyring
+require signatures
+sign file digest
+enable verity
+modify other properties
+set subvolume read only
+send subvolume
+blow away fs
+receive sendstream
+check received subvolume...
+OK
diff --git a/tests/btrfs/290 b/tests/btrfs/290
new file mode 100755
index 00000000..b7254c5e
--- /dev/null
+++ b/tests/btrfs/290
@@ -0,0 +1,172 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2021 Facebook, Inc. All Rights Reserved.
+#
+# FS QA Test 290
+#
+# Test btrfs support for fsverity.
+# This test extends the generic fsverity testing by corrupting inline extents,
+# preallocated extents, holes, and the Merkle descriptor in a btrfs-aware way.
+#
+. ./common/preamble
+_begin_fstest auto quick verity
+
+# Import common functions.
+. ./common/filter
+. ./common/verity
+
+# real QA test starts here
+_supported_fs btrfs
+_require_scratch_verity
+_require_scratch_nocheck
+_require_odirect
+_require_xfs_io_command "falloc"
+_require_xfs_io_command "pread"
+_require_xfs_io_command "pwrite"
+_require_btrfs_corrupt_block
+
+get_ino() {
+ local file=$1
+ stat -c "%i" $file
+}
+
+validate() {
+ local f=$1
+ local sz=$(_get_filesize $f)
+ # buffered io
+ echo $(basename $f)
+ $XFS_IO_PROG -rc "pread -q 0 $sz" $f 2>&1 | _filter_scratch
+ # direct io
+ $XFS_IO_PROG -rdc "pread -q 0 $sz" $f 2>&1 | _filter_scratch
+}
+
+# corrupt the data portion of an inline extent
+corrupt_inline() {
+ local f=$SCRATCH_MNT/inl
+ $XFS_IO_PROG -fc "pwrite -q -S 0x58 0 42" $f
+ local ino=$(get_ino $f)
+ _fsv_enable $f
+ _scratch_unmount
+ # inline data starts at disk_bytenr
+ # overwrite the first u64 with random bogus junk
+ $BTRFS_CORRUPT_BLOCK_PROG -i $ino -x 0 -f disk_bytenr $SCRATCH_DEV > /dev/null 2>&1
+ _scratch_mount
+ validate $f
+}
+
+# preallocate a file, then corrupt it by changing it to a regular file
+corrupt_prealloc_to_reg() {
+ local f=$SCRATCH_MNT/prealloc
+ $XFS_IO_PROG -fc "falloc 0 12k" $f
+ local ino=$(get_ino $f)
+ _fsv_enable $f
+ _scratch_unmount
+ # ensure non-zero at the pre-allocated region on disk
+ # set extent type from prealloc (2) to reg (1)
+ $BTRFS_CORRUPT_BLOCK_PROG -i $ino -x 0 -f type -v 1 $SCRATCH_DEV >/dev/null 2>&1
+ _scratch_mount
+ # now that it's a regular file, reading actually looks at the previously
+ # preallocated region, so ensure that has non-zero contents.
+ head -c 5 /dev/zero | tr '\0' X | _fsv_scratch_corrupt_bytes $f 0
+ validate $f
+}
+
+# corrupt a regular file by changing the type to preallocated
+corrupt_reg_to_prealloc() {
+ local f=$SCRATCH_MNT/reg
+ $XFS_IO_PROG -fc "pwrite -q -S 0x58 0 12288" $f
+ local ino=$(get_ino $f)
+ _fsv_enable $f
+ _scratch_unmount
+ # set type from reg (1) to prealloc (2)
+ $BTRFS_CORRUPT_BLOCK_PROG -i $ino -x 0 -f type -v 2 $SCRATCH_DEV >/dev/null 2>&1
+ _scratch_mount
+ validate $f
+}
+
+# corrupt a file by punching a hole
+corrupt_punch_hole() {
+ local f=$SCRATCH_MNT/punch
+ $XFS_IO_PROG -fc "pwrite -q -S 0x58 0 12288" $f
+ local ino=$(get_ino $f)
+ # make a new extent in the middle, sync so the writes don't coalesce
+ $XFS_IO_PROG -c sync $SCRATCH_MNT
+ $XFS_IO_PROG -fc "pwrite -q -S 0x59 4096 4096" $f
+ _fsv_enable $f
+ _scratch_unmount
+ # change disk_bytenr to 0, representing a hole
+ $BTRFS_CORRUPT_BLOCK_PROG -i $ino -x 4096 -f disk_bytenr -v 0 $SCRATCH_DEV > /dev/null 2>&1
+ _scratch_mount
+ validate $f
+}
+
+# plug hole
+corrupt_plug_hole() {
+ local f=$SCRATCH_MNT/plug
+ $XFS_IO_PROG -fc "pwrite -q -S 0x58 0 12288" $f
+ local ino=$(get_ino $f)
+ $XFS_IO_PROG -fc "falloc 4k 4k" $f
+ _fsv_enable $f
+ _scratch_unmount
+ # change disk_bytenr to some value, plugging the hole
+ $BTRFS_CORRUPT_BLOCK_PROG -i $ino -x 4096 -f disk_bytenr -v 13639680 $SCRATCH_DEV > /dev/null 2>&1
+ _scratch_mount
+ validate $f
+}
+
+# corrupt the fsverity descriptor item indiscriminately (causes EINVAL)
+corrupt_verity_descriptor() {
+ local f=$SCRATCH_MNT/desc
+ $XFS_IO_PROG -fc "pwrite -q -S 0x58 0 12288" $f
+ local ino=$(get_ino $f)
+ _fsv_enable $f
+ _scratch_unmount
+ # key for the descriptor item is <inode, BTRFS_VERITY_DESC_ITEM_KEY, 1>,
+ # 88 is X. So we write 5 Xs to the start of the descriptor
+ $BTRFS_CORRUPT_BLOCK_PROG -r 5 -I $ino,36,1 -v 88 -o 0 -b 5 $SCRATCH_DEV > /dev/null 2>&1
+ _scratch_mount
+ validate $f
+}
+
+# specifically target the root hash in the descriptor (causes EIO)
+corrupt_root_hash() {
+ local f=$SCRATCH_MNT/roothash
+ $XFS_IO_PROG -fc "pwrite -q -S 0x58 0 12288" $f
+ local ino=$(get_ino $f)
+ _fsv_enable $f
+ _scratch_unmount
+ $BTRFS_CORRUPT_BLOCK_PROG -r 5 -I $ino,36,1 -v 88 -o 16 -b 1 $SCRATCH_DEV > /dev/null 2>&1
+ _scratch_mount
+ validate $f
+}
+
+# corrupt the Merkle tree data itself
+corrupt_merkle_tree() {
+ local f=$SCRATCH_MNT/merkle
+ $XFS_IO_PROG -fc "pwrite -q -S 0x58 0 12288" $f
+ local ino=$(get_ino $f)
+ _fsv_enable $f
+ _scratch_unmount
+ # key for the descriptor item is <inode, BTRFS_VERITY_MERKLE_ITEM_KEY, 0>,
+ # 88 is X. So we write 5 Xs to somewhere in the middle of the first
+ # merkle item
+ $BTRFS_CORRUPT_BLOCK_PROG -r 5 -I $ino,37,0 -v 88 -o 100 -b 5 $SCRATCH_DEV > /dev/null 2>&1
+ _scratch_mount
+ validate $f
+}
+
+# real QA test starts here
+_scratch_mkfs >/dev/null
+_scratch_mount
+
+corrupt_inline
+corrupt_prealloc_to_reg
+corrupt_reg_to_prealloc
+corrupt_punch_hole
+corrupt_plug_hole
+corrupt_verity_descriptor
+corrupt_root_hash
+corrupt_merkle_tree
+
+status=0
+exit
diff --git a/tests/btrfs/290.out b/tests/btrfs/290.out
new file mode 100644
index 00000000..056b114b
--- /dev/null
+++ b/tests/btrfs/290.out
@@ -0,0 +1,25 @@
+QA output created by 290
+inl
+pread: Input/output error
+pread: Input/output error
+prealloc
+pread: Input/output error
+pread: Input/output error
+reg
+pread: Input/output error
+pread: Input/output error
+punch
+pread: Input/output error
+pread: Input/output error
+plug
+pread: Input/output error
+pread: Input/output error
+desc
+SCRATCH_MNT/desc: Invalid argument
+SCRATCH_MNT/desc: Invalid argument
+roothash
+pread: Input/output error
+pread: Input/output error
+merkle
+pread: Input/output error
+pread: Input/output error
diff --git a/tests/btrfs/291 b/tests/btrfs/291
new file mode 100755
index 00000000..bbdd183d
--- /dev/null
+++ b/tests/btrfs/291
@@ -0,0 +1,168 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2021 Facebook, Inc. All Rights Reserved.
+#
+# FS QA Test 291
+#
+# Test btrfs consistency after each FUA while enabling verity on a file
+# This test works by following the pattern in log-writes/replay-individual.sh:
+# 1. run a workload (verity + sync) while logging to the log device
+# 2. replay an entry to the replay device
+# 3. snapshot the replay device to the snapshot device
+# 4. run destructive tests on the snapshot device (e.g. mount with orphans)
+# 5. goto 2
+#
+. ./common/preamble
+_begin_fstest auto verity recoveryloop
+
+# Override the default cleanup function.
+_cleanup()
+{
+ cd /
+ _log_writes_cleanup &> /dev/null
+ rm -f $img
+ $LVM_PROG vgremove -f -y $vgname >>$seqres.full 2>&1
+ losetup -d $loop_dev >>$seqres.full 2>&1
+}
+
+# Import common functions.
+. ./common/filter
+. ./common/attr
+. ./common/dmlogwrites
+. ./common/verity
+
+# real QA test starts here
+_supported_fs btrfs
+
+_require_scratch
+_require_test
+_require_loop
+_require_log_writes
+_require_dm_target snapshot
+_require_command $LVM_PROG lvm
+_require_scratch_verity
+_require_btrfs_command inspect-internal dump-tree
+_require_test_program "log-writes/replay-log"
+
+sync_loop() {
+ i=$1
+ [ -z "$i" ] && _fail "sync loop needs a number of iterations"
+ while [ $i -gt 0 ]
+ do
+ $XFS_IO_PROG -c sync $SCRATCH_MNT
+ let i-=1
+ done
+}
+
+dump_tree() {
+ local dev=$1
+ $BTRFS_UTIL_PROG inspect-internal dump-tree $dev
+}
+
+count_item() {
+ local dev=$1
+ local item=$2
+ dump_tree $dev | grep -c "$item"
+}
+
+count_merkle_items() {
+ local dev=$1
+ count_item $dev 'VERITY_\(DESC\|MERKLE\)_ITEM'
+}
+
+_log_writes_init $SCRATCH_DEV
+_log_writes_mkfs
+_log_writes_mount
+
+f=$SCRATCH_MNT/fsv
+MB=$((1024 * 1024))
+img=$TEST_DIR/$$.img
+$XFS_IO_PROG -fc "pwrite -q 0 $((10 * $MB))" $f
+$XFS_IO_PROG -c sync $SCRATCH_MNT
+sync_loop 10 &
+sync_proc=$!
+_fsv_enable $f
+$XFS_IO_PROG -c sync $SCRATCH_MNT
+wait $sync_proc
+
+_log_writes_unmount
+_log_writes_remove
+
+# the snapshot and the replay will each be the size of the log writes dev
+# so we create a loop device of size 2 * logwrites and then split it into
+# replay and snapshot with lvm.
+log_writes_blocks=$(blockdev --getsz $LOGWRITES_DEV)
+replay_bytes=$((512 * $log_writes_blocks))
+img_bytes=$((2 * $replay_bytes))
+
+$XFS_IO_PROG -fc "pwrite -q -S 0 $img_bytes $MB" $img >>$seqres.full 2>&1 || \
+ _fail "failed to create image for loop device"
+loop_dev=$(losetup -f --show $img)
+vgname=vg_replay
+lvname=lv_replay
+replay_dev=/dev/mapper/vg_replay-lv_replay
+snapname=lv_snap
+snap_dev=/dev/mapper/vg_replay-$snapname
+
+$LVM_PROG vgcreate -f $vgname $loop_dev >>$seqres.full 2>&1 || _fail "failed to vgcreate $vgname"
+$LVM_PROG lvcreate -L "$replay_bytes"B -n $lvname $vgname -y >>$seqres.full 2>&1 || \
+ _fail "failed to lvcreate $lvname"
+$UDEV_SETTLE_PROG >>$seqres.full 2>&1
+
+replay_log_prog=$here/src/log-writes/replay-log
+num_entries=$($replay_log_prog --log $LOGWRITES_DEV --num-entries)
+entry=$($replay_log_prog --log $LOGWRITES_DEV --replay $replay_dev --find --end-mark mkfs | cut -d@ -f1)
+prev=$(_log_writes_mark_to_entry_number mkfs)
+[ -z "$prev" ] && _fail "failed to locate entry mark 'mkfs'"
+cur=$(_log_writes_find_next_fua $prev)
+
+# state = 0: verity hasn't started
+# state = 1: verity underway
+# state = 2: verity done
+state=0
+while [ ! -z "$cur" ];
+do
+ _log_writes_replay_log_range $cur $replay_dev >> $seqres.full
+
+ $LVM_PROG lvcreate -s -L 4M -n $snapname $vgname/$lvname >>$seqres.full 2>&1 || \
+ _fail "Failed to create snapshot"
+ $UDEV_SETTLE_PROG >>$seqres.full 2>&1
+
+ orphan=$(count_item $snap_dev ORPHAN)
+ [ $state -eq 0 ] && [ $orphan -gt 0 ] && state=1
+
+ pre_mount=$(count_merkle_items $snap_dev)
+ _mount $snap_dev $SCRATCH_MNT || _fail "mount failed at entry $cur"
+ fsverity measure $SCRATCH_MNT/fsv >>$seqres.full 2>&1
+ measured=$?
+ umount $SCRATCH_MNT
+ [ $state -eq 1 ] && [ $measured -eq 0 ] && state=2
+ [ $state -eq 2 ] && ([ $measured -eq 0 ] || _fail "verity done, but measurement failed at entry $cur")
+ post_mount=$(count_merkle_items $snap_dev)
+
+ echo "entry: $cur, state: $state, orphan: $orphan, pre_mount: $pre_mount, post_mount: $post_mount" >> $seqres.full
+
+ if [ $state -eq 1 ]; then
+ [ $post_mount -eq 0 ] || \
+ _fail "mount failed to clear under-construction merkle items pre: $pre_mount, post: $post_mount at entry $cur";
+ fi
+ if [ $state -eq 2 ]; then
+ [ $pre_mount -gt 0 ] || \
+ _fail "expected to have verity items before mount at entry $cur"
+ [ $pre_mount -eq $post_mount ] || \
+ _fail "mount cleared merkle items after verity was enabled $pre_mount vs $post_mount at entry $cur";
+ fi
+
+ $LVM_PROG lvremove $vgname/$snapname -y >>$seqres.full
+
+ prev=$cur
+ cur=$(_log_writes_find_next_fua $(($cur + 1)))
+done
+
+[ $state -eq 2 ] || _fail "expected to reach verity done state"
+
+echo "Silence is golden"
+
+# success, all done
+status=0
+exit
diff --git a/tests/btrfs/291.out b/tests/btrfs/291.out
new file mode 100644
index 00000000..04605c70
--- /dev/null
+++ b/tests/btrfs/291.out
@@ -0,0 +1,2 @@
+QA output created by 291
+Silence is golden
diff --git a/tests/ceph/004 b/tests/ceph/004
index dbca713e..124ed1bc 100755
--- a/tests/ceph/004
+++ b/tests/ceph/004
@@ -9,7 +9,7 @@
#
# mkdir files limit
# truncate files/file -s 10G
-# setfattr limit -n ceph.quota.max_bytes -v 1000000
+# setfattr limit -n ceph.quota.max_bytes -v 1048576
# mv files limit/
#
# Because we're creating a new file and truncating it, we have Fx caps and thus
@@ -76,9 +76,9 @@ check_Fs_caps()
}
# set quota to 1m
-$SETFATTR_PROG -n ceph.quota.max_bytes -v 1000000 $dest
+$SETFATTR_PROG -n ceph.quota.max_bytes -v 1048576 $dest
# set quota to 20g
-$SETFATTR_PROG -n ceph.quota.max_bytes -v 20000000000 $orig2
+$SETFATTR_PROG -n ceph.quota.max_bytes -v 21474836480 $orig2
#
# The following 2 testcases shall fail with either -EXDEV or -EDQUOT
diff --git a/tests/ext4/053 b/tests/ext4/053
index 555e474e..5d2c478a 100755
--- a/tests/ext4/053
+++ b/tests/ext4/053
@@ -439,7 +439,6 @@ for fstype in ext2 ext3 ext4; do
mnt oldalloc removed
mnt orlov removed
mnt -t user_xattr
- mnt nouser_xattr
if _has_kernel_config CONFIG_EXT4_FS_POSIX_ACL; then
mnt -t acl
diff --git a/tests/ext4/057 b/tests/ext4/057
new file mode 100755
index 00000000..4006a07c
--- /dev/null
+++ b/tests/ext4/057
@@ -0,0 +1,64 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2022 Google, Inc. All Rights Reserved.
+#
+# Test the set/get UUID ioctl.
+#
+
+. ./common/preamble
+_begin_fstest auto ioctl
+
+# Override the default cleanup function.
+_cleanup()
+{
+ cd /
+ rm -r -f $tmp.*
+ kill -9 $fsstress_pid 2>/dev/null;
+ wait > /dev/null 2>&1
+}
+
+# Import common functions.
+. ./common/filter
+
+# real QA test starts here
+_supported_fs ext4
+_require_scratch
+_require_test_program uuid_ioctl
+_require_command $UUIDGEN_PROG uuidgen
+
+UUID_IOCTL=$here/src/uuid_ioctl
+
+# If the ioctl is not supported by the kernel, then skip test.
+current_uuid=$($UUID_IOCTL get $SCRATCH_MNT 2>&1)
+if [[ "$current_uuid" =~ ^Inappropriate[[:space:]]ioctl ]]; then
+ _notrun "UUID ioctls are not supported by kernel."
+fi
+
+# metadata_csum_seed must be set to decouple checksums from the uuid.
+# Otherwise, checksums need to be recomputed when the uuid changes, which
+# is not supported by the ioctl.
+_scratch_mkfs_ext4 -O metadata_csum_seed >> $seqres.full 2>&1
+_scratch_mount
+
+# Begin fsstress while modifying UUID
+fsstress_args=$(_scale_fsstress_args -d $SCRATCH_MNT -p 15 -n 999999)
+$FSSTRESS_PROG $fsstress_args > /dev/null 2>&1 &
+fsstress_pid=$!
+
+for n in $(seq 1 20); do
+ new_uuid=$($UUIDGEN_PROG)
+
+ echo "Setting UUID to ${new_uuid}" >> $seqres.full 2>&1
+ $UUID_IOCTL set $SCRATCH_MNT $new_uuid
+
+ current_uuid=$($UUID_IOCTL get $SCRATCH_MNT)
+ echo "$UUID_IOCTL get $SCARTCH_MNT: $current_uuid" >> $seqres.full 2>&1
+ if [[ "$current_uuid" != "$new_uuid" ]]; then
+ echo "Current UUID ($current_uuid) does not equal what was sent with the ioctl ($new_uuid)"
+ fi
+done
+
+# success, all done
+echo "Silence is golden"
+status=0
+exit
diff --git a/tests/ext4/057.out b/tests/ext4/057.out
new file mode 100644
index 00000000..185023c7
--- /dev/null
+++ b/tests/ext4/057.out
@@ -0,0 +1,2 @@
+QA output created by 057
+Silence is golden
diff --git a/tests/ext4/058 b/tests/ext4/058
new file mode 100755
index 00000000..4704daa7
--- /dev/null
+++ b/tests/ext4/058
@@ -0,0 +1,33 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2022 HUAWEI. All Rights Reserved.
+#
+# FS QA Test 058
+#
+# Set 256 blocks in a block group, then inject I/O pressure,
+# it will trigger off kernel BUG in ext4_mb_mark_diskspace_used
+#
+# Regression test for commit
+# a08f789d2ab5 ext4: fix bug_on ext4_mb_use_inode_pa
+#
+. ./common/preamble
+_begin_fstest auto quick
+
+# real QA test starts here
+
+_supported_fs ext4
+_fixed_by_kernel_commit a08f789d2ab5 \
+ "ext4: fix bug_on ext4_mb_use_inode_pa"
+_require_scratch
+
+# set 256 blocks in a block group
+_scratch_mkfs -g 256 >> $seqres.full 2>&1 || _fail "mkfs failed"
+_scratch_mount
+
+$FSSTRESS_PROG -d $SCRATCH_MNT/stress -n 1000 >> $seqres.full 2>&1
+
+echo "Silence is golden"
+
+# success, all done
+status=0
+exit
diff --git a/tests/ext4/058.out b/tests/ext4/058.out
new file mode 100644
index 00000000..fb5ca60b
--- /dev/null
+++ b/tests/ext4/058.out
@@ -0,0 +1,2 @@
+QA output created by 058
+Silence is golden
diff --git a/tests/ext4/059 b/tests/ext4/059
new file mode 100755
index 00000000..4230bde9
--- /dev/null
+++ b/tests/ext4/059
@@ -0,0 +1,41 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2022 HUAWEI. All Rights Reserved.
+#
+# FS QA Test No. 059
+#
+# A regression test for b55c3cd102a6 ("ext4: add reserved GDT blocks check").
+# Make sure there's not kernel crash, if resize an ext4 which resize_inode
+# feature is disabled but has reserved GDT blocks.
+#
+. ./common/preamble
+_begin_fstest auto resize quick
+
+# real QA test starts here
+_supported_fs ext4
+_fixed_by_kernel_commit b55c3cd102a6 \
+ "ext4: add reserved GDT blocks check"
+
+_require_command "$RESIZE2FS_PROG" resize2fs
+_require_command "$DEBUGFS_PROG" debugfs
+_require_scratch_size_nocheck $((1024 * 1024))
+
+# Initalize a 512M ext4 fs with resize_inode feature disabled
+dev_size=$((512 * 1024 * 1024))
+MKFS_OPTIONS="-O ^resize_inode $MKFS_OPTIONS" _scratch_mkfs_sized $dev_size \
+ >>$seqres.full 2>&1 || _fail "mkfs failed"
+
+# Force some reserved GDT blocks to trigger the bug
+$DEBUGFS_PROG -w -R "set_super_value s_reserved_gdt_blocks 100" $SCRATCH_DEV \
+ >>$seqres.full 2>&1
+$DEBUGFS_PROG -R "show_super_stats -h" $SCRATCH_DEV 2>/dev/null | \
+ grep "Reserved GDT blocks"
+
+_scratch_mount
+
+# Expect no crash from this resize operation
+$RESIZE2FS_PROG $SCRATCH_DEV 1G >> $seqres.full 2>&1
+
+# success, all done
+status=0
+exit
diff --git a/tests/ext4/059.out b/tests/ext4/059.out
new file mode 100644
index 00000000..d199db3e
--- /dev/null
+++ b/tests/ext4/059.out
@@ -0,0 +1,2 @@
+QA output created by 059
+Reserved GDT blocks: 100
diff --git a/tests/generic/017 b/tests/generic/017
index 4b6acace..12c486d1 100755
--- a/tests/generic/017
+++ b/tests/generic/017
@@ -29,7 +29,7 @@ _scratch_mount
testfile=$SCRATCH_MNT/$seq.$$
BLOCKS=10240
-BSIZE=`_get_block_size $SCRATCH_MNT`
+BSIZE=`_get_file_block_size $SCRATCH_MNT`
length=$(($BLOCKS * $BSIZE))
diff --git a/tests/generic/019 b/tests/generic/019
index 45c91624..b68dd90c 100755
--- a/tests/generic/019
+++ b/tests/generic/019
@@ -14,47 +14,17 @@ fio_config=$tmp.fio
# Import common functions.
. ./common/filter
+. ./common/fail_make_request
_supported_fs generic
_require_scratch
_require_block_device $SCRATCH_DEV
_require_fail_make_request
-SYSFS_BDEV=`_sysfs_dev $SCRATCH_DEV`
-
-allow_fail_make_request()
-{
- echo "Allow global fail_make_request feature"
- echo 100 > $DEBUGFS_MNT/fail_make_request/probability
- echo 9999999 > $DEBUGFS_MNT/fail_make_request/times
- echo 0 > /sys/kernel/debug/fail_make_request/verbose
-}
-
-disallow_fail_make_request()
-{
- echo "Disallow global fail_make_request feature"
- echo 0 > $DEBUGFS_MNT/fail_make_request/probability
- echo 0 > $DEBUGFS_MNT/fail_make_request/times
-}
-
-start_fail_scratch_dev()
-{
- echo "Force SCRATCH_DEV device failure"
- echo " echo 1 > $SYSFS_BDEV/make-it-fail" >> $seqres.full
- echo 1 > $SYSFS_BDEV/make-it-fail
-}
-
-stop_fail_scratch_dev()
-{
- echo "Make SCRATCH_DEV device operable again"
- echo " echo 0 > $SYSFS_BDEV/make-it-fail" >> $seqres.full
- echo 0 > $SYSFS_BDEV/make-it-fail
-}
-
# Override the default cleanup function.
_cleanup()
{
kill $fs_pid $fio_pid &> /dev/null
- disallow_fail_make_request
+ _disallow_fail_make_request
cd /
rm -r -f $tmp.*
}
@@ -129,7 +99,7 @@ _workout()
# Let's it work for awhile, and force device failure
sleep $RUN_TIME
- start_fail_scratch_dev
+ _start_fail_scratch_dev
# After device turns in to failed state filesystem may yet not know about
# that so buffered write(2) may succeed, but any integrity operations
# such as (sync, fsync, fdatasync, direct-io) should fail.
@@ -147,7 +117,7 @@ _workout()
run_check _scratch_unmount
# Once filesystem was umounted no one is able to write to block device
# It is now safe to bring device back to normal state
- stop_fail_scratch_dev
+ _stop_fail_scratch_dev
# In order to check that filesystem is able to recover journal on mount(2)
# perform mount/umount, after that all errors should be fixed
@@ -159,7 +129,7 @@ _workout()
_scratch_mkfs >> $seqres.full 2>&1 || _fail "mkfs failed"
_scratch_mount
-allow_fail_make_request
+_allow_fail_make_request
_workout
status=$?
exit
diff --git a/tests/generic/031 b/tests/generic/031
index cbb2fc34..0d2e8268 100755
--- a/tests/generic/031
+++ b/tests/generic/031
@@ -25,6 +25,7 @@ testfile=$SCRATCH_MNT/testfile
_scratch_mkfs > /dev/null 2>&1
_scratch_mount
+_require_congruent_file_oplen $SCRATCH_MNT 4096
$XFS_IO_PROG -f \
-c "pwrite 185332 55756" \
diff --git a/tests/generic/042 b/tests/generic/042
index 413e29d8..b9274112 100755
--- a/tests/generic/042
+++ b/tests/generic/042
@@ -43,7 +43,7 @@ _crashtest()
_mkfs_dev $img >> $seqres.full 2>&1
mkdir -p $mnt
- _mount -t $FSTYP $img $mnt
+ _mount -o loop -t $FSTYP $img $mnt
echo $cmd
@@ -53,7 +53,7 @@ _crashtest()
$here/src/godown -f $mnt
$UMOUNT_PROG $mnt
- _mount -t $FSTYP $img $mnt
+ _mount -o loop -t $FSTYP $img $mnt
# We should /never/ see 0xCD in the file, because we wrote that pattern
# to the filesystem image to expose stale data.
diff --git a/tests/generic/064 b/tests/generic/064
index b7d7fa4b..3b32fa1b 100755
--- a/tests/generic/064
+++ b/tests/generic/064
@@ -29,7 +29,7 @@ _scratch_mount
src=$SCRATCH_MNT/testfile
dest=$SCRATCH_MNT/testfile.dest
BLOCKS=100
-BSIZE=`_get_block_size $SCRATCH_MNT`
+BSIZE=`_get_file_block_size $SCRATCH_MNT`
length=$(($BLOCKS * $BSIZE))
# Write file
diff --git a/tests/generic/081 b/tests/generic/081
index 22ac94de..7146781a 100755
--- a/tests/generic/081
+++ b/tests/generic/081
@@ -80,7 +80,7 @@ _mkfs_dev /dev/mapper/$vgname-$lvname
$LVM_PROG lvcreate -s -L 4M -n $snapname $vgname/$lvname >>$seqres.full 2>&1 || \
_fail "Failed to create snapshot"
-_mount /dev/mapper/$vgname-$snapname $mnt
+_mount -t $FSTYP /dev/mapper/$vgname-$snapname $mnt
# write 5M data to the snapshot
$XFS_IO_PROG -fc "pwrite 0 5m" -c fsync $mnt/testfile >>$seqres.full 2>&1
diff --git a/tests/generic/108 b/tests/generic/108
index efe66ba5..89d9c994 100755
--- a/tests/generic/108
+++ b/tests/generic/108
@@ -64,7 +64,7 @@ $UDEV_SETTLE_PROG >>$seqres.full 2>&1
# above vgcreate/lvcreate operations
_mkfs_dev /dev/mapper/$vgname-$lvname
-_mount /dev/mapper/$vgname-$lvname $SCRATCH_MNT
+_mount -t $FSTYP /dev/mapper/$vgname-$lvname $SCRATCH_MNT
# create a test file with contiguous blocks which will span across the 2 disks
$XFS_IO_PROG -f -c "pwrite 0 16M" -c fsync $SCRATCH_MNT/testfile >>$seqres.full
diff --git a/tests/generic/116 b/tests/generic/116
index b8816e31..88b64f4c 100755
--- a/tests/generic/116
+++ b/tests/generic/116
@@ -31,6 +31,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $TEST_DIR $blksz
_pwrite_byte 0x61 $((blksz * 2)) $((blksz * 6)) $testdir/file1 >> $seqres.full
_pwrite_byte 0x61 $((blksz * 2)) $((blksz * 6)) $testdir/file2 >> $seqres.full
_test_cycle_mount
diff --git a/tests/generic/118 b/tests/generic/118
index 4fa2e1e3..35d933ff 100755
--- a/tests/generic/118
+++ b/tests/generic/118
@@ -32,6 +32,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $TEST_DIR $blksz
_pwrite_byte 0x61 $((blksz * 2)) $((blksz * 6)) $testdir/file1 >> $seqres.full
_pwrite_byte 0x62 $((blksz * 2)) $((blksz * 6)) $testdir/file2 >> $seqres.full
_test_cycle_mount
diff --git a/tests/generic/119 b/tests/generic/119
index fd4c3661..481d12d2 100755
--- a/tests/generic/119
+++ b/tests/generic/119
@@ -34,6 +34,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $TEST_DIR $blksz
_pwrite_byte 0x61 0 $((blksz * 8)) $testdir/file1 >> $seqres.full
_pwrite_byte 0x62 0 $((blksz * 8)) $testdir/file2 >> $seqres.full
_pwrite_byte 0x63 0 $((blksz * 8)) $testdir/file3 >> $seqres.full
diff --git a/tests/generic/121 b/tests/generic/121
index 43137469..e9038240 100755
--- a/tests/generic/121
+++ b/tests/generic/121
@@ -31,6 +31,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $TEST_DIR $blksz
_pwrite_byte 0x61 $((blksz * 2)) $((blksz * 6)) $testdir/file1 >> $seqres.full
_pwrite_byte 0x61 $((blksz * 2)) $((blksz * 6)) $testdir/file2 >> $seqres.full
_test_cycle_mount
diff --git a/tests/generic/122 b/tests/generic/122
index fbf3f1f2..89309c22 100755
--- a/tests/generic/122
+++ b/tests/generic/122
@@ -31,6 +31,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $TEST_DIR $blksz
_pwrite_byte 0x61 $((blksz * 2)) $((blksz * 6)) $testdir/file1 >> $seqres.full
_pwrite_byte 0x62 $((blksz * 2)) $((blksz * 6)) $testdir/file2 >> $seqres.full
_test_cycle_mount
diff --git a/tests/generic/134 b/tests/generic/134
index ab76f046..58b81872 100755
--- a/tests/generic/134
+++ b/tests/generic/134
@@ -35,6 +35,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $TEST_DIR $blksz
_pwrite_byte 0x61 0 $((blksz + 37)) $testdir/file1 >> $seqres.full
_pwrite_byte 0x61 0 $((blksz + 37)) $testdir/file2 >> $seqres.full
_pwrite_byte 0x62 0 $((blksz + 37)) $testdir/file3 >> $seqres.full
diff --git a/tests/generic/136 b/tests/generic/136
index 98ebb0da..c5b80074 100755
--- a/tests/generic/136
+++ b/tests/generic/136
@@ -35,6 +35,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $TEST_DIR $blksz
_pwrite_byte 0x61 0 $((blksz + 37)) $testdir/file1 >> $seqres.full
_pwrite_byte 0x61 0 $((blksz + 37)) $testdir/file2 >> $seqres.full
_pwrite_byte 0x62 0 $((blksz + 37)) $testdir/file3 >> $seqres.full
diff --git a/tests/generic/137 b/tests/generic/137
index fb0071b1..8ee705fd 100755
--- a/tests/generic/137
+++ b/tests/generic/137
@@ -37,6 +37,7 @@ mkdir $testdir
echo "Create the original file blocks"
blksz=65536
+_require_congruent_file_oplen $TEST_DIR $blksz
_pwrite_byte 0x61 0 $blksz $testdir/file1 >> $seqres.full
_pwrite_byte 0x62 $blksz $((blksz * 2)) $testdir/file1 >> $seqres.full
diff --git a/tests/generic/144 b/tests/generic/144
index 842d51f3..21c49577 100755
--- a/tests/generic/144
+++ b/tests/generic/144
@@ -35,6 +35,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $TEST_DIR $blksz
_pwrite_byte 0x61 0 $((blksz * 5 + 37)) $testdir/file1 >> $seqres.full
_reflink_range $testdir/file1 $blksz $testdir/file2 $blksz \
diff --git a/tests/generic/149 b/tests/generic/149
index 5343a139..108f1368 100755
--- a/tests/generic/149
+++ b/tests/generic/149
@@ -35,6 +35,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $TEST_DIR $blksz
_pwrite_byte 0x61 0 $blksz $testdir/file1 >> $seqres.full
_pwrite_byte 0x62 $blksz $blksz $testdir/file1 >> $seqres.full
_pwrite_byte 0x63 $((blksz * 2)) $blksz $testdir/file1 >> $seqres.full
diff --git a/tests/generic/153 b/tests/generic/153
index 40877266..342959fd 100755
--- a/tests/generic/153
+++ b/tests/generic/153
@@ -37,7 +37,7 @@ rm -rf $testdir
mkdir $testdir
echo "Create the original file blocks"
-blksz="$(_get_block_size $testdir)"
+blksz="$(_get_file_block_size $testdir)"
blks=2000
margin='15%'
sz=$((blksz * blks))
diff --git a/tests/generic/158 b/tests/generic/158
index 649c75db..b9955265 100755
--- a/tests/generic/158
+++ b/tests/generic/158
@@ -38,7 +38,7 @@ testdir2=$SCRATCH_MNT/test-$seq
mkdir $testdir2
echo "Create the original files"
-blksz="$(_get_block_size $testdir1)"
+blksz="$(_get_file_block_size $testdir1)"
blks=1000
margin='7%'
sz=$((blksz * blks))
diff --git a/tests/generic/162 b/tests/generic/162
index 0dc17f75..7b625e86 100755
--- a/tests/generic/162
+++ b/tests/generic/162
@@ -38,6 +38,7 @@ mkdir $testdir
loops=512
nr_loops=$((loops - 1))
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
echo "Initialize files"
echo >> $seqres.full
diff --git a/tests/generic/163 b/tests/generic/163
index 4a6c341e..91da69d3 100755
--- a/tests/generic/163
+++ b/tests/generic/163
@@ -38,6 +38,7 @@ mkdir $testdir
loops=512
nr_loops=$((loops - 1))
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
echo "Initialize files"
echo >> $seqres.full
diff --git a/tests/generic/164 b/tests/generic/164
index 8e0b630b..56c05e37 100755
--- a/tests/generic/164
+++ b/tests/generic/164
@@ -40,6 +40,7 @@ mkdir $testdir
loops=512
nr_loops=$((loops - 1))
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
echo "Initialize files"
echo >> $seqres.full
diff --git a/tests/generic/165 b/tests/generic/165
index d9e6a6e9..bc24bcab 100755
--- a/tests/generic/165
+++ b/tests/generic/165
@@ -41,6 +41,7 @@ mkdir $testdir
loops=512
nr_loops=$((loops - 1))
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
echo "Initialize files"
echo >> $seqres.full
diff --git a/tests/generic/168 b/tests/generic/168
index 575ff08c..bdc8f7a0 100755
--- a/tests/generic/168
+++ b/tests/generic/168
@@ -39,6 +39,7 @@ mkdir $testdir
loops=1024
nr_loops=$((loops - 1))
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
echo "Initialize files"
echo >> $seqres.full
diff --git a/tests/generic/170 b/tests/generic/170
index d323ab8f..593cfbb7 100755
--- a/tests/generic/170
+++ b/tests/generic/170
@@ -40,6 +40,7 @@ mkdir $testdir
loops=1024
nr_loops=$((loops - 1))
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
echo "Initialize files"
echo >> $seqres.full
diff --git a/tests/generic/181 b/tests/generic/181
index 2b4617be..5e5883df 100755
--- a/tests/generic/181
+++ b/tests/generic/181
@@ -33,6 +33,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $TEST_DIR $blksz
_pwrite_byte 0x61 0 $((blksz * 256)) $testdir/file1 >> $seqres.full
_pwrite_byte 0x62 0 $((blksz * 256)) $testdir/file2 >> $seqres.full
_pwrite_byte 0x62 0 $((blksz * 2)) $testdir/file2.chk >> $seqres.full
diff --git a/tests/generic/183 b/tests/generic/183
index 77bfcfcb..c8614514 100755
--- a/tests/generic/183
+++ b/tests/generic/183
@@ -39,6 +39,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
_pwrite_byte 0x61 0 $filesize $testdir/file1 >> $seqres.full
diff --git a/tests/generic/185 b/tests/generic/185
index 09469924..75dbc6b8 100755
--- a/tests/generic/185
+++ b/tests/generic/185
@@ -38,6 +38,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
_pwrite_byte 0x61 0 $filesize $testdir/file1 >> $seqres.full
diff --git a/tests/generic/186 b/tests/generic/186
index 37d88440..c5a1e13a 100755
--- a/tests/generic/186
+++ b/tests/generic/186
@@ -81,6 +81,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=1024
filesize=$((blksz * nr))
_pwrite_byte 0x61 0 $filesize $testdir/file1 >> $seqres.full
diff --git a/tests/generic/187 b/tests/generic/187
index 152e3cc2..be7a635a 100755
--- a/tests/generic/187
+++ b/tests/generic/187
@@ -82,6 +82,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=1024
filesize=$((blksz * nr))
_pwrite_byte 0x61 0 $filesize $testdir/file1 >> $seqres.full
diff --git a/tests/generic/188 b/tests/generic/188
index eab77b39..52a7f2d2 100755
--- a/tests/generic/188
+++ b/tests/generic/188
@@ -39,6 +39,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
_weave_reflink_unwritten $blksz $nr $testdir/file1 $testdir/file3 >> $seqres.full
diff --git a/tests/generic/189 b/tests/generic/189
index 75cca42a..63faac6e 100755
--- a/tests/generic/189
+++ b/tests/generic/189
@@ -38,6 +38,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
_weave_reflink_unwritten $blksz $nr $testdir/file1 $testdir/file3 >> $seqres.full
diff --git a/tests/generic/190 b/tests/generic/190
index 9e220740..b336f12b 100755
--- a/tests/generic/190
+++ b/tests/generic/190
@@ -39,6 +39,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
_weave_reflink_holes $blksz $nr $testdir/file1 $testdir/file3 >> $seqres.full
diff --git a/tests/generic/191 b/tests/generic/191
index 78b9a3f0..1b12d9ac 100755
--- a/tests/generic/191
+++ b/tests/generic/191
@@ -38,6 +38,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
_weave_reflink_holes $blksz $nr $testdir/file1 $testdir/file3 >> $seqres.full
diff --git a/tests/generic/194 b/tests/generic/194
index ff76438d..aa80560b 100755
--- a/tests/generic/194
+++ b/tests/generic/194
@@ -41,6 +41,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
_weave_reflink_holes $blksz $nr $testdir/file1 $testdir/file3 >> $seqres.full
diff --git a/tests/generic/195 b/tests/generic/195
index e087b99c..4f21201e 100755
--- a/tests/generic/195
+++ b/tests/generic/195
@@ -40,6 +40,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
_weave_reflink_holes $blksz $nr $testdir/file1 $testdir/file3 >> $seqres.full
diff --git a/tests/generic/196 b/tests/generic/196
index e2ae0410..366d0cad 100755
--- a/tests/generic/196
+++ b/tests/generic/196
@@ -39,6 +39,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
_weave_reflink_regular $blksz $nr $testdir/file1 $testdir/file3 >> $seqres.full
diff --git a/tests/generic/197 b/tests/generic/197
index c5f80207..ac314186 100755
--- a/tests/generic/197
+++ b/tests/generic/197
@@ -38,6 +38,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
_weave_reflink_regular $blksz $nr $testdir/file1 $testdir/file3 >> $seqres.full
diff --git a/tests/generic/199 b/tests/generic/199
index 2a8cafcc..2246fdd1 100755
--- a/tests/generic/199
+++ b/tests/generic/199
@@ -46,6 +46,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
_weave_reflink_rainbow $blksz $nr $testdir/file1 $testdir/file3 >> $seqres.full
diff --git a/tests/generic/200 b/tests/generic/200
index a1a78ef4..eeefeb50 100755
--- a/tests/generic/200
+++ b/tests/generic/200
@@ -46,6 +46,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
_weave_reflink_rainbow $blksz $nr $testdir/file1 $testdir/file3 >> $seqres.full
diff --git a/tests/generic/201 b/tests/generic/201
index 2598b44a..0a5a1d4a 100755
--- a/tests/generic/201
+++ b/tests/generic/201
@@ -34,6 +34,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
_pwrite_byte 0x61 0 $filesize $testdir/file1 >> $seqres.full
diff --git a/tests/generic/275 b/tests/generic/275
index 6189edca..f3b05409 100755
--- a/tests/generic/275
+++ b/tests/generic/275
@@ -37,6 +37,15 @@ _scratch_unmount 2>/dev/null
_scratch_mkfs_sized $((2 * 1024 * 1024 * 1024)) >>$seqres.full 2>&1
_scratch_mount
+# Certain filesystems such as XFS require sufficient free blocks to handle the
+# worst-case directory expansion as a result of a creat() call. If the fs
+# block size is very large (e.g. 64k) then the number of blocks required for
+# the creat() call can represent far more free space than the 256K left at the
+# end of this test. Therefore, create the file that the last dd will write to
+# now when we know there's enough free blocks.
+later_file=$SCRATCH_MNT/later
+touch $later_file
+
# this file will get removed to create 256k of free space after ENOSPC
# conditions are created.
dd if=/dev/zero of=$SCRATCH_MNT/tmp1 bs=256K count=1 >>$seqres.full 2>&1
@@ -63,12 +72,12 @@ _freespace=`$DF_PROG -k $SCRATCH_MNT | tail -n 1 | awk '{print $5}'`
# Try to write more than available space in chunks that will allow at least one
# full write to succeed.
-dd if=/dev/zero of=$SCRATCH_MNT/tmp1 bs=128k count=8 >>$seqres.full 2>&1
+dd if=/dev/zero of=$later_file bs=128k count=8 >>$seqres.full 2>&1
echo "Bytes written until ENOSPC:" >>$seqres.full
-du $SCRATCH_MNT/tmp1 >>$seqres.full
+du $later_file >>$seqres.full
# And at least some of it should succeed.
-_filesize=`_get_filesize $SCRATCH_MNT/tmp1`
+_filesize=`_get_filesize $later_file`
[ $_filesize -lt $((128 * 1024)) ] && \
_fail "Partial write until enospc failed; wrote $_filesize bytes."
diff --git a/tests/generic/284 b/tests/generic/284
index 729da77a..f9eefff3 100755
--- a/tests/generic/284
+++ b/tests/generic/284
@@ -32,6 +32,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
_sweave_reflink_regular $blksz $nr $testdir/file1 $testdir/file3 >> $seqres.full
diff --git a/tests/generic/287 b/tests/generic/287
index 76ea26ba..61301368 100755
--- a/tests/generic/287
+++ b/tests/generic/287
@@ -33,6 +33,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
_sweave_reflink_regular $blksz $nr $testdir/file1 $testdir/file3 >> $seqres.full
diff --git a/tests/generic/289 b/tests/generic/289
index ed4f3268..52d03c35 100755
--- a/tests/generic/289
+++ b/tests/generic/289
@@ -34,6 +34,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
_sweave_reflink_unwritten $blksz $nr $testdir/file1 $testdir/file3 >> $seqres.full
diff --git a/tests/generic/290 b/tests/generic/290
index 534fb24f..5352b9ba 100755
--- a/tests/generic/290
+++ b/tests/generic/290
@@ -35,6 +35,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
_sweave_reflink_unwritten $blksz $nr $testdir/file1 $testdir/file3 >> $seqres.full
diff --git a/tests/generic/291 b/tests/generic/291
index 50119c03..1c589cf6 100755
--- a/tests/generic/291
+++ b/tests/generic/291
@@ -34,6 +34,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
_sweave_reflink_holes $blksz $nr $testdir/file1 $testdir/file3 >> $seqres.full
diff --git a/tests/generic/292 b/tests/generic/292
index 24cdab53..725fe057 100755
--- a/tests/generic/292
+++ b/tests/generic/292
@@ -35,6 +35,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
_sweave_reflink_holes $blksz $nr $testdir/file1 $testdir/file3 >> $seqres.full
diff --git a/tests/generic/293 b/tests/generic/293
index 0f1d8416..05997501 100755
--- a/tests/generic/293
+++ b/tests/generic/293
@@ -36,6 +36,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
_sweave_reflink_holes $blksz $nr $testdir/file1 $testdir/file3 >> $seqres.full
diff --git a/tests/generic/295 b/tests/generic/295
index f66c1805..9ccf823f 100755
--- a/tests/generic/295
+++ b/tests/generic/295
@@ -37,6 +37,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
_sweave_reflink_holes $blksz $nr $testdir/file1 $testdir/file3 >> $seqres.full
diff --git a/tests/generic/352 b/tests/generic/352
index c8cca6ba..034b54c3 100755
--- a/tests/generic/352
+++ b/tests/generic/352
@@ -30,6 +30,7 @@ _scratch_mkfs > /dev/null 2>&1
_scratch_mount
blocksize=$((128 * 1024))
+_require_congruent_file_oplen $SCRATCH_MNT $blocksize
file="$SCRATCH_MNT/tmp"
# Golden output is for $LOAD_FACTOR == 1 case
diff --git a/tests/generic/358 b/tests/generic/358
index 8c73ba36..91fe5e2b 100755
--- a/tests/generic/358
+++ b/tests/generic/358
@@ -39,6 +39,7 @@ mkdir $testdir
blocks=64
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
echo "Initialize file"
_pwrite_byte 0x61 0 $((blocks * blksz)) $testdir/file >> $seqres.full
diff --git a/tests/generic/359 b/tests/generic/359
index 25692058..8ef4f846 100755
--- a/tests/generic/359
+++ b/tests/generic/359
@@ -41,6 +41,7 @@ mkdir $testdir
blocks=64
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=4
halfway=$((blocks / 2 * blksz))
quarter=$((blocks / 4 * blksz))
diff --git a/tests/generic/372 b/tests/generic/372
index 1ce1236f..8b5552ea 100755
--- a/tests/generic/372
+++ b/tests/generic/372
@@ -40,6 +40,7 @@ mkdir $testdir
blocks=5
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
sz=$((blocks * blksz))
echo "Create the original files"
diff --git a/tests/generic/404 b/tests/generic/404
index 939692eb..30fce85d 100755
--- a/tests/generic/404
+++ b/tests/generic/404
@@ -69,7 +69,7 @@ _require_test
_require_xfs_io_command "falloc"
_require_xfs_io_command "finsert"
-blksize=`_get_block_size $TEST_DIR`
+blksize=`_get_file_block_size $TEST_DIR`
# Generate a block with a repeating number represented as 4 bytes decimal.
# The test generates unique pattern for each block in order to observe a
diff --git a/tests/generic/414 b/tests/generic/414
index 01b9da8e..6416216d 100755
--- a/tests/generic/414
+++ b/tests/generic/414
@@ -39,6 +39,7 @@ mkdir $testdir
blocks=32
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
sz=$((blocks * blksz))
echo "Create the original files"
diff --git a/tests/generic/441 b/tests/generic/441
index 0ec751da..85f29a3a 100755
--- a/tests/generic/441
+++ b/tests/generic/441
@@ -52,7 +52,7 @@ unset SCRATCH_RTDEV
echo "Format and mount"
_scratch_mkfs > $seqres.full 2>&1
-_dmerror_init
+_dmerror_init no_log
_dmerror_mount
_require_fs_space $SCRATCH_MNT 65536
diff --git a/tests/generic/455 b/tests/generic/455
index d0a3fafb..db964c9f 100755
--- a/tests/generic/455
+++ b/tests/generic/455
@@ -25,6 +25,7 @@ _cleanup()
_supported_fs generic
_require_test
_require_scratch_nocheck
+_require_no_logdev
_require_log_writes
_require_dm_target thin-pool
diff --git a/tests/generic/457 b/tests/generic/457
index 7b33a3e7..e2ffb4f2 100755
--- a/tests/generic/457
+++ b/tests/generic/457
@@ -26,6 +26,7 @@ _cleanup()
_supported_fs generic
_require_test
_require_scratch_reflink
+_require_no_logdev
_require_cp_reflink
_require_log_writes
_require_dm_target thin-pool
diff --git a/tests/generic/470 b/tests/generic/470
index dd8525d7..f3407511 100755
--- a/tests/generic/470
+++ b/tests/generic/470
@@ -27,6 +27,7 @@ _cleanup()
# real QA test starts here
_supported_fs generic
_require_scratch_nocheck
+_require_no_logdev
_require_log_writes_dax_mountopt "dax"
_require_dm_target thin-pool
_require_xfs_io_command "mmap" "-S"
diff --git a/tests/generic/482 b/tests/generic/482
index 6bc94a8c..fd5855f5 100755
--- a/tests/generic/482
+++ b/tests/generic/482
@@ -49,6 +49,7 @@ _cleanup()
# Modify as appropriate.
_supported_fs generic
+_require_no_logdev
_require_command "$KILLALL_PROG" killall
# Use thin device as replay device, which requires $SCRATCH_DEV
_require_scratch_nocheck
diff --git a/tests/generic/483 b/tests/generic/483
index e7120362..39129542 100755
--- a/tests/generic/483
+++ b/tests/generic/483
@@ -35,6 +35,10 @@ _require_metadata_journaling $SCRATCH_DEV
_init_flakey
_mount_flakey
+# The fiemap results in the golden output requires file allocations to align to
+# 256K boundaries.
+_require_congruent_file_oplen $SCRATCH_MNT 262144
+
# Create our test files.
$XFS_IO_PROG -f -c "pwrite -S 0xea 0 256K" $SCRATCH_MNT/foo >/dev/null
diff --git a/tests/generic/484 b/tests/generic/484
index 40e83cbd..4f413352 100755
--- a/tests/generic/484
+++ b/tests/generic/484
@@ -15,7 +15,7 @@
# buffer: record blockdev write errors in super_block that it backs
. ./common/preamble
-_begin_fstest auto quick
+_begin_fstest auto quick eio
# Override the default cleanup function.
_cleanup()
diff --git a/tests/generic/487 b/tests/generic/487
index fda8828d..3c9b2233 100755
--- a/tests/generic/487
+++ b/tests/generic/487
@@ -45,7 +45,7 @@ unset SCRATCH_RTDEV
echo "Format and mount"
_scratch_mkfs > $seqres.full 2>&1
-_dmerror_init
+_dmerror_init no_log
_dmerror_mount
datalen=65536
diff --git a/tests/generic/495 b/tests/generic/495
index 608f1715..5e03dfee 100755
--- a/tests/generic/495
+++ b/tests/generic/495
@@ -21,6 +21,10 @@ _require_sparse_files
_scratch_mkfs >> $seqres.full 2>&1
_scratch_mount
+blksize=$(_get_file_block_size $SCRATCH_MNT)
+test $blksize -eq $(getconf PAGE_SIZE) || \
+ _notrun "swap file allocation unit size must match page size"
+
# We can't use _format_swapfile because we're using our custom mkswap and
# swapon.
touch "$SCRATCH_MNT/swap"
diff --git a/tests/generic/501 b/tests/generic/501
index 8c3f627b..cb158ba5 100755
--- a/tests/generic/501
+++ b/tests/generic/501
@@ -34,6 +34,7 @@ _scratch_mkfs >>$seqres.full 2>&1
_require_metadata_journaling $SCRATCH_DEV
_init_flakey
_mount_flakey
+_require_congruent_file_oplen $SCRATCH_MNT 2097152
# Use file sizes and offsets/lengths for the clone operation that are multiples
# of 64Kb, so that the test works on machine with any page size.
diff --git a/tests/generic/503 b/tests/generic/503
index a6971e63..ff3390bf 100755
--- a/tests/generic/503
+++ b/tests/generic/503
@@ -38,6 +38,10 @@ _scratch_mkfs >> $seqres.full 2>&1
export MOUNT_OPTIONS=""
_scratch_mount >> $seqres.full 2>&1
+blksize=$(_get_file_block_size $SCRATCH_MNT)
+test $blksize -eq $(getconf PAGE_SIZE) || \
+ _notrun "file block size must match page size"
+
# real QA test starts here
$here/src/t_mmap_collision $TEST_DIR/testfile $SCRATCH_MNT/testfile
diff --git a/tests/generic/515 b/tests/generic/515
index 2f3bd400..758bd639 100755
--- a/tests/generic/515
+++ b/tests/generic/515
@@ -30,6 +30,7 @@ _scratch_mount
DONOR1=$SCRATCH_MNT/a
TARGET=$SCRATCH_MNT/b
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
$XFS_IO_PROG -f -c "pwrite -S 0x72 0 $blksz" $DONOR1 >> $seqres.full
diff --git a/tests/generic/516 b/tests/generic/516
index 790ad532..e846ee24 100755
--- a/tests/generic/516
+++ b/tests/generic/516
@@ -31,6 +31,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $TEST_DIR $blksz
_pwrite_byte 0x61 $((blksz * 2)) $((blksz * 6)) $testdir/file1 >> $seqres.full
_pwrite_byte 0x61 $((blksz * 2)) $((blksz * 6)) $testdir/file2 >> $seqres.full
_pwrite_byte 0x62 $(((blksz * 6) - 33)) 1 $testdir/file2 >> $seqres.full
diff --git a/tests/generic/540 b/tests/generic/540
index 38e00f97..da36939a 100755
--- a/tests/generic/540
+++ b/tests/generic/540
@@ -38,6 +38,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
_pwrite_byte 0x64 0 $((blksz * nr)) $testdir/file2 >> $seqres.full
diff --git a/tests/generic/541 b/tests/generic/541
index 89b2adad..a0f6cae3 100755
--- a/tests/generic/541
+++ b/tests/generic/541
@@ -38,6 +38,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
_pwrite_byte 0x64 0 $((blksz * nr)) $testdir/file2 >> $seqres.full
diff --git a/tests/generic/542 b/tests/generic/542
index e7682f59..530fb8e0 100755
--- a/tests/generic/542
+++ b/tests/generic/542
@@ -38,6 +38,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
_pwrite_byte 0x64 0 $((blksz * nr)) $testdir/file2 >> $seqres.full
diff --git a/tests/generic/543 b/tests/generic/543
index 624cfc41..1dad37fb 100755
--- a/tests/generic/543
+++ b/tests/generic/543
@@ -38,6 +38,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
_pwrite_byte 0x64 0 $((blksz * nr)) $testdir/file2 >> $seqres.full
diff --git a/tests/generic/544 b/tests/generic/544
index 4dbaea4d..a4f654af 100755
--- a/tests/generic/544
+++ b/tests/generic/544
@@ -27,6 +27,7 @@ _scratch_mkfs > $seqres.full 2>&1
_scratch_mount >> $seqres.full 2>&1
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=2
filesize=$((blksz * nr))
testdir=$SCRATCH_MNT/test-$seq
diff --git a/tests/generic/546 b/tests/generic/546
index 7723b980..9dc507be 100755
--- a/tests/generic/546
+++ b/tests/generic/546
@@ -39,6 +39,7 @@ _scratch_mkfs_sized $((512 * 1024 * 1024)) >> $seqres.full 2>&1
_require_metadata_journaling $SCRATCH_DEV
_init_flakey
_mount_flakey
+_require_congruent_file_oplen $SCRATCH_MNT 4096
# Create preallocated extent where we can write into
$XFS_IO_PROG -f -c 'falloc 8k 64m' "$SCRATCH_MNT/foobar" >> $seqres.full
diff --git a/tests/generic/574 b/tests/generic/574
index 882baa21..fd4488c9 100755
--- a/tests/generic/574
+++ b/tests/generic/574
@@ -28,6 +28,7 @@ _cleanup()
_supported_fs generic
_require_scratch_verity
_disable_fsverity_signatures
+_require_fsverity_corruption
_scratch_mkfs_verity &>> $seqres.full
_scratch_mount
@@ -125,6 +126,39 @@ corruption_test()
fi
}
+# Reading the last block of the file with mmap is tricky, so we need to be
+# a bit careful. Some filesystems read the last block in full, while others
+# return zeros in the last block past EOF, regardless of the contents on
+# disk. In the former, corruption should be detected and result in SIGBUS,
+# while in the latter we would expect zeros past EOF, but no error.
+corrupt_eof_block_test() {
+ local file_len=$1
+ local zap_len=$2
+ local page_aligned_eof=$(round_up_to_page_boundary $file_len)
+ _fsv_scratch_begin_subtest "Corruption test: EOF block"
+ setup_zeroed_file $file_len false
+ cmp $fsv_file $fsv_orig_file
+ echo "Corrupting bytes..."
+ head -c $zap_len /dev/zero | tr '\0' X \
+ | _fsv_scratch_corrupt_bytes $fsv_file $file_len
+
+ echo "Reading eof block via mmap into a temporary file..."
+ bash -c "trap '' SIGBUS; $XFS_IO_PROG -r $fsv_file \
+ -c 'mmap -r 0 $page_aligned_eof' \
+ -c 'mread -v $file_len $zap_len'" \
+ |& filter_sigbus >$tmp.eof_block_read 2>&1
+
+ head -c $file_len /dev/zero > $tmp.zero_cmp_file
+ $XFS_IO_PROG -r $tmp.zero_cmp_file \
+ -c "mmap -r 0 $page_aligned_eof" \
+ -c "mread -v $file_len $zap_len" >$tmp.eof_zero_read
+
+ echo "Checking for SIGBUS or zeros..."
+ grep -q -e '^Bus error$' $tmp.eof_block_read \
+ || diff $tmp.eof_block_read $tmp.eof_zero_read \
+ && echo "OK"
+}
+
# Note: these tests just overwrite some bytes without checking their original
# values. Therefore, make sure to overwrite at least 5 or so bytes, to make it
# nearly guaranteed that there will be a change -- even when the test file is
@@ -135,9 +169,7 @@ corruption_test 131072 4091 5
corruption_test 131072 65536 65536
corruption_test 131072 131067 5
-# Non-zeroed bytes in the final partial block beyond EOF should cause reads to
-# fail too. Such bytes would be visible via mmap().
-corruption_test 130999 131000 72
+corrupt_eof_block_test 130999 72
# Merkle tree corruption.
corruption_test 200000 100 10 true
diff --git a/tests/generic/574.out b/tests/generic/574.out
index 3c08d3e8..d40d1263 100644
--- a/tests/generic/574.out
+++ b/tests/generic/574.out
@@ -56,17 +56,12 @@ Bus error
Validating corruption (reading just corrupted part via mmap)...
Bus error
-# Corruption test: file_len=130999 zap_offset=131000 zap_len=72
+# Corruption test: EOF block
f5cca0d7fbb8b02bc6118a9954d5d306 SCRATCH_MNT/file.fsv
Corrupting bytes...
-Validating corruption (reading full file)...
-md5sum: SCRATCH_MNT/file.fsv: Input/output error
-Validating corruption (direct I/O)...
-dd: error reading 'SCRATCH_MNT/file.fsv': Input/output error
-Validating corruption (reading full file via mmap)...
-Bus error
-Validating corruption (reading just corrupted part via mmap)...
-Bus error
+Reading eof block via mmap into a temporary file...
+Checking for SIGBUS or zeros...
+OK
# Corruption test: file_len=200000 zap_offset=100 (in Merkle tree) zap_len=10
4a1e4325031b13f933ac4f1db9ecb63f SCRATCH_MNT/file.fsv
diff --git a/tests/generic/576 b/tests/generic/576
index 3ef04953..c8862de2 100755
--- a/tests/generic/576
+++ b/tests/generic/576
@@ -28,6 +28,7 @@ _supported_fs generic
_require_scratch_verity
_require_scratch_encryption
_require_command "$KEYCTL_PROG" keyctl
+_require_fsverity_corruption
_disable_fsverity_signatures
_scratch_mkfs_encrypted_verity &>> $seqres.full
diff --git a/tests/generic/578 b/tests/generic/578
index 01929a28..d04cacb4 100755
--- a/tests/generic/578
+++ b/tests/generic/578
@@ -41,6 +41,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $TEST_DIR $blksz
filesz=$((blksz * 4))
_pwrite_byte 0x61 0 $filesz $testdir/file1 >> $seqres.full
_cp_reflink $testdir/file1 $testdir/file2 >> $seqres.full
diff --git a/tests/generic/588 b/tests/generic/588
index 563ff65e..a915a73e 100755
--- a/tests/generic/588
+++ b/tests/generic/588
@@ -35,6 +35,8 @@ _require_metadata_journaling $SCRATCH_DEV
_init_flakey
_mount_flakey
+_require_congruent_file_oplen $SCRATCH_MNT 65536
+
# Create our test file with two 256Kb extents, one at file offset 0 and the
# other at file offset 256Kb.
$XFS_IO_PROG -f -c "pwrite -S 0xa3 0 256K" \
diff --git a/tests/generic/628 b/tests/generic/628
index 7dc6dfcd..380a7f0b 100755
--- a/tests/generic/628
+++ b/tests/generic/628
@@ -11,7 +11,7 @@
# 5ffce3cc22a0 ("xfs: force the log after remapping a synchronous-writes file")
. ./common/preamble
-_begin_fstest auto quick rw clone
+_begin_fstest auto quick rw clone eio
# Override the default cleanup function.
_cleanup()
diff --git a/tests/generic/629 b/tests/generic/629
index f501555e..dbd7ada8 100755
--- a/tests/generic/629
+++ b/tests/generic/629
@@ -11,7 +11,7 @@
# 5ffce3cc22a0 ("xfs: force the log after remapping a synchronous-writes file")
. ./common/preamble
-_begin_fstest auto quick rw copy_range
+_begin_fstest auto quick rw copy_range eio
# Override the default cleanup function.
_cleanup()
diff --git a/tests/generic/648 b/tests/generic/648
index d7bf5697..4892c4c0 100755
--- a/tests/generic/648
+++ b/tests/generic/648
@@ -137,7 +137,7 @@ done
# Make sure the fs image file is ok
if [ -f "$loopimg" ]; then
- if _mount $loopimg $loopmnt -o loop; then
+ if _mount -o loop -t $FSTYP $loopimg $loopmnt -o loop; then
$UMOUNT_PROG $loopmnt &> /dev/null
else
_metadump_dev $DMERROR_DEV $seqres.scratch.final.md
diff --git a/tests/generic/673 b/tests/generic/673
index e40e672a..4d8dc07e 100755
--- a/tests/generic/673
+++ b/tests/generic/673
@@ -22,6 +22,7 @@ _require_scratch_reflink
_scratch_mkfs >> $seqres.full
_scratch_mount
+_require_congruent_file_oplen $SCRATCH_MNT 1048576
chmod a+rw $SCRATCH_MNT/
setup_testfile() {
diff --git a/tests/generic/674 b/tests/generic/674
index 920ed5f2..a3130249 100755
--- a/tests/generic/674
+++ b/tests/generic/674
@@ -23,6 +23,7 @@ _require_xfs_io_command dedupe
_scratch_mkfs >> $seqres.full
_scratch_mount
+_require_congruent_file_oplen $SCRATCH_MNT 1048576
chmod a+rw $SCRATCH_MNT/
setup_testfile() {
diff --git a/tests/generic/675 b/tests/generic/675
index 23b7e545..189251f2 100755
--- a/tests/generic/675
+++ b/tests/generic/675
@@ -24,6 +24,7 @@ _require_scratch_reflink
_scratch_mkfs >> $seqres.full
_scratch_mount
+_require_congruent_file_oplen $SCRATCH_MNT 1048576
chmod a+rw $SCRATCH_MNT/
setup_testfile() {
diff --git a/tests/generic/677 b/tests/generic/677
index 39af90a9..4dbfed7d 100755
--- a/tests/generic/677
+++ b/tests/generic/677
@@ -38,6 +38,10 @@ _require_metadata_journaling $SCRATCH_DEV
_init_flakey
_mount_flakey
+# The fiemap results in the golden output requires file allocations to align to
+# 1MB boundaries.
+_require_congruent_file_oplen $SCRATCH_MNT 1048576
+
# Create our test file with many extents.
# On btrfs this results in having multiple leaves of metadata full of file
# extent items, a condition necessary to trigger the original bug.
diff --git a/tests/generic/683 b/tests/generic/683
index 746ead86..4c93346d 100755
--- a/tests/generic/683
+++ b/tests/generic/683
@@ -28,6 +28,7 @@ _require_user
_require_test
verb=falloc
_require_xfs_io_command $verb
+_require_congruent_file_oplen $TEST_DIR 65536
junk_dir=$TEST_DIR/$seq
junk_file=$junk_dir/a
diff --git a/tests/generic/684 b/tests/generic/684
index 4bebeff0..03481e69 100755
--- a/tests/generic/684
+++ b/tests/generic/684
@@ -28,6 +28,7 @@ _require_user
_require_test
verb=fpunch
_require_xfs_io_command $verb
+_require_congruent_file_oplen $TEST_DIR 65536
junk_dir=$TEST_DIR/$seq
junk_file=$junk_dir/a
diff --git a/tests/generic/685 b/tests/generic/685
index 03447e00..6a108842 100755
--- a/tests/generic/685
+++ b/tests/generic/685
@@ -28,6 +28,7 @@ _require_user
_require_test
verb=fzero
_require_xfs_io_command $verb
+_require_congruent_file_oplen $TEST_DIR 65536
junk_dir=$TEST_DIR/$seq
junk_file=$junk_dir/a
diff --git a/tests/generic/686 b/tests/generic/686
index eae3cbda..4279f76b 100755
--- a/tests/generic/686
+++ b/tests/generic/686
@@ -28,6 +28,7 @@ _require_user
_require_test
verb=finsert
_require_xfs_io_command $verb
+_require_congruent_file_oplen $TEST_DIR 65536
junk_dir=$TEST_DIR/$seq
junk_file=$junk_dir/a
diff --git a/tests/generic/687 b/tests/generic/687
index 0bd421e5..78cb6202 100755
--- a/tests/generic/687
+++ b/tests/generic/687
@@ -28,6 +28,7 @@ _require_user
_require_test
verb=fcollapse
_require_xfs_io_command $verb
+_require_congruent_file_oplen $TEST_DIR 65536
junk_dir=$TEST_DIR/$seq
junk_file=$junk_dir/a
diff --git a/tests/generic/688 b/tests/generic/688
index 905c46ac..426286b6 100755
--- a/tests/generic/688
+++ b/tests/generic/688
@@ -28,6 +28,7 @@ _require_command "$GETCAP_PROG" getcap
_require_command "$SETCAP_PROG" setcap
_require_xfs_io_command falloc
_require_test
+_require_congruent_file_oplen $TEST_DIR 65536
junk_dir=$TEST_DIR/$seq
junk_file=$junk_dir/a
diff --git a/tests/generic/692 b/tests/generic/692
new file mode 100644
index 00000000..0bb1fd33
--- /dev/null
+++ b/tests/generic/692
@@ -0,0 +1,64 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2022 Meta, Inc. All Rights Reserved.
+#
+# FS QA Test 692
+#
+# fs-verity requires the filesystem to decide how it stores the Merkle tree,
+# which can be quite large.
+# It is convenient to treat the Merkle tree as past EOF, and ext4, f2fs, and
+# btrfs do so in at least some fashion. This leads to an edge case where a
+# large file can be under the file system file size limit, but trigger EFBIG
+# on enabling fs-verity. Test enabling verity on some large files to exercise
+# EFBIG logic for filesystems with fs-verity specific limits.
+#
+. ./common/preamble
+_begin_fstest auto quick verity
+
+
+# Import common functions.
+. ./common/filter
+. ./common/verity
+
+# real QA test starts here
+_supported_fs generic
+_require_test
+_require_math
+_require_scratch_verity
+_require_fsverity_max_file_size_limit
+
+_scratch_mkfs_verity &>> $seqres.full
+_scratch_mount
+
+fsv_file=$SCRATCH_MNT/file.fsv
+
+max_sz=$(_get_max_file_size)
+_fsv_scratch_begin_subtest "way too big: fail on first merkle block"
+truncate -s $max_sz $fsv_file
+_fsv_enable $fsv_file |& _filter_scratch
+
+# The goal of this second test is to make a big enough file that we trip the
+# EFBIG codepath, but not so big that we hit it immediately when writing the
+# first Merkle leaf.
+#
+# The Merkle tree is stored with the leaf node level (L0) last, but it is
+# written first. To get an interesting overflow, we need the maximum file size
+# (MAX) to be in the middle of L0 -- ideally near the beginning of L0 so that we
+# don't have to write many blocks before getting an error.
+#
+# With SHA-256 and 4K blocks, there are 128 hashes per block. Thus, ignoring
+# padding, L0 is 1/128 of the file size while the other levels in total are
+# 1/128**2 + 1/128**3 + 1/128**4 + ... = 1/16256 of the file size. So still
+# ignoring padding, for L0 start exactly at MAX, the file size must be s such
+# that s + s/16256 = MAX, i.e. s = MAX * (16256/16257). Then to get a file size
+# where MAX occurs *near* the start of L0 rather than *at* the start, we can
+# just subtract an overestimate of the padding: 64K after the file contents,
+# then 4K per level, where the consideration of 8 levels is sufficient.
+sz=$(echo "scale=20; $max_sz * (16256/16257) - 65536 - 4096*8" | $BC -q | cut -d. -f1)
+_fsv_scratch_begin_subtest "still too big: fail on first invalid merkle block"
+truncate -s $sz $fsv_file
+_fsv_enable $fsv_file |& _filter_scratch
+
+# success, all done
+status=0
+exit
diff --git a/tests/generic/692.out b/tests/generic/692.out
new file mode 100644
index 00000000..05996713
--- /dev/null
+++ b/tests/generic/692.out
@@ -0,0 +1,7 @@
+QA output created by 692
+
+# way too big: fail on first merkle block
+ERROR: FS_IOC_ENABLE_VERITY failed on 'SCRATCH_MNT/file.fsv': File too large
+
+# still too big: fail on first invalid merkle block
+ERROR: FS_IOC_ENABLE_VERITY failed on 'SCRATCH_MNT/file.fsv': File too large
diff --git a/tests/generic/693 b/tests/generic/693
new file mode 100755
index 00000000..1596865e
--- /dev/null
+++ b/tests/generic/693
@@ -0,0 +1,31 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright 2022 Google LLC
+#
+# FS QA Test No. 693
+#
+# Verify ciphertext for v2 encryption policies that use AES-256-XTS to encrypt
+# file contents and AES-256-HCTR2 to encrypt file names.
+#
+# HCTR2 was introduced in kernel commit 6b2a51ff03bf ("fscrypt: Add HCTR2
+# support for filename encryption")
+#
+. ./common/preamble
+_begin_fstest auto quick encrypt
+
+# Import common functions.
+. ./common/filter
+. ./common/encrypt
+
+# real QA test starts here
+_supported_fs generic
+
+_verify_ciphertext_for_encryption_policy AES-256-XTS AES-256-HCTR2 v2
+_verify_ciphertext_for_encryption_policy AES-256-XTS AES-256-HCTR2 \
+ v2 iv_ino_lblk_32
+_verify_ciphertext_for_encryption_policy AES-256-XTS AES-256-HCTR2 \
+ v2 iv_ino_lblk_64
+
+# success, all done
+status=0
+exit
diff --git a/tests/generic/693.out b/tests/generic/693.out
new file mode 100644
index 00000000..91ff7f20
--- /dev/null
+++ b/tests/generic/693.out
@@ -0,0 +1,16 @@
+QA output created by 693
+
+Verifying ciphertext with parameters:
+ contents_encryption_mode: AES-256-XTS
+ filenames_encryption_mode: AES-256-HCTR2
+ options: v2
+
+Verifying ciphertext with parameters:
+ contents_encryption_mode: AES-256-XTS
+ filenames_encryption_mode: AES-256-HCTR2
+ options: v2 iv_ino_lblk_32
+
+Verifying ciphertext with parameters:
+ contents_encryption_mode: AES-256-XTS
+ filenames_encryption_mode: AES-256-HCTR2
+ options: v2 iv_ino_lblk_64
diff --git a/tests/generic/694 b/tests/generic/694
new file mode 100755
index 00000000..dfd988df
--- /dev/null
+++ b/tests/generic/694
@@ -0,0 +1,47 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2022 Red Hat Inc. All Rights Reserved.
+#
+# FS QA Test 694
+#
+# Verify that i_blocks for files larger than 4 GiB have correct
+# values.
+#
+# This test verifies the problem fixed in kernel with commit
+# 0c336d6e33f4 exfat: fix incorrect loading of i_blocks for large files
+#
+. ./common/preamble
+_begin_fstest auto
+
+# Override the default cleanup function.
+_cleanup()
+{
+ cd /
+ rm -r -f $tmp.* $junk_dir
+}
+
+_supported_fs generic
+_require_test
+_require_fs_space $TEST_DIR $((4 * 1024 * 1024)) #kB
+
+echo "Silence is golden"
+
+junk_dir=$TEST_DIR/$seq
+junk_file=$junk_dir/junk
+mkdir -p $junk_dir
+
+$XFS_IO_PROG -f -c "pwrite -W 0 4G" $junk_file > /dev/null
+
+iblocks=`stat -c '%b' $junk_file`
+
+_test_cycle_mount
+
+iblocks_after_remount=`stat -c '%b' $junk_file`
+
+if [ "$iblocks" != "$iblocks_after_remount" ]; then
+ echo "Number of blocks needs to be same: $iblocks, $iblocks_after_remount"
+fi
+
+status=0
+
+exit
diff --git a/tests/generic/694.out b/tests/generic/694.out
new file mode 100644
index 00000000..d1fb84a2
--- /dev/null
+++ b/tests/generic/694.out
@@ -0,0 +1,2 @@
+QA output created by 694
+Silence is golden
diff --git a/tests/generic/695 b/tests/generic/695
new file mode 100755
index 00000000..b46e35cf
--- /dev/null
+++ b/tests/generic/695
@@ -0,0 +1,91 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2022 SUSE Linux Products GmbH. All Rights Reserved.
+#
+# FS QA Test 695
+#
+# Test that if we punch a hole adjacent to an existing hole, fsync the file and
+# then power fail, the new hole exists after mounting again the filesystem.
+#
+# This is motivated by a regression on btrfs, fixed by the commit mentioned
+# below, when not using the no-holes feature (which is enabled by default since
+# btrfs-progs 5.15).
+#
+. ./common/preamble
+_begin_fstest auto quick log punch
+
+_cleanup()
+{
+ _cleanup_flakey
+ cd /
+ rm -r -f $tmp.*
+}
+
+. ./common/filter
+. ./common/dmflakey
+. ./common/punch
+
+_supported_fs generic
+_fixed_by_kernel_commit e6e3dec6c3c288 \
+ "btrfs: update generation of hole file extent item when merging holes"
+_require_scratch
+_require_dm_target flakey
+_require_xfs_io_command "fpunch"
+_require_xfs_io_command "fiemap"
+
+_scratch_mkfs >>$seqres.full 2>&1
+_require_metadata_journaling $SCRATCH_DEV
+_init_flakey
+_mount_flakey
+
+# We punch 2M holes and require extent allocations to align to 2M in fiemap
+# results.
+_require_congruent_file_oplen $SCRATCH_MNT $((2 * 1024 * 1024))
+
+# Create our test file with the following layout:
+#
+# [0, 2M) - hole
+# [2M, 10M) - extent
+# [10M, 12M) - hole
+$XFS_IO_PROG -f -c "truncate 12M" \
+ -c "pwrite -S 0xab 2M 8M" \
+ $SCRATCH_MNT/foobar | _filter_xfs_io
+
+# Persist everything, commit the filesystem's transaction.
+sync
+
+# Now punch two holes in the file:
+#
+# 1) For the range [2M, 4M), which is adjacent to the existing hole in the range
+# [0, 2M);
+# 2) For the range [8M, 10M), which is adjacent to the existing hole in the
+# range [10M, 12M).
+#
+# These operations start a new filesystem transaction.
+# Then finally fsync the file.
+$XFS_IO_PROG -c "fpunch 2M 2M" \
+ -c "fpunch 8M 2M" \
+ -c "fsync" $SCRATCH_MNT/foobar
+
+# Simulate a power failure and mount the filesystem to check that everything
+# is in the same state as before the power failure.
+_flakey_drop_and_remount
+
+# We expect the following file layout:
+#
+# [0, 4M) - hole
+# [4M, 8M) - extent
+# [8M, 12M) - hole
+echo "File layout after power failure:"
+$XFS_IO_PROG -c "fiemap -v" $SCRATCH_MNT/foobar | _filter_fiemap
+
+# When reading the file we expect to get the range [4M, 8M) filled with bytes
+# that have a value of 0xab and 0x00 for anything outside that range.
+echo "File content after power failure:"
+_hexdump $SCRATCH_MNT/foobar
+
+_unmount_flakey
+
+# success, all done
+status=0
+exit
diff --git a/tests/generic/695.out b/tests/generic/695.out
new file mode 100644
index 00000000..447ef5cf
--- /dev/null
+++ b/tests/generic/695.out
@@ -0,0 +1,15 @@
+QA output created by 695
+wrote 8388608/8388608 bytes at offset 2097152
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+File layout after power failure:
+0: [0..8191]: hole
+1: [8192..16383]: data
+2: [16384..24575]: hole
+File content after power failure:
+000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >................<
+*
+400000 ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab >................<
+*
+800000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >................<
+*
+c00000
diff --git a/tests/generic/696 b/tests/generic/696
new file mode 100755
index 00000000..178d78e1
--- /dev/null
+++ b/tests/generic/696
@@ -0,0 +1,46 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2022 Fujitsu Limited. All Rights Reserved.
+#
+# FS QA Test No. 696
+#
+# Test S_ISGID stripping whether works correctly when call process
+# uses umask(S_IXGRP).
+#
+# It is also a regression test for
+# commit ac6800e279a2 ("fs: Add missing umask strip in vfs_tmpfile")
+# commit 1639a49ccdce ("fs: move S_ISGID stripping into the vfs_*() helpers")
+
+. ./common/preamble
+_begin_fstest auto quick cap idmapped mount perms rw unlink
+
+# Import common functions.
+. ./common/filter
+
+# real QA test starts here
+
+_supported_fs generic
+_require_test
+_require_scratch
+_fixed_by_kernel_commit ac6800e279a2 \
+ "fs: Add missing umask strip in vfs_tmpfile" \
+1639a49ccdce "fs: move S_ISGID stripping into the vfs_*() helpers"
+
+_scratch_mkfs >$seqres.full 2>&1
+
+$here/src/vfs/vfstest --test-setgid-create-umask \
+ --device "$TEST_DEV" --mount "$TEST_DIR" --fstype "$FSTYP"
+
+export MOUNT_OPTIONS="-o noacl $MOUNT_OPTIONS"
+
+# Also test S_ISGID stripping whether works correctly on underflying filesystem
+# that supports noacl feature.
+# noacl will earse acl flag in superblock, so kernel will use current_umask in
+# vfs directly instead of calling posix_acl_create on underflying filesystem.
+_try_scratch_mount >>$seqres.full 2>&1 && \
+ $here/src/vfs/vfstest --test-setgid-create-umask \
+ --device "$SCRATCH_DEV" --mount "$SCRATCH_MNT" --fstype "$FSTYP"
+
+echo "Silence is golden"
+status=0
+exit
diff --git a/tests/generic/696.out b/tests/generic/696.out
new file mode 100644
index 00000000..c07efdfe
--- /dev/null
+++ b/tests/generic/696.out
@@ -0,0 +1,2 @@
+QA output created by 696
+Silence is golden
diff --git a/tests/generic/697 b/tests/generic/697
new file mode 100755
index 00000000..8d7ad651
--- /dev/null
+++ b/tests/generic/697
@@ -0,0 +1,33 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2022 Fujitsu Limited. All Rights Reserved.
+#
+# FS QA Test No. 697
+#
+# Test S_ISGID stripping whether works correctly when call process
+# uses posix acl.
+#
+# It is also a regression test for
+# commit 1639a49ccdce ("fs: move S_ISGID stripping into the vfs_*() helpers")
+
+. ./common/preamble
+_begin_fstest auto quick cap acl idmapped mount perms rw unlink
+
+# Import common functions.
+. ./common/filter
+. ./common/attr
+
+# real QA test starts here
+
+_supported_fs generic
+_require_test
+_require_acls
+_fixed_by_kernel_commit 1639a49ccdce \
+ "fs: move S_ISGID stripping into the vfs_*() helpers"
+
+$here/src/vfs/vfstest --test-setgid-create-acl \
+ --device "$TEST_DEV" --mount "$TEST_DIR" --fstype "$FSTYP"
+
+echo "Silence is golden"
+status=0
+exit
diff --git a/tests/generic/697.out b/tests/generic/697.out
new file mode 100644
index 00000000..8aab5a91
--- /dev/null
+++ b/tests/generic/697.out
@@ -0,0 +1,2 @@
+QA output created by 697
+Silence is golden
diff --git a/tests/xfs/006.out b/tests/xfs/006.out
index 3260b3a2..433b0bc3 100644
--- a/tests/xfs/006.out
+++ b/tests/xfs/006.out
@@ -1,8 +1,8 @@
QA output created by 006
error/fail_at_unmount=1
error/metadata/default/max_retries=-1
-error/metadata/default/retry_timeout_seconds=0
+error/metadata/default/retry_timeout_seconds=-1
error/metadata/EIO/max_retries=-1
-error/metadata/EIO/retry_timeout_seconds=0
+error/metadata/EIO/retry_timeout_seconds=-1
error/metadata/ENOSPC/max_retries=-1
-error/metadata/ENOSPC/retry_timeout_seconds=0
+error/metadata/ENOSPC/retry_timeout_seconds=-1
diff --git a/tests/xfs/015 b/tests/xfs/015
index 2bb7b8d5..a7f4d243 100755
--- a/tests/xfs/015
+++ b/tests/xfs/015
@@ -40,10 +40,10 @@ _require_scratch
# need 128M space, don't make any assumption
_scratch_mkfs >/dev/null 2>&1
_scratch_mount
-_require_fs_space $SCRATCH_MNT 131072
+_require_fs_space $SCRATCH_MNT 196608
_scratch_unmount
-_scratch_mkfs_sized $((32 * 1024 * 1024)) > $tmp.mkfs.raw || _fail "mkfs failed"
+_scratch_mkfs_sized $((96 * 1024 * 1024)) > $tmp.mkfs.raw || _fail "mkfs failed"
cat $tmp.mkfs.raw | _filter_mkfs >$seqres.full 2>$tmp.mkfs
# get original data blocks number and agcount
. $tmp.mkfs
diff --git a/tests/xfs/018 b/tests/xfs/018
index 041a3b24..1b45edf4 100755
--- a/tests/xfs/018
+++ b/tests/xfs/018
@@ -47,7 +47,8 @@ test_attr_replay()
touch $testfile
# Verify attr recovery
- $ATTR_PROG -l $testfile | _filter_scratch
+ $ATTR_PROG -l $testfile >> $seqres.full
+ echo "Checking contents of $attr_name" >> $seqres.full
echo -n "$attr_name: "
$ATTR_PROG -q -g $attr_name $testfile 2> /dev/null | md5sum;
@@ -98,6 +99,10 @@ attr64k="$attr32k$attr32k"
echo "*** mkfs"
_scratch_mkfs >/dev/null
+blk_sz=$(_scratch_xfs_get_sb_field blocksize)
+err_inj_attr_sz=$(( blk_sz / 3 - 50 ))
+err_inj_attr_val=$(printf "A%.0s" $(seq $err_inj_attr_sz))
+
echo "*** mount FS"
_scratch_mount
@@ -140,12 +145,12 @@ test_attr_replay extent_file1 "attr_name2" $attr1k "s" "larp"
test_attr_replay extent_file1 "attr_name2" $attr1k "r" "larp"
# extent, inject error on split
-create_test_file extent_file2 3 $attr1k
-test_attr_replay extent_file2 "attr_name4" $attr1k "s" "da_leaf_split"
+create_test_file extent_file2 3 $err_inj_attr_val
+test_attr_replay extent_file2 "attr_name4" $attr256 "s" "da_leaf_split"
# extent, inject error on fork transition
-create_test_file extent_file3 3 $attr1k
-test_attr_replay extent_file3 "attr_name4" $attr1k "s" "attr_leaf_to_node"
+create_test_file extent_file3 3 $err_inj_attr_val
+test_attr_replay extent_file3 "attr_name4" $attr256 "s" "attr_leaf_to_node"
# extent, remote
create_test_file extent_file4 1 $attr1k
diff --git a/tests/xfs/018.out b/tests/xfs/018.out
index 022b0ca3..415ecd7a 100644
--- a/tests/xfs/018.out
+++ b/tests/xfs/018.out
@@ -4,7 +4,6 @@ QA output created by 018
attr_set: Input/output error
Could not set "attr_name" for SCRATCH_MNT/testdir/empty_file1
touch: cannot touch 'SCRATCH_MNT/testdir/empty_file1': Input/output error
-Attribute "attr_name" has a 65 byte value for SCRATCH_MNT/testdir/empty_file1
attr_name: cfbe2a33be4601d2b655d099a18378fc -
attr_remove: Input/output error
@@ -15,7 +14,6 @@ attr_name: d41d8cd98f00b204e9800998ecf8427e -
attr_set: Input/output error
Could not set "attr_name" for SCRATCH_MNT/testdir/empty_file2
touch: cannot touch 'SCRATCH_MNT/testdir/empty_file2': Input/output error
-Attribute "attr_name" has a 1025 byte value for SCRATCH_MNT/testdir/empty_file2
attr_name: 9fd415c49d67afc4b78fad4055a3a376 -
attr_remove: Input/output error
@@ -26,7 +24,6 @@ attr_name: d41d8cd98f00b204e9800998ecf8427e -
attr_set: Input/output error
Could not set "attr_name" for SCRATCH_MNT/testdir/empty_file3
touch: cannot touch 'SCRATCH_MNT/testdir/empty_file3': Input/output error
-Attribute "attr_name" has a 65536 byte value for SCRATCH_MNT/testdir/empty_file3
attr_name: 7f6fd1b6d872108bd44bd143cbcdfa19 -
attr_remove: Input/output error
@@ -37,132 +34,96 @@ attr_name: d41d8cd98f00b204e9800998ecf8427e -
attr_set: Input/output error
Could not set "attr_name2" for SCRATCH_MNT/testdir/inline_file1
touch: cannot touch 'SCRATCH_MNT/testdir/inline_file1': Input/output error
-Attribute "attr_name1" has a 16 byte value for SCRATCH_MNT/testdir/inline_file1
-Attribute "attr_name2" has a 65 byte value for SCRATCH_MNT/testdir/inline_file1
attr_name2: cfbe2a33be4601d2b655d099a18378fc -
attr_remove: Input/output error
Could not remove "attr_name2" for SCRATCH_MNT/testdir/inline_file1
touch: cannot touch 'SCRATCH_MNT/testdir/inline_file1': Input/output error
-Attribute "attr_name1" has a 16 byte value for SCRATCH_MNT/testdir/inline_file1
attr_name2: d41d8cd98f00b204e9800998ecf8427e -
attr_set: Input/output error
Could not set "attr_name2" for SCRATCH_MNT/testdir/inline_file2
touch: cannot touch 'SCRATCH_MNT/testdir/inline_file2': Input/output error
-Attribute "attr_name2" has a 1025 byte value for SCRATCH_MNT/testdir/inline_file2
-Attribute "attr_name1" has a 16 byte value for SCRATCH_MNT/testdir/inline_file2
attr_name2: 9fd415c49d67afc4b78fad4055a3a376 -
attr_remove: Input/output error
Could not remove "attr_name2" for SCRATCH_MNT/testdir/inline_file2
touch: cannot touch 'SCRATCH_MNT/testdir/inline_file2': Input/output error
-Attribute "attr_name1" has a 16 byte value for SCRATCH_MNT/testdir/inline_file2
attr_name2: d41d8cd98f00b204e9800998ecf8427e -
attr_set: Input/output error
Could not set "attr_name2" for SCRATCH_MNT/testdir/inline_file3
touch: cannot touch 'SCRATCH_MNT/testdir/inline_file3': Input/output error
-Attribute "attr_name2" has a 65536 byte value for SCRATCH_MNT/testdir/inline_file3
-Attribute "attr_name1" has a 16 byte value for SCRATCH_MNT/testdir/inline_file3
attr_name2: 7f6fd1b6d872108bd44bd143cbcdfa19 -
attr_remove: Input/output error
Could not remove "attr_name2" for SCRATCH_MNT/testdir/inline_file3
touch: cannot touch 'SCRATCH_MNT/testdir/inline_file3': Input/output error
-Attribute "attr_name1" has a 16 byte value for SCRATCH_MNT/testdir/inline_file3
attr_name2: d41d8cd98f00b204e9800998ecf8427e -
attr_set: Input/output error
Could not set "attr_name2" for SCRATCH_MNT/testdir/extent_file1
touch: cannot touch 'SCRATCH_MNT/testdir/extent_file1': Input/output error
-Attribute "attr_name2" has a 1025 byte value for SCRATCH_MNT/testdir/extent_file1
-Attribute "attr_name1" has a 1024 byte value for SCRATCH_MNT/testdir/extent_file1
attr_name2: 9fd415c49d67afc4b78fad4055a3a376 -
attr_remove: Input/output error
Could not remove "attr_name2" for SCRATCH_MNT/testdir/extent_file1
touch: cannot touch 'SCRATCH_MNT/testdir/extent_file1': Input/output error
-Attribute "attr_name1" has a 1024 byte value for SCRATCH_MNT/testdir/extent_file1
attr_name2: d41d8cd98f00b204e9800998ecf8427e -
attr_set: Input/output error
Could not set "attr_name4" for SCRATCH_MNT/testdir/extent_file2
touch: cannot touch 'SCRATCH_MNT/testdir/extent_file2': Input/output error
-Attribute "attr_name4" has a 1025 byte value for SCRATCH_MNT/testdir/extent_file2
-Attribute "attr_name2" has a 1024 byte value for SCRATCH_MNT/testdir/extent_file2
-Attribute "attr_name3" has a 1024 byte value for SCRATCH_MNT/testdir/extent_file2
-Attribute "attr_name1" has a 1024 byte value for SCRATCH_MNT/testdir/extent_file2
-attr_name4: 9fd415c49d67afc4b78fad4055a3a376 -
+attr_name4: f4ea5799d72a0a9bf2d56a685c9cba7a -
attr_set: Input/output error
Could not set "attr_name4" for SCRATCH_MNT/testdir/extent_file3
touch: cannot touch 'SCRATCH_MNT/testdir/extent_file3': Input/output error
-Attribute "attr_name4" has a 1025 byte value for SCRATCH_MNT/testdir/extent_file3
-Attribute "attr_name2" has a 1024 byte value for SCRATCH_MNT/testdir/extent_file3
-Attribute "attr_name3" has a 1024 byte value for SCRATCH_MNT/testdir/extent_file3
-Attribute "attr_name1" has a 1024 byte value for SCRATCH_MNT/testdir/extent_file3
-attr_name4: 9fd415c49d67afc4b78fad4055a3a376 -
+attr_name4: f4ea5799d72a0a9bf2d56a685c9cba7a -
attr_set: Input/output error
Could not set "attr_name2" for SCRATCH_MNT/testdir/extent_file4
touch: cannot touch 'SCRATCH_MNT/testdir/extent_file4': Input/output error
-Attribute "attr_name2" has a 65536 byte value for SCRATCH_MNT/testdir/extent_file4
-Attribute "attr_name1" has a 1024 byte value for SCRATCH_MNT/testdir/extent_file4
attr_name2: 7f6fd1b6d872108bd44bd143cbcdfa19 -
attr_remove: Input/output error
Could not remove "attr_name2" for SCRATCH_MNT/testdir/extent_file4
touch: cannot touch 'SCRATCH_MNT/testdir/extent_file4': Input/output error
-Attribute "attr_name1" has a 1024 byte value for SCRATCH_MNT/testdir/extent_file4
attr_name2: d41d8cd98f00b204e9800998ecf8427e -
attr_set: Input/output error
Could not set "attr_name2" for SCRATCH_MNT/testdir/remote_file1
touch: cannot touch 'SCRATCH_MNT/testdir/remote_file1': Input/output error
-Attribute "attr_name2" has a 1025 byte value for SCRATCH_MNT/testdir/remote_file1
-Attribute "attr_name1" has a 65536 byte value for SCRATCH_MNT/testdir/remote_file1
attr_name2: 9fd415c49d67afc4b78fad4055a3a376 -
attr_remove: Input/output error
Could not remove "attr_name2" for SCRATCH_MNT/testdir/remote_file1
touch: cannot touch 'SCRATCH_MNT/testdir/remote_file1': Input/output error
-Attribute "attr_name1" has a 65536 byte value for SCRATCH_MNT/testdir/remote_file1
attr_name2: d41d8cd98f00b204e9800998ecf8427e -
attr_set: Input/output error
Could not set "attr_name2" for SCRATCH_MNT/testdir/remote_file2
touch: cannot touch 'SCRATCH_MNT/testdir/remote_file2': Input/output error
-Attribute "attr_name2" has a 65536 byte value for SCRATCH_MNT/testdir/remote_file2
-Attribute "attr_name1" has a 65536 byte value for SCRATCH_MNT/testdir/remote_file2
attr_name2: 7f6fd1b6d872108bd44bd143cbcdfa19 -
attr_remove: Input/output error
Could not remove "attr_name2" for SCRATCH_MNT/testdir/remote_file2
touch: cannot touch 'SCRATCH_MNT/testdir/remote_file2': Input/output error
-Attribute "attr_name1" has a 65536 byte value for SCRATCH_MNT/testdir/remote_file2
attr_name2: d41d8cd98f00b204e9800998ecf8427e -
attr_set: Input/output error
Could not set "attr_name2" for SCRATCH_MNT/testdir/sf_file
touch: cannot touch 'SCRATCH_MNT/testdir/sf_file': Input/output error
-Attribute "attr_name1" has a 64 byte value for SCRATCH_MNT/testdir/sf_file
-Attribute "attr_name2" has a 17 byte value for SCRATCH_MNT/testdir/sf_file
attr_name2: 9a6eb1bc9da3c66a9b495dfe2fe8a756 -
attr_set: Input/output error
Could not set "attr_name2" for SCRATCH_MNT/testdir/leaf_file
touch: cannot touch 'SCRATCH_MNT/testdir/leaf_file': Input/output error
-Attribute "attr_name2" has a 257 byte value for SCRATCH_MNT/testdir/leaf_file
-Attribute "attr_name3" has a 1024 byte value for SCRATCH_MNT/testdir/leaf_file
-Attribute "attr_name1" has a 1024 byte value for SCRATCH_MNT/testdir/leaf_file
attr_name2: f4ea5799d72a0a9bf2d56a685c9cba7a -
attr_set: Input/output error
Could not set "attr_name2" for SCRATCH_MNT/testdir/node_file
touch: cannot touch 'SCRATCH_MNT/testdir/node_file': Input/output error
-Attribute "attr_name2" has a 257 byte value for SCRATCH_MNT/testdir/node_file
-Attribute "attr_name1" has a 65536 byte value for SCRATCH_MNT/testdir/node_file
attr_name2: f4ea5799d72a0a9bf2d56a685c9cba7a -
*** done
diff --git a/tests/xfs/042 b/tests/xfs/042
index d62eb045..657abd21 100755
--- a/tests/xfs/042
+++ b/tests/xfs/042
@@ -51,14 +51,14 @@ _require_scratch
_do_die_on_error=message_only
-echo -n "Make a 48 megabyte filesystem on SCRATCH_DEV and mount... "
-_scratch_mkfs_xfs -dsize=48m,agcount=3 2>&1 >/dev/null || _fail "mkfs failed"
+echo -n "Make a 96 megabyte filesystem on SCRATCH_DEV and mount... "
+_scratch_mkfs_xfs -dsize=96m,agcount=3 2>&1 >/dev/null || _fail "mkfs failed"
_scratch_mount
echo "done"
-echo -n "Reserve 16 1Mb unfragmented regions... "
-for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+echo -n "Reserve 32 1Mb unfragmented regions... "
+for i in `seq 1 32`
do
_do "$XFS_IO_PROG -f -c \"resvsp 0 1m\" $SCRATCH_MNT/hole$i"
_do "$XFS_IO_PROG -f -c \"resvsp 0 4k\" $SCRATCH_MNT/space$i"
@@ -68,7 +68,7 @@ echo "done"
# set up filesystem
echo -n "Fill filesystem with fill file... "
-for i in `seq 0 1 31`; do
+for i in `seq 0 1 63`; do
_do "$XFS_IO_PROG -f -c \"falloc ${i}m 1m\" $SCRATCH_MNT/fill"
done
_do "xfs_bmap -vp $SCRATCH_MNT/fill"
@@ -83,7 +83,7 @@ echo "done"
# create fragmented file
#_do "Delete every second file" "_cull_files"
echo -n "Punch every second 4k block... "
-for i in `seq 0 8 32768`; do
+for i in `seq 0 8 65536`; do
# This generates excessive output that significantly slows down the
# test. It's not necessary for debug, so just bin it.
$XFS_IO_PROG -f -c "unresvsp ${i}k 4k" $SCRATCH_MNT/fill \
@@ -94,7 +94,7 @@ _do "sum $SCRATCH_MNT/fill >$tmp.fillsum1"
echo "done"
echo -n "Create one very large file... "
-_do "$here/src/fill2 -d nbytes=16000000,file=$SCRATCH_MNT/fragmented"
+_do "$here/src/fill2 -d nbytes=32000000,file=$SCRATCH_MNT/fragmented"
echo "done"
_do "xfs_bmap -v $SCRATCH_MNT/fragmented"
_do "sum $SCRATCH_MNT/fragmented >$tmp.sum1"
diff --git a/tests/xfs/042.out b/tests/xfs/042.out
index a25885b6..e7ec3d41 100644
--- a/tests/xfs/042.out
+++ b/tests/xfs/042.out
@@ -1,6 +1,6 @@
QA output created by 042
-Make a 48 megabyte filesystem on SCRATCH_DEV and mount... done
-Reserve 16 1Mb unfragmented regions... done
+Make a 96 megabyte filesystem on SCRATCH_DEV and mount... done
+Reserve 32 1Mb unfragmented regions... done
Fill filesystem with fill file... done
Use up any further available space... done
Punch every second 4k block... done
diff --git a/tests/xfs/069 b/tests/xfs/069
index bf4aa202..b3074e25 100755
--- a/tests/xfs/069
+++ b/tests/xfs/069
@@ -22,6 +22,7 @@ _require_scratch
_scratch_mkfs_xfs >/dev/null 2>&1
_scratch_mount
+_require_congruent_file_oplen $SCRATCH_MNT 8388608
small=$SCRATCH_MNT/small
big=$SCRATCH_MNT/big
diff --git a/tests/xfs/076 b/tests/xfs/076
index 8eef1367..db88b43d 100755
--- a/tests/xfs/076
+++ b/tests/xfs/076
@@ -69,7 +69,7 @@ _require_xfs_sparse_inodes
# bitmap consuming all the free space in our small data device.
unset SCRATCH_RTDEV
-_scratch_mkfs "-d size=50m -m crc=1 -i sparse" | tee -a $seqres.full |
+_scratch_mkfs "-d size=96m -m crc=1 -i sparse" | tee -a $seqres.full |
_filter_mkfs > /dev/null 2> $tmp.mkfs
. $tmp.mkfs # for isize
diff --git a/tests/xfs/114 b/tests/xfs/114
index a0ea1d13..3aec814a 100755
--- a/tests/xfs/114
+++ b/tests/xfs/114
@@ -35,6 +35,8 @@ len1=$((blocks1 * blksz))
len2=$((blocks2 * blksz))
file_blksz=$(_get_file_block_size $SCRATCH_MNT)
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
+
echo "Create some files"
$XFS_IO_PROG -f \
-c "falloc 0 $len1" \
diff --git a/tests/xfs/144 b/tests/xfs/144
index 2910eec9..706aff61 100755
--- a/tests/xfs/144
+++ b/tests/xfs/144
@@ -16,6 +16,10 @@ _begin_fstest auto mkfs
# Modify as appropriate.
_supported_fs xfs
_require_test
+
+# The last testcase creates a (sparse) fs image with a 2GB log, so we need
+# 3GB to avoid failing the mkfs due to ENOSPC.
+_require_fs_space $TEST_DIR $((3 * 1048576))
echo Silence is golden
testfile=$TEST_DIR/a
@@ -26,7 +30,7 @@ test_format() {
shift
echo "$tag" >> $seqres.full
- $MKFS_XFS_PROG $@ -d file,name=$testfile &>> $seqres.full
+ $MKFS_XFS_PROG -f $@ -d file,name=$testfile &>> $seqres.full
local res=$?
test $res -eq 0 || echo "$tag FAIL $res" | tee -a $seqres.full
}
@@ -38,13 +42,13 @@ for M in `seq 298 302` `seq 490 520`; do
done
done
+# log end rounded beyond EOAG due to stripe unit
+test_format "log end beyond eoag" -d agcount=3200,size=6366g -d su=256k,sw=4 -N
+
# Log so large it pushes the root dir into AG 1. We can't use -N for the mkfs
# because this check only occurs after the root directory has been allocated,
# which mkfs -N doesn't do.
-test_format "log pushes rootdir into AG 1" -d agcount=3200,size=6366g -lagnum=0 -N
-
-# log end rounded beyond EOAG due to stripe unit
-test_format "log end beyond eoag" -d agcount=3200,size=6366g -d su=256k,sw=4 -N
+test_format "log pushes rootdir into AG 1" -d agcount=3200,size=6366g -lagnum=0
# success, all done
status=0
diff --git a/tests/xfs/166 b/tests/xfs/166
index d45dc5e8..9e082152 100755
--- a/tests/xfs/166
+++ b/tests/xfs/166
@@ -71,6 +71,10 @@ TEST_PROG=$here/src/unwritten_mmap
# we need to set the file size to (6 * 2MB == 12MB) to cover all cases.
FILE_SIZE=$((12 * 1048576))
+# The xfs_bmap results in the golden output requires file allocations to align
+# to 1M boundaries.
+_require_congruent_file_oplen $SCRATCH_MNT $FILE_SIZE
+
rm -f $TEST_FILE
$TEST_PROG $FILE_SIZE $TEST_FILE
diff --git a/tests/xfs/180 b/tests/xfs/180
index 72a1b738..9b52f1ff 100755
--- a/tests/xfs/180
+++ b/tests/xfs/180
@@ -32,6 +32,7 @@ testdir=$SCRATCH_MNT/test-$seq
mkdir $testdir
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=128
filesize=$((blksz * nr))
bufnr=16
diff --git a/tests/xfs/182 b/tests/xfs/182
index ea565824..93852229 100755
--- a/tests/xfs/182
+++ b/tests/xfs/182
@@ -33,6 +33,7 @@ testdir=$SCRATCH_MNT/test-$seq
mkdir $testdir
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=128
filesize=$((blksz * nr))
bufnr=16
diff --git a/tests/xfs/184 b/tests/xfs/184
index 95250b29..2ca6528e 100755
--- a/tests/xfs/184
+++ b/tests/xfs/184
@@ -33,6 +33,7 @@ testdir=$SCRATCH_MNT/test-$seq
mkdir $testdir
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=128
filesize=$((blksz * nr))
bufnr=16
diff --git a/tests/xfs/191 b/tests/xfs/191
new file mode 100755
index 00000000..4f0a9b9e
--- /dev/null
+++ b/tests/xfs/191
@@ -0,0 +1,120 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2022 Oracle. All Rights Reserved.
+#
+# FS QA Test No. 191
+#
+# Make sure that XFS can handle empty leaf xattr blocks correctly. These
+# blocks can appear in files as a result of system crashes in the middle of
+# xattr operations, which means that we /must/ handle them gracefully.
+# Check that read and write verifiers won't trip, that the get/list/setxattr
+# operations don't stumble over them, and that xfs_repair will offer to remove
+# the entire xattr fork if the root xattr leaf block is empty.
+#
+# Regression test for
+# kernel commit:
+# 7be3bd8856fb ("xfs: empty xattr leaf header blocks are not corruption")
+# xfsprogs commit:
+# f50d3462c654 ("xfs_repair: ignore empty xattr leaf blocks")
+#
+. ./common/preamble
+_begin_fstest auto quick attr
+
+# Import common functions.
+. ./common/filter
+. ./common/attr
+
+# real QA test starts here
+
+_supported_fs xfs
+_require_scratch
+_require_scratch_xfs_crc # V4 is deprecated
+_fixed_by_kernel_commit 7be3bd8856fb "xfs: empty xattr leaf header blocks are not corruption"
+_fixed_by_git_commit xfsprogs f50d3462c654 "xfs_repair: ignore empty xattr leaf blocks"
+
+_scratch_mkfs_xfs | _filter_mkfs >$seqres.full 2>$tmp.mkfs
+cat $tmp.mkfs >> $seqres.full
+source $tmp.mkfs
+_scratch_mount
+
+$XFS_IO_PROG -f -c 'pwrite -S 0x58 0 64k' $SCRATCH_MNT/largefile >> $seqres.full
+$XFS_IO_PROG -f -c "pwrite -S 0x58 0 $isize" $SCRATCH_MNT/smallfile >> $seqres.full
+
+smallfile_md5=$(_md5_checksum $SCRATCH_MNT/smallfile)
+largefile_md5=$(_md5_checksum $SCRATCH_MNT/largefile)
+
+# Try to force the creation of a single leaf block in each of three files.
+# The first one gets a local attr, the second a remote attr, and the third
+# is left for scrub and repair to find.
+touch $SCRATCH_MNT/e0
+touch $SCRATCH_MNT/e1
+touch $SCRATCH_MNT/e2
+
+$ATTR_PROG -s x $SCRATCH_MNT/e0 < $SCRATCH_MNT/smallfile >> $seqres.full
+$ATTR_PROG -s x $SCRATCH_MNT/e1 < $SCRATCH_MNT/smallfile >> $seqres.full
+$ATTR_PROG -s x $SCRATCH_MNT/e2 < $SCRATCH_MNT/smallfile >> $seqres.full
+
+e0_ino=$(stat -c '%i' $SCRATCH_MNT/e0)
+e1_ino=$(stat -c '%i' $SCRATCH_MNT/e1)
+e2_ino=$(stat -c '%i' $SCRATCH_MNT/e2)
+
+_scratch_unmount
+
+# We used to think that it wasn't possible for empty xattr leaf blocks to
+# exist, but it turns out that setting a large xattr on a file that has no
+# xattrs can race with a log flush and crash, which results in an empty
+# leaf block being logged and recovered. This is rather hard to trip, so we
+# use xfs_db to turn a regular leaf block into an empty one.
+make_empty_leaf() {
+ local inum="$1"
+
+ echo "editing inode $inum" >> $seqres.full
+
+ magic=$(_scratch_xfs_get_metadata_field hdr.info.hdr.magic "inode $inum" "ablock 0")
+ if [ "$magic" != "0x3bee" ]; then
+ _scratch_xfs_db -x -c "inode $inum" -c "ablock 0" -c print >> $seqres.full
+ _fail "inode $inum ablock 0 is not a leaf block?"
+ fi
+
+ base=$(_scratch_xfs_get_metadata_field "hdr.freemap[0].base" "inode $inum" "ablock 0")
+
+ _scratch_xfs_db -x -c "inode $inum" -c "ablock 0" \
+ -c "write -d hdr.count 0" \
+ -c "write -d hdr.usedbytes 0" \
+ -c "write -d hdr.firstused $dbsize" \
+ -c "write -d hdr.freemap[0].size $((dbsize - base))" \
+ -c print >> $seqres.full
+}
+
+make_empty_leaf $e0_ino
+make_empty_leaf $e1_ino
+make_empty_leaf $e2_ino
+
+_scratch_mount
+
+# Check that listxattr/getxattr/removexattr do nothing.
+$ATTR_PROG -l $SCRATCH_MNT/e0 2>&1 | _filter_scratch
+$ATTR_PROG -g x $SCRATCH_MNT/e0 2>&1 | _filter_scratch
+$ATTR_PROG -r x $SCRATCH_MNT/e0 2>&1 | _filter_scratch
+
+# Add a small attr to e0
+$ATTR_PROG -s x $SCRATCH_MNT/e0 < $SCRATCH_MNT/smallfile > /dev/null
+$ATTR_PROG -l $SCRATCH_MNT/e0 2>&1 | sed -e 's/\([0-9]*\) byte/XXX byte/g' | _filter_scratch
+small_md5="$($GETFATTR_PROG -n user.x --absolute-names --only-values $SCRATCH_MNT/e0 | _md5_checksum)"
+test "$small_md5" = "$smallfile_md5" || \
+ echo "smallfile $smallfile_md5 does not match small attr $small_md5"
+
+# Add a large attr to e1
+$ATTR_PROG -s x $SCRATCH_MNT/e1 < $SCRATCH_MNT/largefile > /dev/null
+$ATTR_PROG -l $SCRATCH_MNT/e1 2>&1 | _filter_scratch
+large_md5="$($GETFATTR_PROG -n user.x --absolute-names --only-values $SCRATCH_MNT/e1 | _md5_checksum)"
+test "$large_md5" = "$largefile_md5" || \
+ echo "largefile $largefile_md5 does not match large attr $large_md5"
+
+
+# Leave e2 to try to trip the repair tools, since xfs_repair used to flag
+# empty leaf blocks incorrectly too.
+
+# success, all done
+status=0
+exit
diff --git a/tests/xfs/191.out b/tests/xfs/191.out
new file mode 100644
index 00000000..46dc05c7
--- /dev/null
+++ b/tests/xfs/191.out
@@ -0,0 +1,7 @@
+QA output created by 191
+attr_get: No data available
+Could not get "x" for SCRATCH_MNT/e0
+attr_remove: No data available
+Could not remove "x" for SCRATCH_MNT/e0
+Attribute "x" has a XXX byte value for SCRATCH_MNT/e0
+Attribute "x" has a 65536 byte value for SCRATCH_MNT/e1
diff --git a/tests/xfs/192 b/tests/xfs/192
index 1eb9d52e..8329604d 100755
--- a/tests/xfs/192
+++ b/tests/xfs/192
@@ -34,6 +34,7 @@ testdir=$SCRATCH_MNT/test-$seq
mkdir $testdir
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=128
filesize=$((blksz * nr))
bufnr=16
diff --git a/tests/xfs/193 b/tests/xfs/193
index 1bc48610..18f2fc2f 100755
--- a/tests/xfs/193
+++ b/tests/xfs/193
@@ -31,6 +31,7 @@ testdir=$SCRATCH_MNT/test-$seq
mkdir $testdir
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=128
filesize=$((blksz * nr))
bufnr=16
diff --git a/tests/xfs/198 b/tests/xfs/198
index 0c650874..231e1c23 100755
--- a/tests/xfs/198
+++ b/tests/xfs/198
@@ -32,6 +32,7 @@ testdir=$SCRATCH_MNT/test-$seq
mkdir $testdir
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=128
filesize=$((blksz * nr))
bufnr=16
diff --git a/tests/xfs/200 b/tests/xfs/200
index 2324fbdb..435cd9b9 100755
--- a/tests/xfs/200
+++ b/tests/xfs/200
@@ -35,6 +35,7 @@ testdir=$SCRATCH_MNT/test-$seq
mkdir $testdir
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=128
filesize=$((blksz * nr))
bufnr=16
diff --git a/tests/xfs/203 b/tests/xfs/203
index a12ae7c3..9a4a4564 100755
--- a/tests/xfs/203
+++ b/tests/xfs/203
@@ -51,6 +51,10 @@ _require_scratch
_scratch_mkfs > /dev/null 2>&1
_scratch_mount > /dev/null 2>&1
+# The xfs_bmap results in the golden output requires file allocations to align
+# to 64k boundaries.
+_require_congruent_file_oplen $SCRATCH_MNT 65536
+
for i in 10 14 15 16 17 28 29 30 31; do
rm -f $SCRATCH_MNT/hole_file
_write_holes $SCRATCH_MNT/hole_file${i} ${i}
diff --git a/tests/xfs/204 b/tests/xfs/204
index 931be128..3f9b6dca 100755
--- a/tests/xfs/204
+++ b/tests/xfs/204
@@ -36,6 +36,7 @@ testdir=$SCRATCH_MNT/test-$seq
mkdir $testdir
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=128
filesize=$((blksz * nr))
bufnr=16
diff --git a/tests/xfs/208 b/tests/xfs/208
index 66c3eda1..0fbb99c8 100755
--- a/tests/xfs/208
+++ b/tests/xfs/208
@@ -35,6 +35,7 @@ testdir=$SCRATCH_MNT/test-$seq
mkdir $testdir
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=128
filesize=$((blksz * nr))
bufnr=16
diff --git a/tests/xfs/209 b/tests/xfs/209
index 220ea31d..08ec87f5 100755
--- a/tests/xfs/209
+++ b/tests/xfs/209
@@ -23,6 +23,7 @@ _require_xfs_io_command "cowextsize"
echo "Format and mount"
_scratch_mkfs > $seqres.full 2>&1
_scratch_mount >> $seqres.full 2>&1
+_require_congruent_file_oplen $SCRATCH_MNT 1048576
testdir=$SCRATCH_MNT/test-$seq
mkdir $testdir
diff --git a/tests/xfs/210 b/tests/xfs/210
index 6edc5606..2439967b 100755
--- a/tests/xfs/210
+++ b/tests/xfs/210
@@ -27,6 +27,7 @@ _require_xfs_io_command "cowextsize"
echo "Format and mount"
_scratch_mkfs > $seqres.full 2>&1
_scratch_mount >> $seqres.full 2>&1
+_require_congruent_file_oplen $SCRATCH_MNT 65536
testdir=$SCRATCH_MNT/test-$seq
mkdir $testdir
diff --git a/tests/xfs/211 b/tests/xfs/211
index 05515041..b99871ba 100755
--- a/tests/xfs/211
+++ b/tests/xfs/211
@@ -33,6 +33,7 @@ testdir=$SCRATCH_MNT/test-$seq
mkdir $testdir
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=50000
filesize=$((blksz * nr))
bufnr=16
diff --git a/tests/xfs/212 b/tests/xfs/212
index b133e09b..805a72af 100755
--- a/tests/xfs/212
+++ b/tests/xfs/212
@@ -30,6 +30,7 @@ testdir=$SCRATCH_MNT/test-$seq
mkdir $testdir
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=16
filesize=$((blksz * nr))
bufnr=2
diff --git a/tests/xfs/215 b/tests/xfs/215
index 20217187..c07cdd1a 100755
--- a/tests/xfs/215
+++ b/tests/xfs/215
@@ -34,6 +34,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
real_blksz=$(_get_block_size $testdir)
diff --git a/tests/xfs/218 b/tests/xfs/218
index b834bbeb..cc3e1552 100755
--- a/tests/xfs/218
+++ b/tests/xfs/218
@@ -33,6 +33,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
real_blksz=$(_get_block_size $testdir)
diff --git a/tests/xfs/219 b/tests/xfs/219
index b0eeb784..bd2c47bf 100755
--- a/tests/xfs/219
+++ b/tests/xfs/219
@@ -34,6 +34,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
real_blksz=$(_get_block_size $testdir)
diff --git a/tests/xfs/221 b/tests/xfs/221
index 09b2067d..cda99b5c 100755
--- a/tests/xfs/221
+++ b/tests/xfs/221
@@ -33,6 +33,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
real_blksz=$(_get_block_size $testdir)
diff --git a/tests/xfs/223 b/tests/xfs/223
index 11dbad14..e22c1ba9 100755
--- a/tests/xfs/223
+++ b/tests/xfs/223
@@ -36,6 +36,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
real_blksz=$(_get_block_size $testdir)
diff --git a/tests/xfs/224 b/tests/xfs/224
index f8bab07e..7e984a8a 100755
--- a/tests/xfs/224
+++ b/tests/xfs/224
@@ -35,6 +35,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
real_blksz=$(_get_block_size $testdir)
diff --git a/tests/xfs/225 b/tests/xfs/225
index 52a37d64..a07ef3f0 100755
--- a/tests/xfs/225
+++ b/tests/xfs/225
@@ -34,6 +34,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
real_blksz=$(_get_block_size $testdir)
diff --git a/tests/xfs/226 b/tests/xfs/226
index 826bd08d..1e566e2e 100755
--- a/tests/xfs/226
+++ b/tests/xfs/226
@@ -33,6 +33,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
real_blksz=$(_get_block_size $testdir)
diff --git a/tests/xfs/228 b/tests/xfs/228
index f2f2f6a9..85a4abc5 100755
--- a/tests/xfs/228
+++ b/tests/xfs/228
@@ -41,6 +41,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
real_blksz=$(_get_block_size $testdir)
diff --git a/tests/xfs/230 b/tests/xfs/230
index 15f6b684..2347a307 100755
--- a/tests/xfs/230
+++ b/tests/xfs/230
@@ -41,6 +41,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
real_blksz=$(_get_block_size $testdir)
diff --git a/tests/xfs/231 b/tests/xfs/231
index 8155d0ab..fd7d7a85 100755
--- a/tests/xfs/231
+++ b/tests/xfs/231
@@ -45,6 +45,7 @@ testdir=$SCRATCH_MNT/test-$seq
mkdir $testdir
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
bufnr=2
diff --git a/tests/xfs/232 b/tests/xfs/232
index 06217466..0bf3bb75 100755
--- a/tests/xfs/232
+++ b/tests/xfs/232
@@ -46,6 +46,7 @@ testdir=$SCRATCH_MNT/test-$seq
mkdir $testdir
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
bufnr=2
diff --git a/tests/xfs/237 b/tests/xfs/237
index 34d54a6c..db235e05 100755
--- a/tests/xfs/237
+++ b/tests/xfs/237
@@ -46,6 +46,7 @@ bufsize=$((blksz * bufnr))
alignment=`_min_dio_alignment $TEST_DEV`
_require_fs_space $SCRATCH_MNT $((filesize / 1024 * 3 * 5 / 4))
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
echo "Create the original files"
$XFS_IO_PROG -c "cowextsize $((bufsize * 2))" $testdir
diff --git a/tests/xfs/239 b/tests/xfs/239
index 5143cc2e..f04460bc 100755
--- a/tests/xfs/239
+++ b/tests/xfs/239
@@ -35,6 +35,7 @@ testdir=$SCRATCH_MNT/test-$seq
mkdir $testdir
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=640
bufnr=128
filesize=$((blksz * nr))
diff --git a/tests/xfs/240 b/tests/xfs/240
index e5d35a83..a65c270d 100755
--- a/tests/xfs/240
+++ b/tests/xfs/240
@@ -40,6 +40,7 @@ testdir=$SCRATCH_MNT/test-$seq
mkdir $testdir
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=640
bufnr=128
filesize=$((blksz * nr))
diff --git a/tests/xfs/241 b/tests/xfs/241
index 7988c2d8..d9879788 100755
--- a/tests/xfs/241
+++ b/tests/xfs/241
@@ -36,6 +36,7 @@ testdir=$SCRATCH_MNT/test-$seq
mkdir $testdir
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=640
bufnr=128
filesize=$((blksz * nr))
diff --git a/tests/xfs/248 b/tests/xfs/248
index 32902cb7..cdb1da02 100755
--- a/tests/xfs/248
+++ b/tests/xfs/248
@@ -34,6 +34,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
$XFS_IO_PROG -c "cowextsize $((blksz * 16))" $testdir >> $seqres.full
diff --git a/tests/xfs/249 b/tests/xfs/249
index 774d3bf2..0c4b0335 100755
--- a/tests/xfs/249
+++ b/tests/xfs/249
@@ -35,6 +35,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
$XFS_IO_PROG -c "cowextsize $((blksz * 16))" $testdir >> $seqres.full
diff --git a/tests/xfs/251 b/tests/xfs/251
index 0b090180..1efa331d 100755
--- a/tests/xfs/251
+++ b/tests/xfs/251
@@ -36,6 +36,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
$XFS_IO_PROG -c "cowextsize $((blksz * 16))" $testdir >> $seqres.full
diff --git a/tests/xfs/254 b/tests/xfs/254
index 40d176fc..d08ccc52 100755
--- a/tests/xfs/254
+++ b/tests/xfs/254
@@ -37,6 +37,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
$XFS_IO_PROG -c "cowextsize $((blksz * 16))" $testdir >> $seqres.full
diff --git a/tests/xfs/255 b/tests/xfs/255
index 255f3b2f..8ec6f0be 100755
--- a/tests/xfs/255
+++ b/tests/xfs/255
@@ -36,6 +36,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
$XFS_IO_PROG -c "cowextsize $((blksz * 16))" $testdir >> $seqres.full
diff --git a/tests/xfs/256 b/tests/xfs/256
index 1c703242..7157d532 100755
--- a/tests/xfs/256
+++ b/tests/xfs/256
@@ -37,6 +37,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
$XFS_IO_PROG -c "cowextsize $((blksz * 16))" $testdir >> $seqres.full
diff --git a/tests/xfs/257 b/tests/xfs/257
index 6a58f0ac..c3100d60 100755
--- a/tests/xfs/257
+++ b/tests/xfs/257
@@ -38,6 +38,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
$XFS_IO_PROG -c "cowextsize $((blksz * 16))" $testdir >> $seqres.full
diff --git a/tests/xfs/258 b/tests/xfs/258
index 2865cdf9..a3a130ea 100755
--- a/tests/xfs/258
+++ b/tests/xfs/258
@@ -39,6 +39,7 @@ mkdir $testdir
echo "Create the original files"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=64
filesize=$((blksz * nr))
$XFS_IO_PROG -c "cowextsize $((blksz * 16))" $testdir >> $seqres.full
diff --git a/tests/xfs/264.out b/tests/xfs/264.out
index 502e72d3..e45ac5a5 100644
--- a/tests/xfs/264.out
+++ b/tests/xfs/264.out
@@ -2,20 +2,20 @@ QA output created by 264
=== Test EIO/max_retries ===
error/fail_at_unmount=1
error/metadata/default/max_retries=-1
-error/metadata/default/retry_timeout_seconds=0
+error/metadata/default/retry_timeout_seconds=-1
error/metadata/EIO/max_retries=-1
-error/metadata/EIO/retry_timeout_seconds=0
+error/metadata/EIO/retry_timeout_seconds=-1
error/metadata/ENOSPC/max_retries=-1
-error/metadata/ENOSPC/retry_timeout_seconds=0
+error/metadata/ENOSPC/retry_timeout_seconds=-1
error/fail_at_unmount=0
error/metadata/EIO/max_retries=1
=== Test EIO/retry_timeout_seconds ===
error/fail_at_unmount=1
error/metadata/default/max_retries=-1
-error/metadata/default/retry_timeout_seconds=0
+error/metadata/default/retry_timeout_seconds=-1
error/metadata/EIO/max_retries=-1
-error/metadata/EIO/retry_timeout_seconds=0
+error/metadata/EIO/retry_timeout_seconds=-1
error/metadata/ENOSPC/max_retries=-1
-error/metadata/ENOSPC/retry_timeout_seconds=0
+error/metadata/ENOSPC/retry_timeout_seconds=-1
error/fail_at_unmount=0
error/metadata/EIO/retry_timeout_seconds=1
diff --git a/tests/xfs/270 b/tests/xfs/270
index b740c379..7447ce87 100755
--- a/tests/xfs/270
+++ b/tests/xfs/270
@@ -47,8 +47,10 @@ _scratch_xfs_set_metadata_field "features_ro_compat" "$ro_compat" "sb 0" \
new_ro_compat=$(_scratch_xfs_get_metadata_field "features_ro_compat" "sb 0" \
2>/dev/null)
-# verify the new ro_compat field is correct.
-if [ $new_ro_compat != $ro_compat ]; then
+# verify the new ro_compat field is correct. Without xfsprogs commit
+# f4afdcb0ad ("xfs_db: clean up the salvage read callsites in set_cur()"),
+# we can't get new_ro_compat value.
+if [ "$new_ro_compat" != "$ro_compat" ]; then
echo "Unable to set new features_ro_compat. Wanted $ro_compat, got $new_ro_compat"
fi
diff --git a/tests/xfs/280 b/tests/xfs/280
index bc26e629..0d9a7958 100755
--- a/tests/xfs/280
+++ b/tests/xfs/280
@@ -30,6 +30,7 @@ mkdir $testdir
blocks=5
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
sz=$((blocks * blksz))
echo "Create the original files"
diff --git a/tests/xfs/288 b/tests/xfs/288
index e3d230e9..aa664a26 100755
--- a/tests/xfs/288
+++ b/tests/xfs/288
@@ -8,7 +8,7 @@
# that leaf directly (as xfsprogs commit f714016).
#
. ./common/preamble
-_begin_fstest auto quick repair fuzzers
+_begin_fstest auto quick repair fuzzers attr
# Import common functions.
. ./common/filter
@@ -50,25 +50,19 @@ if [ "$count" != "0" ]; then
_notrun "xfs_db can't set attr hdr.count to 0"
fi
-# make sure xfs_repair can find above corruption. If it can't, that
-# means we need to fix this bug on current xfs_repair
-_scratch_xfs_repair -n >> $seqres.full 2>&1
-if [ $? -eq 0 ];then
- _fail "xfs_repair can't find the corruption"
-else
- # If xfs_repair can find this corruption, then this repair
- # should junk above leaf attribute and fix this XFS.
- _scratch_xfs_repair >> $seqres.full 2>&1
+# Check that xfs_repair discards the attr fork if block 0 is an empty leaf
+# block. Empty leaf blocks at the start of the xattr data can be a byproduct
+# of a shutdown race, and hence are not a corruption.
+_scratch_xfs_repair >> $seqres.full 2>&1
- # Old xfs_repair maybe find and fix this corruption by
- # reset the first used heap value and the usedbytes cnt
- # in ablock 0. That's not what we want. So check if
- # xfs_repair has junked the whole ablock 0 by xfs_db.
- _scratch_xfs_db -x -c "inode $inum" -c "ablock 0" | \
- grep -q "no attribute data"
- if [ $? -ne 0 ]; then
- _fail "xfs_repair didn't junk the empty attr leaf"
- fi
+# Old xfs_repair maybe find and fix this corruption by
+# reset the first used heap value and the usedbytes cnt
+# in ablock 0. That's not what we want. So check if
+# xfs_repair has junked the whole ablock 0 by xfs_db.
+_scratch_xfs_db -x -c "inode $inum" -c "ablock 0" | \
+ grep -q "no attribute data"
+if [ $? -ne 0 ]; then
+ _fail "xfs_repair didn't junk the empty attr leaf"
fi
echo "Silence is golden"
diff --git a/tests/xfs/291 b/tests/xfs/291
index 6d5e247e..a2425e47 100755
--- a/tests/xfs/291
+++ b/tests/xfs/291
@@ -93,11 +93,7 @@ _scratch_xfs_check >> $seqres.full 2>&1 || _fail "xfs_check failed"
# Can xfs_metadump cope with this monster?
_scratch_xfs_metadump $tmp.metadump || _fail "xfs_metadump failed"
xfs_mdrestore $tmp.metadump $tmp.img || _fail "xfs_mdrestore failed"
-[ "$USE_EXTERNAL" = yes ] && [ -n "$SCRATCH_RTDEV" ] && \
- rt_repair_opts="-r $SCRATCH_RTDEV"
-[ "$USE_EXTERNAL" = yes ] && [ -n "$SCRATCH_LOGDEV" ] && \
- log_repair_opts="-l $SCRATCH_LOGDEV"
-$XFS_REPAIR_PROG $rt_repair_opts $log_repair_opts -f $tmp.img >> $seqres.full 2>&1 || \
+SCRATCH_DEV=$tmp.img _scratch_xfs_repair -f &>> $seqres.full || \
_fail "xfs_repair of metadump failed"
# Yes it can; success, all done
diff --git a/tests/xfs/312 b/tests/xfs/312
index 94f868fe..e4884787 100755
--- a/tests/xfs/312
+++ b/tests/xfs/312
@@ -36,6 +36,7 @@ sz=$((blksz * blks))
echo "Format filesystem"
_scratch_mkfs >/dev/null 2>&1
_scratch_mount >> $seqres.full
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
echo "Create files"
_pwrite_byte 0x66 0 $sz $SCRATCH_MNT/file1 >> $seqres.full
diff --git a/tests/xfs/315 b/tests/xfs/315
index 105515ab..9f6b39c8 100755
--- a/tests/xfs/315
+++ b/tests/xfs/315
@@ -37,6 +37,7 @@ sz=$((blksz * blks))
echo "Format filesystem"
_scratch_mkfs >/dev/null 2>&1
_scratch_mount >> $seqres.full
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
$XFS_IO_PROG -c "cowextsize $sz" $SCRATCH_MNT
diff --git a/tests/xfs/322 b/tests/xfs/322
index 89a2f741..a2c3720e 100755
--- a/tests/xfs/322
+++ b/tests/xfs/322
@@ -36,6 +36,7 @@ sz=$((blksz * blks))
echo "Format filesystem"
_scratch_mkfs >/dev/null 2>&1
_scratch_mount >> $seqres.full
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
echo "Create files"
_pwrite_byte 0x66 0 $sz $SCRATCH_MNT/file1 >> $seqres.full
diff --git a/tests/xfs/326 b/tests/xfs/326
index 8b95a18a..d8a9ac25 100755
--- a/tests/xfs/326
+++ b/tests/xfs/326
@@ -40,6 +40,7 @@ echo "Format filesystem"
_scratch_mkfs >/dev/null 2>&1
_scratch_mount >> $seqres.full
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
$XFS_IO_PROG -c "cowextsize $sz" $SCRATCH_MNT
echo "Create files"
diff --git a/tests/xfs/329 b/tests/xfs/329
index e9a30d05..4cad686c 100755
--- a/tests/xfs/329
+++ b/tests/xfs/329
@@ -31,6 +31,7 @@ _scratch_mount >> "$seqres.full" 2>&1
testdir="$SCRATCH_MNT/test-$seq"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
blks=3
mkdir "$testdir"
diff --git a/tests/xfs/346 b/tests/xfs/346
index bb542202..6d371342 100755
--- a/tests/xfs/346
+++ b/tests/xfs/346
@@ -34,6 +34,7 @@ testdir=$SCRATCH_MNT/test-$seq
mkdir $testdir
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=128
filesize=$((blksz * nr))
bufnr=8
diff --git a/tests/xfs/347 b/tests/xfs/347
index 63ee1ec6..86f405b5 100755
--- a/tests/xfs/347
+++ b/tests/xfs/347
@@ -33,6 +33,7 @@ testdir=$SCRATCH_MNT/test-$seq
mkdir $testdir
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
nr=128
filesize=$((blksz * nr))
bufnr=8
diff --git a/tests/xfs/432 b/tests/xfs/432
index 86012f0b..e1e610d0 100755
--- a/tests/xfs/432
+++ b/tests/xfs/432
@@ -89,7 +89,8 @@ _scratch_xfs_metadump $metadump_file -w
xfs_mdrestore $metadump_file $metadump_img
echo "Check restored metadump image"
-$XFS_REPAIR_PROG -n $metadump_img >> $seqres.full 2>&1
+SCRATCH_DEV=$metadump_img _scratch_xfs_repair -n &>> $seqres.full || \
+ echo "xfs_repair on restored fs returned $?"
# success, all done
status=0
diff --git a/tests/xfs/436 b/tests/xfs/436
index d99183cf..9e6ec937 100755
--- a/tests/xfs/436
+++ b/tests/xfs/436
@@ -42,6 +42,7 @@ _scratch_mount -o noquota >> "$seqres.full" 2>&1
testdir="$SCRATCH_MNT/test-$seq"
blksz=65536
+_require_congruent_file_oplen $SCRATCH_MNT $blksz
blks=3
mkdir "$testdir"
diff --git a/tests/xfs/507 b/tests/xfs/507
index b9c9ab29..8757152e 100755
--- a/tests/xfs/507
+++ b/tests/xfs/507
@@ -44,6 +44,9 @@ echo "Format and mount"
_scratch_mkfs > "$seqres.full" 2>&1
_scratch_mount
+fs_blksz=$(_get_block_size $SCRATCH_MNT)
+_require_congruent_file_oplen $SCRATCH_MNT $((MAXEXTLEN * fs_blksz))
+
# Create a huge sparse filesystem on the scratch device because that's what
# we're going to need to guarantee that we have enough blocks to overflow in
# the first place. We need to have at least enough free space on that huge fs
diff --git a/tests/xfs/533 b/tests/xfs/533
new file mode 100755
index 00000000..31858cc9
--- /dev/null
+++ b/tests/xfs/533
@@ -0,0 +1,40 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2022 FUJITSU LIMITED. All rights reserved.
+#
+# FS QA Test 533
+#
+# Regression test for xfsprogs commit
+# f4afdcb0ad11 ("xfs_db: clean up the salvage read callsites in set_cur()")
+#
+# This case test xfs_db whether can get the new magicnum field value even we
+# just have corrupted this field value.
+#
+
+. ./common/preamble
+_begin_fstest auto quick db
+
+# real QA test starts here
+_supported_fs xfs
+_fixed_by_git_commit xfsprogs f4afdcb0ad11 \
+ "xfs_db: clean up the salvage read callsites in set_cur()"
+#skip fs check because invalid superblock 1
+_require_scratch_nocheck
+
+# The error messages in the golden output come from the V5 superblock verifier
+# routines, so ignore V4 filesystems.
+_require_scratch_xfs_crc
+
+_scratch_mkfs_xfs >>$seqres.full 2>&1
+
+# write the bad magicnum field value(0) to the superblock 1
+_scratch_xfs_set_metadata_field "magicnum" "0" "sb 1"
+
+# Even magicnum field has been corrupted, we still can read this field value.
+# The error message changed in xfsprogs 5.19.
+_scratch_xfs_get_metadata_field "magicnum" "sb 1" 2>&1 | \
+ sed -e 's/Superblock has bad magic number 0x0. Not an XFS filesystem?/bad magic number/g'
+
+# success, all done
+status=0
+exit
diff --git a/tests/xfs/533.out b/tests/xfs/533.out
new file mode 100644
index 00000000..7deb78a3
--- /dev/null
+++ b/tests/xfs/533.out
@@ -0,0 +1,5 @@
+QA output created by 533
+Allowing write of corrupted data with good CRC
+magicnum = 0
+bad magic number
+0
diff --git a/tests/xfs/537 b/tests/xfs/537
index 7d7776f7..a31652cd 100755
--- a/tests/xfs/537
+++ b/tests/xfs/537
@@ -29,7 +29,7 @@ echo "Format and mount fs"
_scratch_mkfs >> $seqres.full
_scratch_mount >> $seqres.full
-bsize=$(_get_block_size $SCRATCH_MNT)
+bsize=$(_get_file_block_size $SCRATCH_MNT)
srcfile=${SCRATCH_MNT}/srcfile
donorfile=${SCRATCH_MNT}/donorfile
diff --git a/tests/xfs/547 b/tests/xfs/547
index 9d4216ca..60121eb9 100755
--- a/tests/xfs/547
+++ b/tests/xfs/547
@@ -33,6 +33,10 @@ for nrext64 in 0 1; do
>> $seqres.full
_scratch_mount >> $seqres.full
+ # Force data device extents so that we can fragment the free space
+ # and force attr fork allocations to be non-contiguous
+ _xfs_force_bdev data $SCRATCH_MNT
+
bsize=$(_get_file_block_size $SCRATCH_MNT)
testfile=$SCRATCH_MNT/testfile
@@ -76,13 +80,15 @@ for nrext64 in 0 1; do
acnt=$(_scratch_xfs_get_metadata_field core.naextents \
"path /$(basename $testfile)")
- if (( $dcnt != 10 )); then
- echo "Invalid data fork extent count: $dextcnt"
+ echo "nrext64: $nrext64 dcnt: $dcnt acnt: $acnt" >> $seqres.full
+
+ if [ -z "$dcnt" ] || (( $dcnt != 10 )); then
+ echo "Invalid data fork extent count: $dcnt"
exit 1
fi
- if (( $acnt < 10 )); then
- echo "Invalid attr fork extent count: $aextcnt"
+ if [ -z "$acnt" ] || (( $acnt < 10 )); then
+ echo "Invalid attr fork extent count: $acnt"
exit 1
fi
done
diff --git a/tests/xfs/549 b/tests/xfs/549
new file mode 100755
index 00000000..925ca993
--- /dev/null
+++ b/tests/xfs/549
@@ -0,0 +1,29 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2022 FUJITSU LIMITED. All rights reserved.
+#
+# FS QA Test No. 549
+#
+# Regression test for xfsprogs commit
+# 50dba8189b1f ("mkfs: terminate getsubopt arrays properly")
+#
+# This case test mkfs.xfs whether can terminate getsubopt arrays properly.
+# If not, it will trigger segmentation fault.
+#
+
+. ./common/preamble
+_begin_fstest auto quick mkfs
+
+# real QA test starts here
+_supported_fs xfs
+_fixed_by_git_commit xfsprogs 50dba8189b1f \
+ "mkfs: terminate getsubopt arrays properly"
+_require_test
+
+$MKFS_XFS_PROG -f -d agcount=4 -d garbage=0 >> $seqres.full 2>&1
+
+echo "Silence is golden"
+
+# success, all done
+status=0
+exit
diff --git a/tests/xfs/549.out b/tests/xfs/549.out
new file mode 100644
index 00000000..4e3acd3f
--- /dev/null
+++ b/tests/xfs/549.out
@@ -0,0 +1,2 @@
+QA output created by 549
+Silence is golden
diff --git a/tests/xfs/550 b/tests/xfs/550
new file mode 100755
index 00000000..87ae4110
--- /dev/null
+++ b/tests/xfs/550
@@ -0,0 +1,50 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2022 Fujitsu Limited. All Rights Reserved.
+#
+# FS QA Test No. 550
+#
+# Test memory failure mechanism when dax enabled
+#
+. ./common/preamble
+_begin_fstest auto quick dax
+
+# Import common functions.
+. ./common/filter
+. ./common/reflink
+
+# real QA test starts here
+_require_check_dmesg
+_require_scratch_reflink
+_require_cp_reflink
+_require_xfs_scratch_rmapbt
+_require_scratch_dax_mountopt "dax"
+_require_test_program "t_mmap_cow_memory_failure"
+
+echo "Format and mount"
+_scratch_mkfs > $seqres.full 2>&1
+_scratch_mount "-o dax" >> $seqres.full 2>&1
+
+testdir=$SCRATCH_MNT/test-$seq
+mkdir $testdir
+
+echo "Create the original files"
+filesize=65536
+_pwrite_byte 0x61 0 $filesize $testdir/testfile >> $seqres.full
+_scratch_cycle_mount "dax"
+
+echo "Inject memory failure (1 page)"
+# create two processes:
+# process1: mread 1 page to cause page fault, and wait
+# process2: mread 1 page to cause page fault, then inject poison on this page
+$here/src/t_mmap_cow_memory_failure -s1 -S1 -R $testdir/testfile -P $testdir/testfile
+
+echo "Inject memory failure (2 pages)"
+$here/src/t_mmap_cow_memory_failure -s2 -S2 -R $testdir/testfile -P $testdir/testfile
+
+_check_dmesg_for "Sending SIGBUS to t_mmap_cow_memo" || echo "Memory failure didn't kill the process"
+_check_dmesg_for "recovery action for dax page: Recovered" || echo "Failured page didn't recovered"
+
+# success, all done
+status=0
+exit
diff --git a/tests/xfs/550.out b/tests/xfs/550.out
new file mode 100644
index 00000000..80e3223c
--- /dev/null
+++ b/tests/xfs/550.out
@@ -0,0 +1,9 @@
+QA output created by 550
+Format and mount
+Create the original files
+Inject memory failure (1 page)
+Inject poison...
+Process is killed by signal: 7
+Inject memory failure (2 pages)
+Inject poison...
+Process is killed by signal: 7
diff --git a/tests/xfs/551 b/tests/xfs/551
new file mode 100755
index 00000000..f4af72ed
--- /dev/null
+++ b/tests/xfs/551
@@ -0,0 +1,51 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2022 Fujitsu Limited. All Rights Reserved.
+#
+# FS QA Test No. 551
+#
+# Test memory failure mechanism when dax and reflink working together
+#
+. ./common/preamble
+_begin_fstest auto quick clone dax
+
+# Import common functions.
+. ./common/filter
+. ./common/reflink
+
+# real QA test starts here
+_require_check_dmesg
+_require_scratch_reflink
+_require_cp_reflink
+_require_xfs_scratch_rmapbt
+_require_scratch_dax_mountopt "dax"
+_require_test_program "t_mmap_cow_memory_failure"
+
+echo "Format and mount"
+_scratch_mkfs > $seqres.full 2>&1
+_scratch_mount "-o dax" >> $seqres.full 2>&1
+
+testdir=$SCRATCH_MNT/test-$seq
+mkdir $testdir
+
+echo "Create the original files"
+filesize=65536
+_pwrite_byte 0x61 0 $filesize $testdir/testfile >> $seqres.full
+_cp_reflink $testdir/testfile $testdir/poisonfile >> $seqres.full
+_scratch_cycle_mount "dax"
+
+echo "Inject memory failure (1 page)"
+# create two processes:
+# process1: mread 1 page to cause page fault, and wait
+# process2: mread 1 page to cause page fault, then inject poison on this page
+$here/src/t_mmap_cow_memory_failure -s1 -S1 -R $testdir/testfile -P $testdir/poisonfile
+
+echo "Inject memory failure (2 pages)"
+$here/src/t_mmap_cow_memory_failure -s2 -S2 -R $testdir/testfile -P $testdir/poisonfile
+
+_check_dmesg_for "Sending SIGBUS to t_mmap_cow_memo" || echo "Memory failure didn't kill the process"
+_check_dmesg_for "recovery action for dax page: Recovered" || echo "Failured page didn't recovered"
+
+# success, all done
+status=0
+exit
diff --git a/tests/xfs/551.out b/tests/xfs/551.out
new file mode 100644
index 00000000..6dc8533f
--- /dev/null
+++ b/tests/xfs/551.out
@@ -0,0 +1,9 @@
+QA output created by 551
+Format and mount
+Create the original files
+Inject memory failure (1 page)
+Inject poison...
+Process is killed by signal: 7
+Inject memory failure (2 pages)
+Inject poison...
+Process is killed by signal: 7
diff --git a/tests/xfs/552 b/tests/xfs/552
new file mode 100755
index 00000000..172ed206
--- /dev/null
+++ b/tests/xfs/552
@@ -0,0 +1,54 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2022 Fujitsu Limited. All Rights Reserved.
+#
+# FS QA Test No. 552
+#
+# Test memory failure mechanism when dax and reflink working together
+# test for partly reflinked file
+#
+. ./common/preamble
+_begin_fstest auto quick clone dax
+
+# Import common functions.
+. ./common/filter
+. ./common/reflink
+
+# real QA test starts here
+_require_check_dmesg
+_require_scratch_reflink
+_require_xfs_scratch_rmapbt
+_require_scratch_dax_mountopt "dax"
+_require_test_program "t_mmap_cow_memory_failure"
+
+echo "Format and mount"
+_scratch_mkfs > $seqres.full 2>&1
+_scratch_mount "-o dax" >> $seqres.full 2>&1
+
+testdir=$SCRATCH_MNT/test-$seq
+mkdir $testdir
+
+echo "Create the original files"
+nr=16
+blksz=$(get_page_size)
+_pwrite_byte 0x61 0 $((blksz * nr)) $testdir/testfile >> $seqres.full
+_pwrite_byte 0x62 0 $((blksz * nr)) $testdir/poisonfile >> $seqres.full
+seq 0 2 $((nr - 1)) | while read i; do
+ _reflink_range $testdir/testfile $((blksz * i)) \
+ $testdir/poisonfile $((blksz * i)) $blksz >> $seqres.full
+done
+_scratch_cycle_mount "dax"
+
+echo "Inject memory failure (1 page)"
+$here/src/t_mmap_cow_memory_failure -s1 -S1 -R $testdir/testfile -P $testdir/poisonfile
+
+echo "Inject memory failure (2 pages)"
+# poison on reflinked page and not reflinked page
+$here/src/t_mmap_cow_memory_failure -s2 -S2 -R $testdir/testfile -P $testdir/poisonfile
+
+_check_dmesg_for "Sending SIGBUS to t_mmap_cow_memo" || echo "Memory failure didn't kill the process"
+_check_dmesg_for "recovery action for dax page: Recovered" || echo "Failured page didn't recovered"
+
+# success, all done
+status=0
+exit
diff --git a/tests/xfs/552.out b/tests/xfs/552.out
new file mode 100644
index 00000000..fac36801
--- /dev/null
+++ b/tests/xfs/552.out
@@ -0,0 +1,9 @@
+QA output created by 552
+Format and mount
+Create the original files
+Inject memory failure (1 page)
+Inject poison...
+Process is killed by signal: 7
+Inject memory failure (2 pages)
+Inject poison...
+Process is killed by signal: 7
diff --git a/tests/xfs/553 b/tests/xfs/553
new file mode 100755
index 00000000..e98c04ed
--- /dev/null
+++ b/tests/xfs/553
@@ -0,0 +1,67 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2022 Oracle. All Rights Reserved.
+#
+# FS QA Test 553
+#
+# Test to check if a direct write on a delalloc extent present in CoW fork can
+# result in an ENOSPC error.
+#
+. ./common/preamble
+_begin_fstest auto quick clone
+
+# Import common functions.
+. ./common/reflink
+. ./common/inject
+
+# real QA test starts here
+_supported_fs xfs
+_fixed_by_kernel_commit d62113303d691 \
+ "xfs: Fix false ENOSPC when performing direct write on a delalloc extent in cow fork"
+_require_scratch_reflink
+_require_xfs_debug
+_require_test_program "punch-alternating"
+_require_xfs_io_error_injection "bmap_alloc_minlen_extent"
+_require_xfs_io_command "reflink"
+_require_xfs_io_command "cowextsize"
+
+source=${SCRATCH_MNT}/source
+destination=${SCRATCH_MNT}/destination
+fragmented_file=${SCRATCH_MNT}/fragmented_file
+
+echo "Format and mount fs"
+_scratch_mkfs >> $seqres.full
+_scratch_mount >> $seqres.full
+
+blksz=$(_get_file_block_size $SCRATCH_MNT)
+
+echo "Create source file"
+$XFS_IO_PROG -f -c "pwrite 0 $((blksz * 8192))" $source >> $seqres.full
+
+echo "Reflink destination file with source file"
+$XFS_IO_PROG -f -c "reflink $source" $destination >> $seqres.full
+
+echo "Set destination file's cowextsize to 4096 blocks"
+$XFS_IO_PROG -c "cowextsize $((blksz * 4096))" $destination >> $seqres.full
+
+echo "Fragment FS"
+$XFS_IO_PROG -f -c "pwrite 0 $((blksz * 16384))" $fragmented_file \
+ >> $seqres.full
+sync
+$here/src/punch-alternating $fragmented_file >> $seqres.full
+
+echo "Inject bmap_alloc_minlen_extent error tag"
+_scratch_inject_error bmap_alloc_minlen_extent 1
+
+echo "Create delalloc extent of length 4096 blocks in destination file's CoW fork"
+$XFS_IO_PROG -c "pwrite 0 $blksz" $destination >> $seqres.full
+
+sync
+
+echo "Direct I/O write at 3rd block in destination file"
+$XFS_IO_PROG -d -c "pwrite $((blksz * 3)) $((blksz * 2))" $destination \
+ >> $seqres.full
+
+# success, all done
+status=0
+exit
diff --git a/tests/xfs/553.out b/tests/xfs/553.out
new file mode 100644
index 00000000..9f5679de
--- /dev/null
+++ b/tests/xfs/553.out
@@ -0,0 +1,9 @@
+QA output created by 553
+Format and mount fs
+Create source file
+Reflink destination file with source file
+Set destination file's cowextsize to 4096 blocks
+Fragment FS
+Inject bmap_alloc_minlen_extent error tag
+Create delalloc extent of length 4096 blocks in destination file's CoW fork
+Direct I/O write at 3rd block in destination file