#! /bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2020 Fujitsu.  All Rights Reserved.
#
# FS QA Test 607
#
# Verify the inheritance behavior of FS_XFLAG_DAX flag in various combinations.
# 1) New files and directories automatically inherit FS_XFLAG_DAX from their parent directory.
# 2) cp operation make files and directories inherit the FS_XFLAG_DAX from new parent directory.
# 3) mv operation make files and directories preserve the FS_XFLAG_DAX from old parent directory.
# In addition, setting/clearing FS_XFLAG_DAX flag is not impacted by dax mount options.

. ./common/preamble
_begin_fstest auto attr quick dax

# Import common functions.
. ./common/filter

_supported_fs generic
_require_scratch
_require_dax_iflag
_require_xfs_io_command "lsattr" "-v"

# Make sure we can call FSGETXATTR on a directory...
output="$($XFS_IO_PROG -c "lsattr -v" $TEST_DIR 2>&1)"
echo "$output" | grep -q "Inappropriate ioctl for device" && \
	_notrun "$FSTYP: FSGETXATTR not supported on directories."

# If a/ is +x, check that a's new children
# inherit +x from a/.
test_xflag_inheritance1()
{
	mkdir -p a
	$XFS_IO_PROG -c "chattr +x" a
	mkdir -p a/b/c
	touch a/b/c/d

	_check_xflag a 1
	_check_xflag a/b 1
	_check_xflag a/b/c 1
	_check_xflag a/b/c/d 1

	rm -rf a
}

# If a/ is +x and b/ is -x, check that:
# 1) b's new children inherit -x from b/.
# 2) a's new children(b/ is old) inherit +x from a/.
test_xflag_inheritance2()
{
	mkdir -p a/b
	$XFS_IO_PROG -c "chattr +x" a
	mkdir -p a/b/c a/d
	touch a/b/c/e a/d/f

	_check_xflag a 1
	_check_xflag a/b 0
	_check_xflag a/b/c 0
	_check_xflag a/b/c/e 0
	_check_xflag a/d 1
	_check_xflag a/d/f 1

	rm -rf a
}

# If a/ is -x and b/ is +x, check that:
# 1) b's new children inherit +x from b/.
# 2) a's new children(b/ is old) inherit -x from a/.
test_xflag_inheritance3()
{
	mkdir -p a/b
	$XFS_IO_PROG -c "chattr +x" a/b
	mkdir -p a/b/c a/d
	touch a/b/c/e a/d/f

	_check_xflag a 0
	_check_xflag a/b 1
	_check_xflag a/b/c 1
	_check_xflag a/b/c/e 1
	_check_xflag a/d 0
	_check_xflag a/d/f 0

	rm -rf a
}

# If a/, c/ are +x and b/ is -x, check that:
# 1) c's new children inherit +x from c/.
# 2) b's new children(c/ is old) inherit -x from b/.
test_xflag_inheritance4()
{
	mkdir -p a
	$XFS_IO_PROG -c "chattr +x" a
	mkdir -p a/b/c
	$XFS_IO_PROG -c "chattr -x" a/b
	mkdir -p a/b/c/d a/b/e
	touch a/b/c/d/f a/b/e/g

	_check_xflag a 1
	_check_xflag a/b 0
	_check_xflag a/b/c 1
	_check_xflag a/b/c/d 1
	_check_xflag a/b/c/d/f 1
	_check_xflag a/b/e 0
	_check_xflag a/b/e/g 0

	rm -rf a
}

# If a/ is +x and b/ is -x, check that:
# 1) new b/c and b/g inherit -x from b/ by cp.
# 2) new a/e inherits +x from a/ by cp.
# 3) new b/d preserves +x from a/ by mv.
# 4) new a/f and a/h preserve -x from b/ by mv.
test_xflag_inheritance5()
{
	mkdir -p a b
	$XFS_IO_PROG -c "chattr +x" a
	mkdir -p a/c a/d b/e b/f
	touch a/g b/h

	cp -r a/c b/
	cp -r b/e a/
	cp -r a/g b/
	mv a/d b/
	mv b/f a/
	mv b/h a/

	_check_xflag b/c 0
	_check_xflag b/d 1
	_check_xflag a/e 1
	_check_xflag a/f 0
	_check_xflag b/g 0
	_check_xflag a/h 0

	rm -rf a b
}

do_xflag_tests()
{
	local option=$1

	_scratch_mount "$option"

	# Make sure the root dir doesn't have FS_XFLAG_DAX set before we start.
	$XFS_IO_PROG -c "chattr -x" $SCRATCH_MNT &>> $seqres.full

	cd $SCRATCH_MNT

	for i in $(seq 1 5); do
		test_xflag_inheritance${i}
	done

	cd - > /dev/null
	_scratch_unmount
}

do_tests()
{
	_scratch_mkfs >> $seqres.full 2>&1

	# Mount without dax option
	export MOUNT_OPTIONS=""
	do_xflag_tests

	# Mount with 'dax' or 'dax=always' option if fs supports it.
	_check_scratch_dax_mountopt "dax" && do_xflag_tests "-o dax"

	# Mount with 'dax=inode' and 'dax=never' options if fs supports them.
	if _check_scratch_dax_mountopt "dax=always"; then
		for dax_option in "dax=inode" "dax=never"; do
			do_xflag_tests "-o $dax_option"
		done
	fi
}

do_tests

# success, all done
echo "Silence is golden"
status=0
exit
