blob: b1474d1003747fdb65ddae79babcfd76a6218ec6 [file] [log] [blame]
#! /bin/bash
# FSQA Test No. 080
#
# Regression test for a btrfs issue where if right after the snapshot creation
# ioctl started, a file write followed by a file truncate happened, with both
# operations increasing the file's size, the created snapshot would capture an
# inconsistent state of the file system tree. That state reflected the file
# truncation but it didn't reflect the write operation, and left a gap between
# two file extent items (and that gap corresponded to the total or a partial
# area of the write operation's range).
#
# This issue was fixed by the following linux kernel patch:
#
# Btrfs: fix snapshot inconsistency after a file write followed by truncate
#
#-----------------------------------------------------------------------
#
# Copyright (C) 2014 SUSE Linux Products GmbH. All Rights Reserved.
# Author: Filipe Manana <fdmanana@suse.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it would be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#-----------------------------------------------------------------------
#
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()
{
for p in ${cpu_stress_pids[*]}; do
kill $p &> /dev/null
done
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_nocheck
rm -f $seqres.full
create_snapshot()
{
local ts=`date +'%H_%M_%S_%N'`
_run_btrfs_util_prog subvolume snapshot -r \
$SCRATCH_MNT $SCRATCH_MNT/"${ts}_snap"
}
create_file()
{
local name=$1
run_check $XFS_IO_PROG -f \
-c "pwrite -S 0xaa -b 32K 0 32K" \
-c "fsync" \
-c "pwrite -S 0xbb -b 32770 16K 32770" \
-c "truncate 90123" \
$SCRATCH_MNT/$name
}
workout()
{
local name=$1
create_file $name &
fpid=$!
create_snapshot &
spid=$!
wait $fpid
create_ret=$?
wait $spid
snap_ret=$?
if [ $create_ret != 0 -o $snap_ret != 0 ]; then
_fail "Failure creating file or snapshot, check $seqres.full for details"
fi
}
# If the installed btrfs mkfs supports the no-holes feature, make sure the
# created fs doesn't get that feature enabled. With it enabled, the below fsck
# call wouldn't fail. This feature hasn't been enabled by default since it was
# introduced, but be safe and explicitly disable it.
_scratch_mkfs -O list-all 2>&1 | grep -q '\bno\-holes\b'
if [ $? -eq 0 ]; then
mkfs_options="-O ^no-holes"
fi
_scratch_mkfs "$mkfs_options" >>$seqres.full 2>&1
_scratch_mount
# Run some background load in order to make the issue easier to trigger.
# Specially needed when testing with non-debug kernels and there isn't
# any other significant load on the test machine other than this test.
num_cpus=`$here/src/feature -o`
num_procs=$(($num_cpus * 20))
for ((i = 0; i < $num_procs; i++)); do
while true; do
true
done &
cpu_stress_pids[$i]=$!
done
for ((i = 1; i <= 100; i++)); do
workout "foobar_$i"
done
for ((i = 0; i < $num_procs; i++)); do
kill ${cpu_stress_pids[$i]} &> /dev/null
unset cpu_stress_pids[$i]
done
for f in $(find $SCRATCH_MNT -type f -name 'foobar_*'); do
digest=`md5sum $f | cut -d ' ' -f 1`
case $digest in
"d41d8cd98f00b204e9800998ecf8427e")
# ok, empty file
;;
"c28418534a020122aca59fd3ff9581b5")
# ok, only first write captured
;;
"cd0032da89254cdc498fda396e6a9b54")
# ok, only 2 first writes captured
;;
"a1963f914baf4d2579d643425f4e54bc")
# ok, the 2 writes and the truncate were captured
;;
*)
# not ok, truncate captured but not one or both writes
_fail "Unexpected digest for file $f"
esac
done
# Check the filesystem for inconsistencies.
# Before the btrfs kernel fix mentioned above, we would very often get fsck
# error messages like: "root 306 inode 338 errors 100, file extent discount".
#
# This was because if right after the snapshot creation ioctl started, a file
# write followed by a file truncate, with both operations increasing the file's
# size, we would get a snapshot that reflected a state where the file truncation
# was visible but the previous file write was not visible, breaking expected
# total ordering of operations and causing a gap between 2 file extents, where a
# file extent item representing the range [32K .. ALIGN(16K + 32770, 4096)] was
# missing in the snapshot's btree.
_check_scratch_fs
echo "Silence is golden"
status=0
exit