@@ -580,3 +580,8 @@ _btrfs_buffered_read_on_mirror()
:
done
}
+
+_require_btrfs_corrupt_block()
+{
+ _require_command "$BTRFS_CORRUPT_BLOCK_PROG" btrfs-corrupt-block
+}
@@ -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"
@@ -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
@@ -145,6 +155,9 @@ _require_fsverity_dump_metadata()
_require_fsverity_corruption()
{
_require_xfs_io_command "fiemap"
+ if [ $FSTYP == "btrfs" ]; then
+ _require_btrfs_corrupt_block
+ fi
}
_scratch_mkfs_verity()
@@ -153,6 +166,9 @@ _scratch_mkfs_verity()
ext4|f2fs)
_scratch_mkfs -O verity
;;
+ btrfs)
+ _scratch_mkfs
+ ;;
*)
_notrun "No verity support for $FSTYP"
;;
@@ -314,6 +330,21 @@ _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"
;;
@@ -126,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
@@ -136,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
@@ -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