#! /bin/bash
# FS QA Test 132
#
# Check if false ENOSPC will happen when parallel buffer write happens
# The problem is caused by incorrect metadata reservation for any buffered
# write whose max extent size is not 128M (including compression and in-band
# dedupe).
#
#-----------------------------------------------------------------------
# Copyright (c) 2016 Fujitsu.  All Rights Reserved.
#
# 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"

here=`pwd`
tmp=/tmp/$$
status=1	# failure is the default!
trap "_cleanup; exit \$status" 0 1 2 3 15

_cleanup()
{
	cd /
	rm -f $tmp.*
	kill $pids &> /dev/null
	wait
}

# get standard environment, filters and checks
. ./common/rc
. ./common/filter

# remove previous $seqres.full before test
rm -f $seqres.full

# real QA test starts here

# Modify as appropriate.
_supported_fs btrfs
_supported_os Linux
_require_scratch

# Use small filesystem to trigger the bug more easily
# It's highly recommened to run this test case with MKFS_OPTIONS="-n 64k"
# to further increase the possibility
# Since the false ENOSPC happens due to incorrect metadata reservation,
# larger nodesize and small fs will make it much easier to reproduce
_scratch_mkfs_sized $((512 * 1024 * 1024)) >> $seqres.full 2>&1

# Recommended to use MOUNT_OPTIONS="-o compress" to trigger the bug
_scratch_mount

sleep_time=$(($TIME_FACTOR * 30))
loop_writer()
{
	offset=$1
	len=$2
	file=$3

	while true; do
		# Only need stderr, and we need to specify small block size
		# but still large enough trigger compression
		$XFS_IO_PROG -c "pwrite -b 8K $offset $len" $file > /dev/null
	done
}

touch $SCRATCH_MNT/testfile

# Start 2 writter writting into the same file
# The file is 142M, which is smaller than 1/2 of the filesystem,
# so no other cause can lead to ENOSPC.
loop_writer 0 128M $SCRATCH_MNT/testfile &
pids=$!
loop_writer 128M 16M $SCRATCH_MNT/testfile &
pids="$pids $!"

sleep $sleep_time

kill $pids
wait

# Wait all writers really exits
while ps aux | grep "$SCRATCH_MNT" | grep -qv grep; do
	sleep 1
done

echo "Silence is golden"
status=0
exit
