#! /bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2022, Oracle and/or its affiliates.  All Rights Reserved.
#
# FS QA Test No. 018
#
# Log attribute replay test
#
. ./common/preamble
_begin_fstest auto quick attr

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

_cleanup()
{
	rm -rf $tmp.*
	if [ -n "$ORIG_XFS_LARP" ];then
		echo $ORIG_XFS_LARP > /sys/fs/xfs/debug/larp
	fi
}

test_attr_replay()
{
	testfile=$testdir/$1
	attr_name=$2
	attr_value=$3
	flag=$4
	error_tag=$5

	# Inject error
	_scratch_inject_error $error_tag

	# Set attribute, being careful not to include the trailing newline
	# in the attr value.
	echo -n "$attr_value" | ${ATTR_PROG} -$flag "$attr_name" $testfile 2>&1 | \
			    _filter_scratch

	# FS should be shut down, touch will fail
	touch $testfile 2>&1 | _filter_scratch

	# Remount to replay log
	_scratch_remount_dump_log >> $seqres.full

	# FS should be online, touch should succeed
	touch $testfile

	# Verify attr recovery
	$ATTR_PROG -l $testfile >> $seqres.full
	echo "Checking contents of $attr_name" >> $seqres.full
	echo -n "$attr_name: "
	$ATTR_PROG -q -g $attr_name $testfile 2> /dev/null | md5sum;

	echo ""
}

create_test_file()
{
	filename=$testdir/$1
	count=$2
	attr_value=$3

	touch $filename

	for i in `seq $count`
	do
		$ATTR_PROG -s "attr_name$i" -V $attr_value $filename >> \
			$seqres.full
	done
}

require_larp()
{
	touch $SCRATCH_MNT/a

	# Set attribute, being careful not to include the trailing newline
	# in the attr value.
	echo -n "attr_value" | ${ATTR_PROG} -s "attr_name" $SCRATCH_MNT/a 2>&1 | \
		grep 'Operation not supported' && \
		_notrun 'LARP not supported on this filesystem'
}


_require_scratch
_require_scratch_xfs_crc
_require_attrs
_require_xfs_io_error_injection "larp"
_require_xfs_io_error_injection "da_leaf_split"
_require_xfs_io_error_injection "attr_leaf_to_node"
_require_xfs_sysfs debug/larp
test -w /sys/fs/xfs/debug/larp || _notrun "larp knob not writable"

ORIG_XFS_LARP=`cat /sys/fs/xfs/debug/larp`
# turn on log attributes
echo 1 > /sys/fs/xfs/debug/larp

attr16="0123456789ABCDEF"
attr17="X$attr16"
attr64="$attr16$attr16$attr16$attr16"
attr256="$attr64$attr64$attr64$attr64"
attr1k="$attr256$attr256$attr256$attr256"
attr4k="$attr1k$attr1k$attr1k$attr1k"
attr8k="$attr4k$attr4k"
attr16k="$attr8k$attr8k"
attr32k="$attr16k$attr16k"
attr32l="X$attr32k"
attr64k="$attr32k$attr32k"

echo "*** mkfs"

# Parent pointers change the xattr formats sufficiently to break this test.
# Disable parent pointers if mkfs supports it.
_xfs_force_no_pptrs
_scratch_mkfs >/dev/null

blk_sz=$(_scratch_xfs_get_sb_field blocksize)
err_inj_attr_sz=$(( blk_sz / 3 - 50 ))
err_inj_attr_val=$(printf "A%.0s" $(seq $err_inj_attr_sz))

echo "*** mount FS"
_scratch_mount

testdir=$SCRATCH_MNT/testdir
mkdir $testdir

require_larp

# empty, inline
create_test_file empty_file1 0
test_attr_replay empty_file1 "attr_name" $attr64 "s" "larp"
test_attr_replay empty_file1 "attr_name" $attr64 "r" "larp"

# empty, inline with an unaligned value
create_test_file empty_fileX 0
test_attr_replay empty_fileX "attr_nameX" $attr17 "s" "larp"
test_attr_replay empty_fileX "attr_nameX" $attr17 "r" "larp"

# empty, internal
create_test_file empty_file2 0
test_attr_replay empty_file2 "attr_name" $attr1k "s" "larp"
test_attr_replay empty_file2 "attr_name" $attr1k "r" "larp"

# empty, remote
create_test_file empty_file3 0
test_attr_replay empty_file3 "attr_name" $attr64k "s" "larp"
test_attr_replay empty_file3 "attr_name" $attr64k "r" "larp"

# empty, remote with an unaligned value
create_test_file empty_fileY 0
test_attr_replay empty_fileY "attr_name" $attr32l "s" "larp"
test_attr_replay empty_fileY "attr_name" $attr32l "r" "larp"

# inline, inline
create_test_file inline_file1 1 $attr16
test_attr_replay inline_file1 "attr_name2" $attr64 "s" "larp"
test_attr_replay inline_file1 "attr_name2" $attr64 "r" "larp"

# inline, internal
create_test_file inline_file2 1 $attr16
test_attr_replay inline_file2 "attr_name2" $attr1k "s" "larp"
test_attr_replay inline_file2 "attr_name2" $attr1k "r" "larp"

# inline, remote
create_test_file inline_file3 1 $attr16
test_attr_replay inline_file3 "attr_name2" $attr64k "s" "larp"
test_attr_replay inline_file3 "attr_name2" $attr64k "r" "larp"

# extent, internal
create_test_file extent_file1 1 $attr1k
test_attr_replay extent_file1 "attr_name2" $attr1k "s" "larp"
test_attr_replay extent_file1 "attr_name2" $attr1k "r" "larp"

# extent, inject error on split
create_test_file extent_file2 3 $err_inj_attr_val
test_attr_replay extent_file2 "attr_name4" $attr256 "s" "da_leaf_split"

# extent, inject error on fork transition
create_test_file extent_file3 3 $err_inj_attr_val
test_attr_replay extent_file3 "attr_name4" $attr256 "s" "attr_leaf_to_node"

# extent, remote
create_test_file extent_file4 1 $attr1k
test_attr_replay extent_file4 "attr_name2" $attr64k "s" "larp"
test_attr_replay extent_file4 "attr_name2" $attr64k "r" "larp"

# remote, internal
create_test_file remote_file1 1 $attr64k
test_attr_replay remote_file1 "attr_name2" $attr1k "s" "larp"
test_attr_replay remote_file1 "attr_name2" $attr1k "r" "larp"

# remote, remote
create_test_file remote_file2 1 $attr64k
test_attr_replay remote_file2 "attr_name2" $attr64k "s" "larp"
test_attr_replay remote_file2 "attr_name2" $attr64k "r" "larp"

# replace shortform with different value
create_test_file sf_file 2 $attr64
test_attr_replay sf_file "attr_name2" $attr16 "s" "larp"

# replace leaf with different value
create_test_file leaf_file 3 $attr1k
test_attr_replay leaf_file "attr_name2" $attr256 "s" "larp"

# replace node with a different value
create_test_file node_file 1 $attr64k
$ATTR_PROG -s "attr_name2" -V $attr1k $testdir/node_file \
		>> $seqres.full
test_attr_replay node_file "attr_name2" $attr256 "s" "larp"

echo "*** done"
status=0
exit
