mirror of
https://github.com/linux-apfs/apfstests.git
synced 2026-05-01 15:01:44 -07:00
a1c91630a3
The test creates a subshell that keeps running the 'cat' command
against a test file in an infinite loop, and after it kills the
subshell it unmounts the filesystem, after which point any 'cat'
subcommand that runs after or at that time will fail resulting in an
unexpected golden output:
$ ./check btrfs/081
btrfs/081 3s ... - output mismatch (see /home/fdmanana/git/hub/xfstests/results//btrfs/081.out.bad)
--- tests/btrfs/081.out 2018-09-16 21:30:48.501104179 +0100
+++ /home/fdmanana/git/hub/xfstests/results//btrfs/081.out.bad 2019-01-24 20:36:18.989746185 +0000
@@ -206,5 +206,6 @@
Verifying file digests after cloning
14968c092c68e32fa35e776392d14523 SCRATCH_MNT/foo
14968c092c68e32fa35e776392d14523 SCRATCH_MNT/bar
+cat: /mnt/scratch/bar: No such file or directory
Verifying target file digest after umount + mount
14968c092c68e32fa35e776392d14523 SCRATCH_MNT/bar
...
(Run 'diff -u /home/fdmanana/git/hub/xfstests/tests/btrfs/081.out /home/fdmanana/git/hub/xfstests/results//btrfs/081.out.bad' to see the entire diff)
Ran: btrfs/081
Failures: btrfs/081
Failed 1 of 1 tests
Fix that by adding a proper trap to the reader loop function so that
the subshell waits for executed 'cat' commands when it receives
SIGTERM.
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: Eryu Guan <guaneryu@gmail.com>
Signed-off-by: Eryu Guan <guaneryu@gmail.com>
124 lines
3.4 KiB
Bash
Executable File
124 lines
3.4 KiB
Bash
Executable File
#! /bin/bash
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
# Copyright (C) 2014 SUSE Linux Products GmbH. All Rights Reserved.
|
|
#
|
|
# FSQA Test No. 081
|
|
#
|
|
# Regression test for a btrfs clone ioctl issue where races between
|
|
# a clone operation and concurrent target file reads would result in
|
|
# leaving stale data in the page cache. After the clone operation
|
|
# finished, reading from the clone target file would return the old
|
|
# and no longer valid data. This affected only buffered reads (i.e.
|
|
# didn't affect direct IO reads).
|
|
#
|
|
# This issue was fixed by the following linux kernel patch:
|
|
#
|
|
# Btrfs: ensure readers see new data after a clone operation
|
|
# (commit c125b8bff1d9f6c8c91ce4eb8bd5616058c7d510)
|
|
#
|
|
seq=`basename $0`
|
|
seqres=$RESULT_DIR/$seq
|
|
echo "QA output created by $seq"
|
|
tmp=/tmp/$$
|
|
status=1 # failure is the default!
|
|
trap "_cleanup; exit \$status" 0 1 2 3 15
|
|
|
|
_cleanup()
|
|
{
|
|
rm -f $tmp.*
|
|
}
|
|
|
|
# get standard environment, filters and checks
|
|
. ./common/rc
|
|
. ./common/filter
|
|
|
|
# real QA test starts here
|
|
_supported_fs btrfs
|
|
_supported_os Linux
|
|
_require_scratch
|
|
_require_cloner
|
|
|
|
rm -f $seqres.full
|
|
|
|
num_extents=100
|
|
extent_size=8192
|
|
|
|
create_source_file()
|
|
{
|
|
local name=$1
|
|
|
|
# Create a file with $num_extents extents, each with a size of
|
|
# $extent_size bytes.
|
|
touch $SCRATCH_MNT/$name
|
|
for ((i = 0; i < $num_extents; i++)); do
|
|
off=$((i * $extent_size))
|
|
$XFS_IO_PROG \
|
|
-c "pwrite -S $i -b $extent_size $off $extent_size" \
|
|
-c "fsync" $SCRATCH_MNT/$name | _filter_xfs_io
|
|
done
|
|
}
|
|
|
|
create_target_file()
|
|
{
|
|
local name=$1
|
|
local file_size=$(($num_extents * $extent_size))
|
|
|
|
$XFS_IO_PROG -f -c "pwrite -S 0xff 0 $file_size" \
|
|
-c "fsync" $SCRATCH_MNT/$name | _filter_xfs_io
|
|
}
|
|
|
|
reader_loop()
|
|
{
|
|
# Wait for any running 'cat' subcommand before exitting so that after
|
|
# the test kills the reader loop subshell it does not fail with an
|
|
# error message from a 'cat' subcommand due to the test file being
|
|
# temporarily unavailable due to the scratch fs unmount operation.
|
|
trap "wait; exit" SIGTERM
|
|
|
|
local name=$1
|
|
|
|
while true; do
|
|
cat $SCRATCH_MNT/$name > /dev/null
|
|
done
|
|
}
|
|
|
|
_scratch_mkfs >>$seqres.full 2>&1
|
|
_scratch_mount
|
|
|
|
echo "Creating source file..."
|
|
create_source_file "foo"
|
|
echo "Creating target file..."
|
|
create_target_file "bar"
|
|
|
|
reader_loop "bar" &
|
|
reader_pid=$!
|
|
|
|
$CLONER_PROG -s 0 -d 0 -l $(($num_extents * $extent_size)) \
|
|
$SCRATCH_MNT/foo $SCRATCH_MNT/bar
|
|
|
|
kill $reader_pid > /dev/null 2>&1
|
|
|
|
# Now both foo and bar should have exactly the same content.
|
|
# This didn't use to be the case before the btrfs kernel fix mentioned
|
|
# above. The clone ioctl was racy, as it removed bar's pages from the
|
|
# page cache and only after it would update bar's metadata to point to
|
|
# the same extents that foo's metadata points to - and this was done in
|
|
# an unprotected way, so that a file read request done right after the
|
|
# clone ioctl removed the pages from the page cache and before it updated
|
|
# bar's metadata, would result in populating the page cache with stale
|
|
# data. Therefore a file read after the clone operation finished would
|
|
# not get the cloned data but it would get instead the old and no longer
|
|
# valid data.
|
|
echo "Verifying file digests after cloning"
|
|
md5sum $SCRATCH_MNT/foo | _filter_scratch
|
|
md5sum $SCRATCH_MNT/bar | _filter_scratch
|
|
|
|
# Validate the content of bar still matches foo's content even after
|
|
# clearing all of bar's data from the page cache.
|
|
_scratch_cycle_mount
|
|
echo "Verifying target file digest after umount + mount"
|
|
md5sum $SCRATCH_MNT/bar | _filter_scratch
|
|
|
|
status=0
|
|
exit
|