Tests for cloned device verification should pass on Btrfs, XFS, and ext4. We need 2 scratch devices, allow SCRATCH_DEV_POOL for other FSs. Signed-off-by: Anand Jain --- common/rc | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/common/rc b/common/rc index 92cb69820311..9db8b3e88996 100644 --- a/common/rc +++ b/common/rc @@ -3990,18 +3990,9 @@ _require_scratch_dev_pool() ndevs=$1 fi - # btrfs test case needs ndevs or more scratch_dev_pool; other FS not sure - # so fail it - case $FSTYP in - btrfs) - if [ "`echo $SCRATCH_DEV_POOL|wc -w`" -lt $ndevs ]; then - _notrun "btrfs and this test needs $ndevs or more disks in SCRATCH_DEV_POOL" - fi - ;; - *) - _notrun "dev_pool is not supported by fstype \"$FSTYP\"" - ;; - esac + if [ "`echo $SCRATCH_DEV_POOL|wc -w`" -lt $ndevs ]; then + _notrun "This test needs $ndevs or more disks in SCRATCH_DEV_POOL" + fi for i in $SCRATCH_DEV_POOL; do if [ "`_is_block_dev "$i"`" = "" ]; then -- 2.43.0 Introduce _mkfs_scratch_clone() to mkfs the scratch device and clone it to the next device in SCRATCH_DEV_POOL. Signed-off-by: Anand Jain --- common/rc | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/common/rc b/common/rc index 9db8b3e88996..2253438ef0f6 100644 --- a/common/rc +++ b/common/rc @@ -1503,6 +1503,38 @@ _scratch_resvblks() esac } +_scratch_mkfs_sized_clone() +{ + local devs=($SCRATCH_DEV_POOL) + local scratch_data="$1" + local size=$(_small_fs_size_mb 128) # Smallest possible + + size=$((size * 1024 * 1024)) + + # make sure there are two devices + if [ "${#devs[@]}" -ne 2 ]; then + _notrun "Test requires exactly 2 devices" + fi + + case "$FSTYP" in + "btrfs") + _scratch_mkfs_sized $size + _scratch_mount + $BTRFS_UTIL_PROG subvolume create $SCRATCH_MNT/sv1 + _scratch_unmount + ;; + "xfs"|"ext4") + _scratch_mkfs_sized $size + ;; + *) + _notrun "fstests clone op unsupported for FS $FSTYP" + ;; + esac + + # clone SCRATCH_DEV devs[0] to devs[1]. + dd if=$SCRATCH_DEV of=${devs[1]} bs=$size status=none count=1 || \ + _fail "Clone failed" +} # Repair scratch filesystem. Returns 0 if the FS is good to go (either no # errors found or errors were fixed) and nonzero otherwise; also spits out -- 2.43.0 Adds _clone_mount_option() helper function to handle filesystem-specific requirements for mounting cloned devices. Abstract the need for -o nouuid on XFS. Signed-off-by: Anand Jain --- common/rc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/common/rc b/common/rc index 2253438ef0f6..438de54a467b 100644 --- a/common/rc +++ b/common/rc @@ -397,6 +397,14 @@ _scratch_mount_options() $SCRATCH_DEV $SCRATCH_MNT } +_clone_mount_option() +{ + local mount_opts="" + [[ "$FSTYP" == "xfs" ]] && mount_opts="-o nouuid" + + echo $mount_opts +} + _supports_filetype() { local dir=$1 -- 2.43.0 Add a new test, to verify that the kernel correctly differentiates between two block devices sharing the same FSID/UUID. Signed-off-by: Anand Jain --- common/config | 1 + tests/generic/790 | 78 +++++++++++++++++++++++++++++++++++++++++++ tests/generic/790.out | 7 ++++ 3 files changed, 86 insertions(+) create mode 100644 tests/generic/790 create mode 100644 tests/generic/790.out diff --git a/common/config b/common/config index 1420e35ddfee..c08f828575a2 100644 --- a/common/config +++ b/common/config @@ -228,6 +228,7 @@ export BTRFS_MAP_LOGICAL_PROG=$(type -P btrfs-map-logical) export PARTED_PROG="$(type -P parted)" export XFS_PROPERTY_PROG="$(type -P xfs_property)" export FSCRYPTCTL_PROG="$(type -P fscryptctl)" +export INOTIFYWAIT_PROG="$(type -P inotifywait)" # udev wait functions. # diff --git a/tests/generic/790 b/tests/generic/790 new file mode 100644 index 000000000000..3809fced622d --- /dev/null +++ b/tests/generic/790 @@ -0,0 +1,78 @@ +#! /bin/bash +# SPDX-License-Identifier: GPL-2.0 +# Copyright (c) 2026 Anand Jain . All Rights Reserved. +# +# FS QA Test 790 +# +# Verify if the kernel or userspace becomes confused when two block devices +# share the same fid/fsid/uuid. Create inotify on both original and cloned +# filesystem. Monitor the notification in the respective logs. + +. ./common/preamble + +_begin_fstest auto quick mount clone + +_require_test +_require_scratch_dev_pool 2 +_require_command "$INOTIFYWAIT_PROG" inotifywait + +_cleanup() +{ + cd / + rm -r -f $tmp.* + umount $mnt1 $mnt2 2>/dev/null + _scratch_dev_pool_put +} + +_scratch_dev_pool_get 2 +_scratch_mkfs_sized_clone >$seqres.full 2>&1 +devs=($SCRATCH_DEV_POOL) +mnt2=$TEST_DIR/mnt2 +mkdir -p $mnt2 + +_scratch_mount $(_clone_mount_option) +_mount $(_common_dev_mount_options) $(_clone_mount_option) ${devs[1]} $mnt2 || \ + _fail "Failed to mount dev2" + +log1=$tmp.inotify1 +log2=$tmp.inotify2 + +echo "Setup inotify watchers on both SCRATCH_MNT and mnt2" +$INOTIFYWAIT_PROG -m -e create --format '%f' $SCRATCH_MNT > $log1 2>&1 & +pid1=$! +$INOTIFYWAIT_PROG -m -e create --format '%f' $mnt2 > $log2 2>&1 & +pid2=$! +sleep 2 + +echo "Trigger file creation on SCRATCH_MNT" +touch $SCRATCH_MNT/file_on_scratch_mnt +sync +sleep 1 + +echo "Trigger file creation on mnt2" +touch $mnt2/file_on_mnt2 +sync +sleep 1 + +echo "Verify inotify isolation" +kill $pid1 $pid2 +wait $pid1 $pid2 2>/dev/null + +if grep -q "file_on_scratch_mnt" $log1 && ! grep -q "file_on_mnt2" $log1; then + echo "SUCCESS: SCRATCH_MNT events isolated." +else + echo "FAIL: SCRATCH_MNT inotify confusion!" + [ ! -s $log1 ] && echo " - SCRATCH_MNT received no events." + grep -q "file_on_mnt2" $log1 && echo " - SCRATCH_MNT received event from mnt2." +fi + +if grep -q "file_on_mnt2" $log2 && ! grep -q "file_on_scratch_mnt" $log2; then + echo "SUCCESS: mnt2 events isolated." +else + echo "FAIL: mnt2 inotify confusion!" + [ ! -s $log2 ] && echo " - mnt2 received no events." + grep -q "file_on_scratch_mnt" $log2 && echo " - mnt2 received event from SCRATCH_MNT." +fi + +status=0 +exit diff --git a/tests/generic/790.out b/tests/generic/790.out new file mode 100644 index 000000000000..3c92c34ffbda --- /dev/null +++ b/tests/generic/790.out @@ -0,0 +1,7 @@ +QA output created by 790 +Setup inotify watchers on both SCRATCH_MNT and mnt2 +Trigger file creation on SCRATCH_MNT +Trigger file creation on mnt2 +Verify inotify isolation +SUCCESS: SCRATCH_MNT events isolated. +SUCCESS: mnt2 events isolated. -- 2.43.0 Verify that fanotify events are correctly routed to the appropriate watcher when cloned filesystems are mounted. Helps verify kernel's event notification distinguishes between devices sharing the same FSID/UUID. Signed-off-by: Anand Jain --- .gitignore | 1 + src/Makefile | 2 +- src/fanotify.c | 66 +++++++++++++++++++++++++++++++++ tests/generic/791 | 86 +++++++++++++++++++++++++++++++++++++++++++ tests/generic/791.out | 7 ++++ 5 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 src/fanotify.c create mode 100644 tests/generic/791 create mode 100644 tests/generic/791.out diff --git a/.gitignore b/.gitignore index 82c57f415301..7f91310ce58b 100644 --- a/.gitignore +++ b/.gitignore @@ -212,6 +212,7 @@ tags /src/dio-writeback-race /src/unlink-fsync /src/file_attr +/src/fanotify # Symlinked files /tests/generic/035.out diff --git a/src/Makefile b/src/Makefile index d0a4106e6be8..ff71cde936a7 100644 --- a/src/Makefile +++ b/src/Makefile @@ -36,7 +36,7 @@ LINUX_TARGETS = xfsctl bstat t_mtab getdevicesize preallo_rw_pattern_reader \ fscrypt-crypt-util bulkstat_null_ocount splice-test chprojid_fail \ detached_mounts_propagation ext4_resize t_readdir_3 splice2pipe \ uuid_ioctl t_snapshot_deleted_subvolume fiemap-fault min_dio_alignment \ - rw_hint + rw_hint fanotify EXTRA_EXECS = dmerror fill2attr fill2fs fill2fs_check scaleread.sh \ btrfs_crc32c_forged_name.py popdir.pl popattr.py \ diff --git a/src/fanotify.c b/src/fanotify.c new file mode 100644 index 000000000000..e30c48dc0e52 --- /dev/null +++ b/src/fanotify.c @@ -0,0 +1,66 @@ +/* + * SPDX-License-Identifier: GPL-2.0 + * Copyright (c) 2026 Anand Jain . All Rights Reserved. + * + * Simple fanotify monitor to verify mount-point event isolation. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + int fd; + char buf[4096] __attribute__((aligned(8))); + setlinebuf(stdout); + + if (argc < 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + return 1; + } + + // Initialize with FID reporting + fd = fanotify_init(FAN_CLASS_NOTIF | FAN_REPORT_FID, O_RDONLY); + if (fd < 0) { + perror("fanotify_init"); + return 1; + } + + if (fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_FILESYSTEM, + FAN_CREATE, AT_FDCWD, argv[1]) < 0) { + perror("fanotify_mark"); + return 1; + } + + printf("Listening for events on %s...\n", argv[1]); + while (1) { + struct fanotify_event_metadata *metadata = (struct fanotify_event_metadata *)buf; + ssize_t len = read(fd, buf, sizeof(buf)); + + if (len <= 0) break; + + while (FAN_EVENT_OK(metadata, len)) { + // metadata_len is the offset to the first info record + if (metadata->event_len > metadata->metadata_len) { + struct fanotify_event_info_header *hdr = +(struct fanotify_event_info_header *)((char *)metadata + metadata->metadata_len); + + if (hdr->info_type == FAN_EVENT_INFO_TYPE_FID) { + struct fanotify_event_info_fid *fid = (struct fanotify_event_info_fid *)hdr; + printf("FSID: %08x%08x\n", + fid->fsid.val[0], fid->fsid.val[1]); + } + } + metadata = FAN_EVENT_NEXT(metadata, len); + } + } + + fflush(stdout); + close(fd); + return 0; +} diff --git a/tests/generic/791 b/tests/generic/791 new file mode 100644 index 000000000000..fe8109083732 --- /dev/null +++ b/tests/generic/791 @@ -0,0 +1,86 @@ +#! /bin/bash +# SPDX-License-Identifier: GPL-2.0 +# Copyright (c) 2026 Anand Jain . All Rights Reserved. +# +# FS QA Test 791 +# Verify fanotify FID functionality on cloned filesystems by setting up +# watchers and making sure notifications are in the correct logs files. + +. ./common/preamble + +_begin_fstest auto quick mount clone + +_require_test +_require_scratch_dev_pool 2 + +[ "$FSTYP" = "ext4" ] && _fixed_by_kernel_commit xxxxxxxxxxxx \ + "ext4: derive f_fsid from block device to avoid collisions" + +_cleanup() +{ + cd / + rm -r -f $tmp.* + umount $mnt1 $mnt2 2>/dev/null + _scratch_dev_pool_put +} + +_scratch_dev_pool_get 2 +_scratch_mkfs_sized_clone >$seqres.full 2>&1 +devs=($SCRATCH_DEV_POOL) +mnt2=$TEST_DIR/mnt2 +mkdir -p $mnt2 + +_scratch_mount $(_clone_mount_option) +_mount $(_common_dev_mount_options) $(_clone_mount_option) ${devs[1]} $mnt2 || \ + _fail "Failed to mount dev2" + +fsid1=$(stat -f -c "%i" $SCRATCH_MNT) +fsid2=$(stat -f -c "%i" $mnt2) + +[[ "$fsid1" == "$fsid2" ]] && \ + _notrun "Require clone filesystem with unique f_fsid" + +log1=$tmp.fanotify1 +log2=$tmp.fanotify2 + +echo "Setup FID fanotify watchers on both SCRATCH_MNT and mnt2" +$here/src/fanotify $SCRATCH_MNT > $log1 2>&1 & +pid1=$! +$here/src/fanotify $mnt2 > $log2 2>&1 & +pid2=$! +sleep 2 + +echo "Trigger file creation on SCRATCH_MNT" +touch $SCRATCH_MNT/file_on_scratch_mnt +sync +sleep 1 + +echo "Trigger file creation on mnt2" +touch $mnt2/file_on_mnt2 +sync +sleep 1 + +echo "Verify fsid in the fanotify" +kill $pid1 $pid2 +wait $pid1 $pid2 2>/dev/null + +echo fsid1=$fsid1 fsid2=$fsid2 >> $seqres.full +cat $log1 >> $seqres.full +cat $log2 >> $seqres.full + +if grep -q "${fsid1}" $log1 && ! grep -q "${fsid2}" $log1; then + echo "SUCCESS: SCRATCH_MNT events found" +else + [ ! -s $log1 ] && echo " - SCRATCH_MNT received no events." + grep -q "${fsid2}" $log1 && echo " - SCRATCH_MNT received event from mnt2." +fi + +if grep -q "${fsid2}" $log2 && ! grep -q "${fsid1}" $log2; then + echo "SUCCESS: mnt2 events found" +else + [ ! -s $log2 ] && echo " - mnt2 received no events." + grep -q "${fsid1}" $log2 && echo " - mnt2 received event from SCRATCH_MNT." +fi + +status=0 +exit diff --git a/tests/generic/791.out b/tests/generic/791.out new file mode 100644 index 000000000000..9725c99bcb4b --- /dev/null +++ b/tests/generic/791.out @@ -0,0 +1,7 @@ +QA output created by 791 +Setup FID fanotify watchers on both SCRATCH_MNT and mnt2 +Trigger file creation on SCRATCH_MNT +Trigger file creation on mnt2 +Verify fsid in the fanotify +SUCCESS: SCRATCH_MNT events found +SUCCESS: mnt2 events found -- 2.43.0 Verify that the cloned filesystem provides an f_fsid that is persistent across mount cycles, yet unique from the original filesystem's f_fsid. Signed-off-by: Anand Jain --- tests/generic/792 | 57 +++++++++++++++++++++++++++++++++++++++++++ tests/generic/792.out | 7 ++++++ 2 files changed, 64 insertions(+) create mode 100644 tests/generic/792 create mode 100644 tests/generic/792.out diff --git a/tests/generic/792 b/tests/generic/792 new file mode 100644 index 000000000000..3a2f463dc76e --- /dev/null +++ b/tests/generic/792 @@ -0,0 +1,57 @@ +#! /bin/bash +# SPDX-License-Identifier: GPL-2.0 +# Copyright (c) 2026 Anand Jain . All Rights Reserved. +# +# FS QA Test 792 +# Verify f_fsid and s_uuid of cloned filesystems across mount cycle. + +. ./common/preamble + +_begin_fstest auto quick mount clone + +_require_test +_require_scratch_dev_pool 2 + +[ "$FSTYP" = "btrfs" ] && _fixed_by_kernel_commit xxxxxxxxxxxx \ + "btrfs: use on-disk uuid for s_uuid in temp_fsid mounts" +[ "$FSTYP" = "btrfs" ] && _fixed_by_kernel_commit xxxxxxxxxxxx \ + "btrfs: derive f_fsid from on-disk fsuuid and dev_t" + +_cleanup() +{ + cd / + rm -r -f $tmp.* + umount $mnt2 2>/dev/null + _scratch_dev_pool_put +} + +_scratch_dev_pool_get 2 +_scratch_mkfs_sized_clone >$seqres.full 2>&1 +devs=($SCRATCH_DEV_POOL) +mnt2=$TEST_DIR/mnt2 +mkdir -p $mnt2 + +_scratch_mount $(_clone_mount_option) +_mount $(_common_dev_mount_options) $(_clone_mount_option) ${devs[1]} $mnt2 || \ + _fail "Failed to mount dev2" + +fsid_scratch=$(stat -f -c "%i" $SCRATCH_MNT) +fsid_clone=$(stat -f -c "%i" $mnt2) + +echo "**** fsid initially ****" +echo $fsid_scratch | sed -e "s/$fsid_scratch/FSID_SCRATCH/g" +echo $fsid_clone | sed -e "s/$fsid_clone/FSID_CLONE/g" + +# Make sure fsid still match across a mount cycle, also reverse the order. +echo "**** fsid after mount cycle ****" +_scratch_unmount +_unmount $mnt2 +_mount $(_common_dev_mount_options) $(_clone_mount_option) ${devs[1]} $mnt2 || \ + _fail "Failed to mount dev2" +_scratch_mount $(_clone_mount_option) + +stat -f -c "%i" $SCRATCH_MNT | sed -e "s/$fsid_scratch/FSID_SCRATCH/g" +stat -f -c "%i" $mnt2 | sed -e "s/$fsid_clone/FSID_CLONE/g" + +status=0 +exit diff --git a/tests/generic/792.out b/tests/generic/792.out new file mode 100644 index 000000000000..27ecbce2225e --- /dev/null +++ b/tests/generic/792.out @@ -0,0 +1,7 @@ +QA output created by 792 +**** fsid initially **** +FSID_SCRATCH +FSID_CLONE +**** fsid after mount cycle **** +FSID_SCRATCH +FSID_CLONE -- 2.43.0 Verify how findmnt, df (libblkid) resolve device paths when multiple block devices share the same FSUUID. Signed-off-by: Anand Jain --- tests/generic/793 | 73 +++++++++++++++++++++++++++++++++++++++++++ tests/generic/793.out | 22 +++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 tests/generic/793 create mode 100644 tests/generic/793.out diff --git a/tests/generic/793 b/tests/generic/793 new file mode 100644 index 000000000000..dd80212fad73 --- /dev/null +++ b/tests/generic/793 @@ -0,0 +1,73 @@ +#! /bin/bash +# SPDX-License-Identifier: GPL-2.0 +# Copyright (c) 2026 Anand Jain . All Rights Reserved. +# +# FS QA Test 793 +# Verify how libblkid resolve devices when multiple devices sharing the +# same FSUUID. + +. ./common/preamble +. ./common/filter + +_begin_fstest auto quick mount clone + +_require_test +_require_scratch_dev_pool 2 + +_cleanup() +{ + cd / + rm -r -f $tmp.* + umount $mnt2 2>/dev/null + _scratch_dev_pool_put +} + +filter_pool() +{ + _filter_scratch | \ + sed -e "s|${devs[1]}|DEV2|g" \ + -e "s|$mnt2|MNT2|g" | \ + _filter_spaces +} + +print_info() +{ + local mntpt=$1 + local tgt=$(findmnt -no SOURCE $mntpt) + local fsuuid=$(blkid -s UUID -o value $tgt) + + echo "mntpt=$mntpt tgt=$tgt fsuuid=$fsuuid" >> $seqres.full + echo + findmnt -o SOURCE,TARGET,UUID "$tgt" | tail -n +2 | \ + sed -e "s/$fsuuid/FSUUID/g" | filter_pool + awk -v dev="$tgt" '$1 == dev { print $1, $2 }' /proc/self/mounts | \ + filter_pool + df --all --output=source,target "$tgt" | tail -n +2 | filter_pool + echo +} + +_scratch_dev_pool_get 2 +_scratch_mkfs_sized_clone >$seqres.full 2>&1 +devs=($SCRATCH_DEV_POOL) +mnt2=$TEST_DIR/mnt2 +mkdir -p $mnt2 + +_scratch_mount $(_clone_mount_option) +_mount $(_common_dev_mount_options) $(_clone_mount_option) ${devs[1]} $mnt2 || \ + _fail "Failed to mount dev2" + +print_info $SCRATCH_MNT +print_info $mnt2 + +echo "**** mount cycle ****" +_scratch_unmount +_unmount $mnt2 +_mount $(_common_dev_mount_options) $(_clone_mount_option) ${devs[1]} $mnt2 || \ + _fail "Failed to mount dev2" +_scratch_mount $(_clone_mount_option) + +print_info $SCRATCH_MNT +print_info $mnt2 + +status=0 +exit diff --git a/tests/generic/793.out b/tests/generic/793.out new file mode 100644 index 000000000000..4c7c349ec4ed --- /dev/null +++ b/tests/generic/793.out @@ -0,0 +1,22 @@ +QA output created by 793 + +SCRATCH_DEV SCRATCH_MNT FSUUID +SCRATCH_DEV SCRATCH_MNT +SCRATCH_DEV SCRATCH_MNT + + +DEV2 MNT2 FSUUID +DEV2 MNT2 +DEV2 MNT2 + +**** mount cycle **** + +SCRATCH_DEV SCRATCH_MNT FSUUID +SCRATCH_DEV SCRATCH_MNT +SCRATCH_DEV SCRATCH_MNT + + +DEV2 MNT2 FSUUID +DEV2 MNT2 +DEV2 MNT2 + -- 2.43.0 Add testcase to verify IMA measurement isolation when multiple devices share the same FSUUID. Signed-off-by: Anand Jain --- tests/generic/794 | 101 ++++++++++++++++++++++++++++++++++++++++++ tests/generic/794.out | 10 +++++ 2 files changed, 111 insertions(+) create mode 100644 tests/generic/794 create mode 100644 tests/generic/794.out diff --git a/tests/generic/794 b/tests/generic/794 new file mode 100644 index 000000000000..e3bf3f9c6a7e --- /dev/null +++ b/tests/generic/794 @@ -0,0 +1,101 @@ +#! /bin/bash +# SPDX-License-Identifier: GPL-2.0 +# Copyright (c) 2026 Anand Jain . All Rights Reserved. +# +# FS QA Test 794 +# Verify IMA isolation on cloned filesystems: +# . Mount two devices sharing the same FSUUID (cloned). +# . Apply an IMA policy to measure files based on that FSUUID. +# . Create unique files on each mount point to trigger measurements. +# . Confirm the IMA log correctly attributes events to the respective mounts. + +. ./common/preamble +. ./common/filter + +_begin_fstest auto quick clone + +_require_test +_require_scratch_dev_pool 2 + +[ "$FSTYP" = "btrfs" ] && _fixed_by_kernel_commit xxxxxxxxxxxx \ + "btrfs: use on-disk uuid for s_uuid in temp_fsid mounts" +[ "$FSTYP" = "btrfs" ] && _fixed_by_kernel_commit xxxxxxxxxxxx \ + "btrfs: derive f_fsid from on-disk fsuuid and dev_t" + +_cleanup() +{ + cd / + rm -r -f $tmp.* + umount $mnt2 2>/dev/null + _scratch_dev_pool_put +} + +filter_pool() +{ + _filter_scratch | \ + sed -e "s|${devs[1]}|DEV2|g" \ + -e "s|$mnt2|MNT2|g" | \ + _filter_spaces +} + +do_ima() +{ + local ima_policy="/sys/kernel/security/ima/policy" + local ima_log="/sys/kernel/security/ima/ascii_runtime_measurements" + local fsuuid + local mnt=$1 + local run_enable=$2 + + # Since the in-memory IMA audit log is only cleared upon reboot, + # use unique random filenames to avoid log collisions. + local foofile=$(mktemp --dry-run foobar_XXXXX) + + echo $mnt $run_enable | filter_pool + + [ -w "$ima_policy" ] || _notrun "IMA policy not writable" + + fsuuid=$(blkid -s UUID -o value $SCRATCH_DEV) + + # Load IMA policy to measure file access specifically for this + # filesystem UUID. + if [[ $run_enable -eq 1 ]]; then + echo "measure func=FILE_CHECK fsuuid=$fsuuid" > "$ima_policy" || \ + _notrun "Policy rejected" + fi + + # Create a file to trigger measurement and verify its entry in + # the IMA log. + echo "test_data" > $mnt/$foofile + + # For $ima_log column entry please ref to + grep $foofile "$ima_log" | awk '{ print $5 }' | filter_pool | \ + sed "s/$foofile/FOOBAR_FILE/" + + echo "dbg: $mnt $fsuuid $foofile" >> $seqres.full + cat $ima_log | tail -1 >> $seqres.full + echo >> $seqres.full +} + +_scratch_dev_pool_get 2 +_scratch_mkfs_sized_clone >$seqres.full 2>&1 +devs=($SCRATCH_DEV_POOL) +mnt2=$TEST_DIR/mnt2 +mkdir -p $mnt2 + +_scratch_mount $(_clone_mount_option) +_mount $(_common_dev_mount_options) $(_clone_mount_option) ${devs[1]} $mnt2 || \ + _fail "Failed to mount dev2" + +do_ima $SCRATCH_MNT 1 +do_ima $mnt2 0 + +# Btrfs uses in-memory dynamic temp_fsid +echo mount cycle +_unmount $mnt2 +_mount $mount_opts ${devs[1]} $mnt2 || _fail "Failed to mount dev2" + +do_ima $SCRATCH_MNT 0 +do_ima $mnt2 0 + +status=0 +exit diff --git a/tests/generic/794.out b/tests/generic/794.out new file mode 100644 index 000000000000..026b365853e6 --- /dev/null +++ b/tests/generic/794.out @@ -0,0 +1,10 @@ +QA output created by 794 +SCRATCH_MNT 1 +SCRATCH_MNT/FOOBAR_FILE +MNT2 0 +MNT2/FOOBAR_FILE +mount cycle +SCRATCH_MNT 0 +SCRATCH_MNT/FOOBAR_FILE +MNT2 0 +MNT2/FOOBAR_FILE -- 2.43.0 Ensure that exportfs can correctly decode file handles on a cloned filesystem across a mount cycle, by file handles generated on a cloned device remain valid after mount cycle. Signed-off-by: Anand Jain --- tests/generic/795 | 67 +++++++++++++++++++++++++++++++++++++++++++ tests/generic/795.out | 2 ++ 2 files changed, 69 insertions(+) create mode 100644 tests/generic/795 create mode 100644 tests/generic/795.out diff --git a/tests/generic/795 b/tests/generic/795 new file mode 100644 index 000000000000..b6a75e500949 --- /dev/null +++ b/tests/generic/795 @@ -0,0 +1,67 @@ +#! /bin/bash +# SPDX-License-Identifier: GPL-2.0 +# Copyright (c) 2026 Anand Jain . All Rights Reserved. +# +# FS QA Test No. 795 + +. ./common/preamble + +_begin_fstest auto quick exportfs clone + +_require_test +_require_exportfs +_require_scratch_dev_pool 2 +_require_test_program "open_by_handle" + +_cleanup() +{ + cd / + rm -r -f $tmp.* + _unmount $mnt2 2>/dev/null + _scratch_dev_pool_put +} + +# Create test dir and test files, encode file handles and store to tmp file +create_test_files() +{ + rm -rf $testdir + mkdir -p $testdir + $here/src/open_by_handle -cwp -o $tmp.handles_file $testdir $NUMFILES +} + +# Decode file handles loaded from tmp file +test_file_handles() +{ + local opt=$1 + local when=$2 + + echo test_file_handles after $when + $here/src/open_by_handle $opt -i $tmp.handles_file $mnt2 $NUMFILES +} + +_scratch_dev_pool_get 2 +_scratch_mkfs_sized_clone >$seqres.full 2>&1 +devs=($SCRATCH_DEV_POOL) +mnt2=$TEST_DIR/mnt2 +mkdir -p $mnt2 + +_scratch_mount $(_clone_mount_option) +_mount $(_common_dev_mount_options) $(_clone_mount_option) ${devs[1]} $mnt2 || \ + _fail "Failed to mount dev2" + +NUMFILES=1 +testdir=$mnt2/testdir + +# Decode file handles of files/dir after cycle mount +create_test_files + +_scratch_unmount +_unmount $mnt2 +_mount $(_common_dev_mount_options) $(_clone_mount_option) ${devs[1]} $mnt2 || \ + _fail "Failed to mount dev2" +_scratch_mount $(_clone_mount_option) + +test_file_handles -rp "cycle mount" + +status=0 +exit diff --git a/tests/generic/795.out b/tests/generic/795.out new file mode 100644 index 000000000000..774fe7487d65 --- /dev/null +++ b/tests/generic/795.out @@ -0,0 +1,2 @@ +QA output created by 795 +test_file_handles after cycle mount -- 2.43.0