#! /bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2011 Oracle.  All Rights Reserved.
#
# FS QA Test No. btrfs/003
#
# btrfs vol tests
#
. ./common/preamble
_begin_fstest auto replace volume balance

dev_removed=0
removed_dev_htl=""

# Check if all scratch dev pools are deletable
deletable_scratch_dev_pool()
{
	local i
	local x
	for i in $SCRATCH_DEV_POOL; do
		x=`echo $i | cut -d"/" -f 3`
		if [ ! -f /sys/class/block/${x}/device/delete ]; then
			return 1
		fi
	done

	return 0
}

# Override the default cleanup function.
_cleanup()
{
    cd /
    rm -f $tmp.*
    if [ $dev_removed == 1 ]; then
	_scratch_unmount
	_devmgt_add "${removed_dev_htl}"
    fi
}

. ./common/filter

_require_scratch
_require_scratch_dev_pool 4
_require_command "$WIPEFS_PROG" wipefs

# Test cases related to raid in btrfs
_test_raid0()
{
	export MKFS_OPTIONS="-m raid0 -d raid0"
	_scratch_pool_mkfs >> $seqres.full 2>&1 || _fail "mkfs failed"
	_scratch_mount
	dirp=`mktemp -duq $SCRATCH_MNT/dir.XXXXXX`
	_populate_fs -n 1 -f 20 -d 10 -r $dirp -s 10 -c
	_scratch_unmount
}

_test_raid1()
{
	export MKFS_OPTIONS="-m raid1 -d raid1"
	_scratch_pool_mkfs >> $seqres.full 2>&1 || _fail "mkfs failed"
	_scratch_mount
	dirp=`mktemp -duq $SCRATCH_MNT/dir.XXXXXX`
	_populate_fs -n 1 -f 20 -d 10 -r $dirp -s 10 -c
	_scratch_unmount
}

_test_raid10()
{
	export MKFS_OPTIONS="-m raid10 -d raid10"
	_scratch_pool_mkfs >> $seqres.full 2>&1 || _fail "mkfs failed"
	_scratch_mount
	dirp=`mktemp -duq $SCRATCH_MNT/dir.XXXXXX`
	_populate_fs -n 1 -f 20 -d 10 -r $dirp -s 10
	_scratch_unmount
}

_test_single()
{
	export MKFS_OPTIONS="-m single -d single"
	_scratch_pool_mkfs >> $seqres.full 2>&1 || _fail "mkfs failed"
	_scratch_mount
	dirp=`mktemp -duq $SCRATCH_MNT/dir.XXXXXX`
	_populate_fs -n 1 -f 20 -d 10 -r $dirp -s 10
	_scratch_unmount
}

_test_add()
{
	local i
	local -a devs="( $SCRATCH_DEV_POOL )"
	local n=${#devs[@]}

	n=$(($n-1))

	export MKFS_OPTIONS=""
	_scratch_mkfs >> $seqres.full 2>&1 || _fail "mkfs failed"
	_scratch_mount
	dirp=`mktemp -duq $SCRATCH_MNT/dir.XXXXXX`
	_populate_fs -n 1 -f 20 -d 10 -r $dirp -s 10
	for i in `seq 2 $n`; do
		$WIPEFS_PROG -a ${devs[$i]} >> $seqres.full 2>&1 || \
			_fail "wipefs failed"
		$BTRFS_UTIL_PROG device add ${devs[$i]} $SCRATCH_MNT >> $seqres.full 2>&1 || _fail "device add failed"
	done
	_run_btrfs_balance_start $SCRATCH_MNT >> $seqres.full
	_scratch_unmount
}

_test_replace()
{
	local i
	local devs=( $SCRATCH_DEV_POOL )
	local n=${#devs[@]}
	local ds
	local d

	# If scratch devs are not deletable skip this test
	if ! deletable_scratch_dev_pool; then return 0; fi

	# exclude the first and the last disk in the disk pool
	n=$(($n-1))
	ds=${devs[@]:1:$(($n-1))}

	export MKFS_OPTIONS="-m raid1 -d raid1"
	_scratch_mkfs "$ds" >> $seqres.full 2>&1 || _fail "tr: mkfs failed"
	_scratch_mount
	dirp=`mktemp -duq $SCRATCH_MNT/dir.XXXXXX`
	_populate_fs -n 1 -f 20 -d 10 -r $dirp -s 10

	#pick the 2nd last disk 
	ds=${devs[@]:$(($n-1)):1}

	# retrive the HTL for this scsi disk
	d=`echo $ds|cut -d"/" -f3`
	removed_dev_htl=`ls -l /sys/class/block/${d} | rev | cut -d "/" -f 3 | rev`

	#fail disk
	_devmgt_remove ${removed_dev_htl} $ds
	dev_removed=1

	$BTRFS_UTIL_PROG filesystem show $SCRATCH_DEV | \
		grep -ie '\bmissing\b' >> $seqres.full || \
		_fail "btrfs did not report device missing"

	# add a new disk to btrfs
	ds=${devs[@]:$(($n)):1}
	$WIPEFS_PROG -a ${ds} >> $seqres.full 2>&1 || _fail "wipefs failed"
	$BTRFS_UTIL_PROG device add ${ds} $SCRATCH_MNT >> $seqres.full 2>&1 || _fail "dev add failed"
	# in some system balance fails if there is no delay (a bug)
	# putting sleep 10 to work around as of now
	# sleep 10
	_run_btrfs_balance_start $SCRATCH_MNT >> $seqres.full

	# cleaup. add the removed disk
	_scratch_unmount
	_devmgt_add "${removed_dev_htl}"
	dev_removed=0
}

_test_remove()
{
	_scratch_pool_mkfs >> $seqres.full 2>&1 || _fail "mkfs failed"
	_scratch_mount
	dirp=`mktemp -duq $SCRATCH_MNT/dir.XXXXXX`
	_populate_fs -n 1 -f 20 -d 10 -r $dirp -s 10

	# pick last dev in the list
	dev_del=`echo ${SCRATCH_DEV_POOL} | $AWK_PROG '{print $NF}'`
	$BTRFS_UTIL_PROG device delete $dev_del $SCRATCH_MNT || _fail "btrfs device delete failed"
	$BTRFS_UTIL_PROG filesystem show $SCRATCH_DEV 2>&1 | grep $dev_del >> $seqres.full && _fail "btrfs still shows the deleted dev"
	_scratch_unmount
}

# Zoned btrfs only supports SINGLE profile
if ! _scratch_btrfs_is_zoned; then
	_test_raid0
	_test_raid1
	_test_raid10
fi

_test_single
_test_add
# _test_replace() uses raid1, but zoned btrfs only supports SINGLE
# profile
if ! _scratch_btrfs_is_zoned; then
	_test_replace
fi
_test_remove

echo "Silence is golden"
status=0; exit
