#!/bin/bash
# FS QA Test No. btrfs/002
#
# Extented btrfs snapshot test cases
#
#-----------------------------------------------------------------------
# Copyright (c) 2011 Oracle  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!

_cleanup()
{
    rm -f $tmp.*
}

trap "_cleanup ; exit \$status" 0 1 2 3 15

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

_supported_fs btrfs
_supported_os Linux
_require_scratch

_scratch_mkfs > /dev/null 2>&1 || _fail "mkfs failed"
_scratch_mount

# Create and save sha256sum
# arg1 FS to generate sha256
# arg2 File name to save the sha256 output
_save_checksum()
{
	local i=0
	>$2
	cd $1
	for i in `find . -type f`; do sha256sum $i >> $2; done
	cd $OLDPWD
}

# Verify the sha256sum for a FS
# arg1 FS to be tested
# arg2 sha256 file
_verify_checksum()
{
	cd $1
	[ -f $2 ] || _fail "checksum file $2 not found"
	sha256sum -c $2 | grep "FAILED"
	cd $OLDPWD
}

# Create a snapshot
# arg1 dest dir
# Return snapshot name in the SNAPNAME
_create_snap()
{
	local x
	[ -d $1 ] || _fail "Destination dir $1 not present"
	SNAPNAME=`mktemp -u $SCRATCH_MNT/snap.XXXXXX`
	$BTRFS_UTIL_PROG subvolume snapshot $1 $SNAPNAME > /dev/null || _fail "snapshot create failed"
}

# Reads and writes new data but does not allocate new blocks
# arg1 FS to be modified
_read_modify_write()
{
	local i
	local FSIZE
	for i in `find $1 -type f`
	do
		FSIZE=`stat -t $i | cut -d" " -f2`
		dd if=$i of=/dev/null obs=$FSIZE count=1 status=noxfer 2>/dev/null &
		dd if=/dev/urandom of=$i obs=$FSIZE count=1 status=noxfer 2>/dev/null &
	done
	wait $!
}

# Fills the allocated blocks
# arg1 FS in question
_fill_blk()
{
	local FSIZE
	local BLKS
	local NBLK
	local FALLOC
	local WS

	for i in `find /$1 -type f`
	do
		FSIZE=`stat -t $i | cut -d" " -f2`
		BLKS=`stat -c "%B" $i`
		NBLK=`stat -c "%b" $i`
		FALLOC=$(($BLKS * $NBLK))
		WS=$(($FALLOC - $FSIZE))
		dd if=/dev/urandom of=$i oseek=$FSIZE obs=$WS count=1 status=noxfer 2>/dev/null &
	done
	wait $!
}

# Append a random size to the files
# arg1 : FS in question
_append_file()
{
	local FSIZE
	local X
	local N
	local i
	N=0
	for i in `find $1 -type f`
	do
		if [ $N == 0 ]; then
			X=$i
			FSIZE=`stat -t $X | cut -d" " -f2`
			dd if=$X of=$X seek=1 bs=$FSIZE obs=$FSIZE count=1 status=noxfer 2>/dev/null &
			N=$(($N+1))
			continue
		fi
		FSIZE=`stat -t $i | cut -d" " -f2`
		dd if=$X of=$i seek=1 bs=$FSIZE obs=$FSIZE count=1 status=noxfer 2>/dev/null &
		X=$i
	done
	wait $!
}

##################### real QA test starts here###################################
# sv1 - is just a name nothing spl
firstvol="$SCRATCH_MNT/sv1"
$BTRFS_UTIL_PROG subvolume create $firstvol > /dev/null || _fail "btrfs subvolume create $firstvol failed"
dirp=`mktemp -duq $firstvol/dir.XXXXXX`
_populate_fs -n 1 -f 20 -d 10 -r $dirp -s 10 -x
SNAPNAME=0
_create_snap $firstvol
_save_checksum $firstvol $tmp.sv1.sum
_verify_checksum $SNAPNAME $tmp.sv1.sum

#Append1 the files
_fill_blk $SNAPNAME
_verify_checksum $firstvol $tmp.sv1.sum

#Append2 the files
_append_file $SNAPNAME
_verify_checksum $firstvol $tmp.sv1.sum

#read modify write
_read_modify_write $SNAPNAME
_verify_checksum $firstvol $tmp.sv1.sum

#nested snapshot test
src_vol=$firstvol
for i in `seq 1 7`; do
	SNAPNAME=0
	_create_snap $src_vol
	_verify_checksum $SNAPNAME $tmp.sv1.sum
	src_vol=$SNAPNAME
done

# file delete test
SNAPNAME=0
_create_snap $firstvol
tname=`echo $SNAPNAME | rev | cut -d"/" -f1 | rev`
_save_checksum $SNAPNAME $tmp.$tname.sum
\rm -rf $firstvol/*
_verify_checksum $SNAPNAME $tmp.$tname.sum

_scratch_unmount || _fail "unmount failed"

echo "Silence is golden"
status=0; exit
