#! /bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (C) 2021 CTERA Networks. All Rights Reserved.
#
# FS QA Test 077
#
# Test invalidate of readdir cache
#
# This is a regression test for kernel commits:
# 65cd913ec9d9 ("ovl: invalidate readdir cache on changes to dir with origin")
# 9011c2791e63 ("ovl: skip stale entries in merge dir cache iteration")
#
. ./common/preamble
_begin_fstest auto quick dir

# Import common functions.
. ./common/filter

_fixed_by_kernel_commit 65cd913ec9d9 \
	"ovl: invalidate readdir cache on changes to dir with origin"
_fixed_by_kernel_commit 9011c2791e63 \
	"ovl: skip stale entries in merge dir cache iteration"

_require_scratch_nocheck

# Use small getdents bufsize to fit less than 10 entries
# stuct linux_dirent64 is 20 bytes not including d_name
bufsize=200

# Create enough files to be returned in multiple gendents() calls.
# At least one of the files that we delete will not be listed in the
# first call, so we may encounter stale entries in following calls.
create_files() {
	for n in {1..100}; do
		touch ${1}/${2}${n}
	done
}

# remove all files from previous runs
_scratch_mkfs

# Create test area with a merge dir, a "former" merge dir,
# a pure upper dir and impure upper dir. For each case, overlayfs
# readdir cache is used a bit differently.
lowerdir=$OVL_BASE_SCRATCH_MNT/$OVL_LOWER
upperdir=$OVL_BASE_SCRATCH_MNT/$OVL_UPPER

mkdir -p $lowerdir/merge $lowerdir/former $upperdir/pure $upperdir/impure
# Lower files in merge dir are listed first
create_files $lowerdir/merge m
# Files to be moved into impure upper dir
create_files $lowerdir o
# File to be moved into former merge dir to make it impure
touch $lowerdir/f100

_scratch_mount

create_files $SCRATCH_MNT/pure p
create_files $SCRATCH_MNT/former f
# Copy up file so readdir will need to lookup its origin d_ino
touch $SCRATCH_MNT/merge/m100
# Move copied up files so readdir will need to lookup origin d_ino
mv $SCRATCH_MNT/o* $SCRATCH_MNT/impure/
mv $SCRATCH_MNT/f100 $SCRATCH_MNT/former/

# Remove the lower directory and mount overlay again to create
# a "former merge dir"
$UMOUNT_PROG $SCRATCH_MNT
rm -rf $lowerdir/former
_scratch_mount

# Check readdir cache invalidate on pure upper dir
echo -e "\nCreate file in pure upper dir:" >> $seqres.full
$here/src/t_dir_offset2 $SCRATCH_MNT/pure $bufsize "+p0" 2>&1 >> $seqres.full || \
	echo "Missing created file in pure upper dir (see $seqres.full for details)"
echo -e "\nRemove file in pure upper dir:" >> $seqres.full
$here/src/t_dir_offset2 $SCRATCH_MNT/pure $bufsize "-p100" 2>&1 >> $seqres.full || \
	echo "Found unlinked file in pure upper dir (see $seqres.full for details)"

# Check readdir cache invalidate on impure upper dir
echo -e "\nCreate file in impure upper dir:" >> $seqres.full
$here/src/t_dir_offset2 $SCRATCH_MNT/impure $bufsize "+o0" 2>&1 >> $seqres.full || \
	echo "Missing created file in impure upper dir (see $seqres.full for details)"
echo -e "\nRemove file in impure upper dir:" >> $seqres.full
$here/src/t_dir_offset2 $SCRATCH_MNT/impure $bufsize  "-o100" 2>&1 >> $seqres.full || \
	echo "Found unlinked file in impure upper dir (see $seqres.full for details)"

# Check readdir cache invalidate on merge dir
echo -e "\nCreate file in merge dir:" >> $seqres.full
$here/src/t_dir_offset2 $SCRATCH_MNT/merge $bufsize "+m0" 2>&1 >> $seqres.full || \
	echo "Missing created file in merge dir (see $seqres.full for details)"
echo -e "\nRemove file in merge dir:" >> $seqres.full
$here/src/t_dir_offset2 $SCRATCH_MNT/merge $bufsize "-m100" 2>&1 >> $seqres.full || \
	echo "Found unlinked file in merge dir (see $seqres.full for details)"

# Check readdir cache invalidate on former merge dir
echo -e "\nCreate file in former merge dir:" >> $seqres.full
$here/src/t_dir_offset2 $SCRATCH_MNT/former $bufsize "+f0" 2>&1 >> $seqres.full || \
	echo "Missing created file in former merge dir (see $seqres.full for details)"
echo -e "\nRemove file in former merge dir:" >> $seqres.full
$here/src/t_dir_offset2 $SCRATCH_MNT/former $bufsize "-f100" 2>&1 >> $seqres.full || \
	echo "Found unlinked file in former merge dir (see $seqres.full for details)"

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