| #! /bin/bash |
| # SPDX-License-Identifier: GPL-2.0 |
| # Copyright (C) 2020 SUSE Linux Products GmbH. All Rights Reserved. |
| # |
| # FS QA Test 215 |
| # |
| # Test that reading corrupted files would correctly increment device status |
| # counters. This is fixed by the following linux kernel commit: |
| # 814723e0a55a ("btrfs: increment device corruption error in case of checksum error") |
| # |
| . ./common/preamble |
| _begin_fstest auto quick read_repair |
| |
| . ./common/filter |
| |
| get_physical() |
| { |
| $BTRFS_UTIL_PROG inspect-internal dump-tree -t 3 $SCRATCH_DEV | \ |
| grep $1 -A2 | \ |
| $AWK_PROG "(\$1 ~ /stripe/ && \$3 ~ /devid/ && \$2 ~ /0/) { print \$6 }" |
| } |
| |
| _require_scratch |
| # No data checksums for NOCOW case, so can't detect corruption and repair data. |
| _require_btrfs_no_nodatacow |
| # Overwriting data is forbidden on a zoned block device |
| _require_non_zoned_device $SCRATCH_DEV |
| |
| _scratch_mkfs > /dev/null |
| # disable freespace inode to ensure file is the first thing in the data |
| # blobk group |
| _scratch_mount $(_btrfs_no_v1_cache_opt) |
| |
| pagesize=$(_get_page_size) |
| blocksize=$(_get_block_size $SCRATCH_MNT) |
| |
| # For subpage case, since we still do read in full page size, if have 8 corrupted |
| # sectors in one page, then even we just try to read one sector of that page, |
| # all 8 corruption will be reported. |
| # So here we chose the filesize using page size. |
| filesize=$((8*$pagesize)) |
| if [ $blocksize -le $pagesize ]; then |
| sectors_per_page=$(($pagesize / $blocksize)) |
| else |
| # We don't support multi-page sectorsize yet |
| _notrun "this test doesn't support sectorsize $blocksize with page size $pagesize yet" |
| fi |
| |
| uuid=$(findmnt -n -o UUID "$SCRATCH_MNT") |
| |
| if [ ! -e /sys/fs/btrfs/$uuid/bdi ]; then |
| _notrun "bdi link not found" |
| fi |
| |
| #create an 8 block file |
| $XFS_IO_PROG -d -f -c "pwrite -S 0xbb -b $filesize 0 $filesize" "$SCRATCH_MNT/foobar" > /dev/null |
| |
| logical_extent=$(_btrfs_get_first_logical $SCRATCH_MNT/foobar) |
| physical_extent=$(get_physical $logical_extent) |
| |
| echo "logical = $logical_extent physical=$physical_extent" >> $seqres.full |
| |
| # corrupt first 4 blocks of file |
| _scratch_unmount |
| $XFS_IO_PROG -d -c "pwrite -S 0xaa -b $pagesize $physical_extent $((4 * $pagesize))" $SCRATCH_DEV > /dev/null |
| _scratch_mount |
| |
| # disable readahead to avoid skewing the counter |
| echo 0 > /sys/fs/btrfs/$uuid/bdi/read_ahead_kb |
| |
| # buffered reads whould result in 2 * sectors_per_page errors since readahead code always submits |
| # at least 1 page worth of IO and it will be counted as error(s) as well |
| $XFS_IO_PROG -c "pread -b $filesize 0 $filesize" "$SCRATCH_MNT/foobar" > /dev/null 2>&1 |
| errs=$($BTRFS_UTIL_PROG device stats $SCRATCH_DEV | $AWK_PROG '/corruption_errs/ { print $2 }') |
| if [ $errs -ne $((2 * $sectors_per_page)) ]; then |
| _fail "Errors: $errs expected: 2" |
| fi |
| |
| # DIO does check every sector |
| $XFS_IO_PROG -d -c "pread -b $filesize 0 $filesize" "$SCRATCH_MNT/foobar" > /dev/null 2>&1 |
| errs=$($BTRFS_UTIL_PROG device stats $SCRATCH_DEV | $AWK_PROG '/corruption_errs/ { print $2 }') |
| if [ $errs -ne $((6 * $sectors_per_page)) ]; then |
| _fail "Errors: $errs expected: 6" |
| fi |
| |
| # success, all done |
| echo "Silence is golden" |
| status=0 |
| exit |