#! /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

# Import common functions.
. ./common/filter

# real QA test starts here
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 }"
}

# Modify as appropriate.
_supported_fs btrfs
_require_scratch
# 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
