#!/bin/bash
# FS QA Test No. btrfs/085
#
# Tests to ensure that orphan items are properly created and cleaned up
# on next mount.
#
# There are three cases where orphan items may be cleaned up:
# 1) Default subvolume is fs tree root (mkfs default)
# 2) Default subvolume is explicitly created subvolume
#    (i.e. btrfs subvol set-default)
# 3) Non-default subvolume lookup
#
#-----------------------------------------------------------------------
# Copyright (c) 2015 SUSE.  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()
{
    _cleanup_flakey
    rm -f $tmp.*
}

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

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

# real QA test starts here
_supported_fs btrfs
_supported_os Linux
_require_scratch
_require_dm_target flakey

BTRFS_DEBUG_TREE_PROG="`set_prog_path btrfs-debug-tree`"
_require_command "$BTRFS_DEBUG_TREE_PROG" btrfs-debug-tree

rm -f $seqres.full

has_orphan_item()
{
	INO=$1
	if $BTRFS_DEBUG_TREE_PROG $SCRATCH_DEV | \
		grep -q "key (ORPHAN ORPHAN_ITEM $INO)"; then
		return 0
	fi
	return 1
}

test_orphan()
{
	PRECMD=$1
	SUB=0

	_scratch_mkfs >> $seqres.full 2>&1
	_init_flakey

	_mount_flakey

	$PRECMD

	TESTPATH=$SCRATCH_MNT/testdir/testfile
	DIR=$(dirname $TESTPATH)

	[ -d "$DIR" ] || mkdir -p $DIR

	SIZE=$(( 1024 * 1024 ))
	run_check dd if=/dev/zero of=$TESTPATH bs=$SIZE count=1

	INO=$(stat -c %i $TESTPATH)

	# Orphan item won't be created if the file doesn't make it to disk
	sync

	# Open and delete the file
	exec 27<$TESTPATH
	rm -f $TESTPATH

	# Ensure the unlink (and orphan item creation) hits the disk
	sync

	# Turn off writes before closing so the orphan item will be left behind
	_load_flakey_table $FLAKEY_DROP_WRITES

	# Close the file so we can umount
	exec 27>&-

	# Orphan item should be on disk if operating correctly
	_unmount_flakey
	_load_flakey_table $FLAKEY_ALLOW_WRITES
	if ! has_orphan_item $INO; then
		echo "ERROR: No orphan item found after umount."
		return
	fi
	_mount_flakey

	# If $DIR is a subvolume, this will cause a lookup and orphan cleanup
	(cd $DIR; true)

	# Orphan item will be cleaned up during mount but won't be on
	# disk until there's a sync.
	sync

	_unmount_flakey
	if has_orphan_item $INO; then
		echo "ERROR: Orphan item found after successful mount/sync."
	fi
	_cleanup_flakey
}

new_subvolume()
{
	_run_btrfs_util_prog subvolume create $SCRATCH_MNT/testdir
}

new_default()
{
	new_subvolume
	SUB=$($BTRFS_UTIL_PROG subvolume list $SCRATCH_MNT |awk '{print $2}')
	_run_btrfs_util_prog subvolume set-default $SUB $SCRATCH_MNT

	_unmount_flakey
	_mount_flakey
}

echo "Testing with fs root as default subvolume"
test_orphan true

echo "Testing with explicit default subvolume"
test_orphan new_default

echo "Testing with orphan on non-default subvolume"
test_orphan new_subvolume

status=0
exit
