#! /bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2018 The University of Texas at Austin.  All Rights Reserved.
#
# FS QA Test 520
#
# Test case created by CrashMonkey
#
# Test if we create a hard link to a file and persist either of the files, all
# the names persist.
#
. ./common/preamble
_begin_fstest auto quick log

# Override the default cleanup function.
_cleanup()
{
	_cleanup_flakey
	cd /
	rm -f $tmp.*
}

# Import common functions.
. ./common/filter
. ./common/dmflakey

# 256MB in byte
fssize=$((2**20 * 256))

_require_scratch_nocheck
_require_dm_target flakey

# initialize scratch device
_scratch_mkfs_sized $fssize >> $seqres.full 2>&1
_require_metadata_journaling $SCRATCH_DEV
_init_flakey

stat_opt='-c "blocks: %b size: %s inode: %i links: %h"'
before=""
after=""

# Using _scratch_mkfs instead of cleaning up the  working directory,
# adds about 10 seconds of delay in total for the 37 tests.
clean_dir()
{
	_mount_flakey
	rm -rf $(find $SCRATCH_MNT/* | grep -v "lost+found")
	_unmount_flakey
}

check_consistency()
{
	_flakey_drop_and_remount

	if [ -f $1 ]; then
		after=`stat "$stat_opt" $1`
	fi

	if [ "$before" != "$after" ] && [ $2 -ne 1 ]; then
		echo "Before: $before"
		echo "After: $after"
	fi

	_unmount_flakey
	_check_scratch_fs $FLAKEY_DEV
}

# create a hard link $2 to file $1, and fsync $3, followed by power-cut
test_link_fsync()
{
	local sibling=0
	local src=$SCRATCH_MNT/$1
	local dest=$SCRATCH_MNT/$2
	before=""
	after=""

	if [ "$3" == "./" ]; then
		fsync=$SCRATCH_MNT
	else
		fsync=$SCRATCH_MNT/$3
	fi

	echo -ne "\n=== link $src $dest  with fsync $fsync ===\n" | \
		_filter_scratch
	_mount_flakey

	# Now execute the workload
	# Create the directory in which the source and destination files
	# will be created
	mkdir -p "${src%/*}"
	mkdir -p "${dest%/*}"
	touch $src
	ln $src $dest

	# If the file being persisted is a sibling, create it first
	if [ ! -f $fsync ]; then
		sibling=1
		touch $fsync
	fi

	$XFS_IO_PROG -c "fsync" $fsync

	if [ $sibling -ne 1 ]; then
		before=`stat "$stat_opt" $src`
	fi

	check_consistency $src $sibling
	clean_dir
}

# create a hard link $2 to file $1, and sync, followed by power-cut
test_link_sync()
{
	local src=$SCRATCH_MNT/$1
	local dest=$SCRATCH_MNT/$2
	before=""
	after=""
	echo -ne "\n=== link $src $dest  with sync ===\n" | _filter_scratch
	_mount_flakey

	# now execute the workload
	# Create the directory in which the source and destination files
	# will be created
	mkdir -p "${src%/*}"
	mkdir -p "${dest%/*}"
	touch $src
	ln $src $dest
	_scratch_sync
	before=`stat "$stat_opt" $src`

	check_consistency $src 0
	clean_dir
}

# Create different combinations to run the link test
# Group 0: Both files within root directory
file_names[0]="foo bar"
fsync_names[0]="./ foo bar"

# Group 1: Create hard link in a sub directory
file_names[1]="foo A/bar"
fsync_names[1]="./ foo bar A A/bar A/foo"

# Group 2: Create hard link in parent directory
file_names[2]="A/foo bar"
fsync_names[2]="./ foo bar A A/bar A/foo"

# Group 3: Both files within a directory other than root
file_names[3]="A/foo A/bar"
fsync_names[3]="./ A A/bar A/foo"

#Group 4: Exercise name reuse : Link file in sub-directory
file_names[4]="bar A/bar"
fsync_names[4]="./ foo bar A A/bar A/foo"

#Group 5: Exercise name reuse : Link file in parent directory
file_names[5]="A/bar bar"
fsync_names[5]="./ foo bar A A/bar A/foo"

for ((test_group = 0; test_group < 6; test_group++)); do
	for file in ${fsync_names[$test_group]}; do
		test_link_fsync ${file_names[$test_group]} $file
	done
	test_link_sync ${file_names[$test_group]}
done

# success, all done
status=0
exit
