Re: [PATCH 5/9] fstests: verify fanotify isolation on cloned filesystems

Amir Goldstein
2026-03-01T13:15:55Z

On Thu, Feb 26, 2026 at 10:41:46PM +0800, Anand Jain wrote:
> 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 <asj@kernel.org>
> ---
> .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

Check if you already have fsnotifywait installed on your system
most likely you do. It was added to inotify-tools quite some time ago.
Could save you from adding a custom prog.
Not 100% sure about fsnotifywait, but quite sure that
fsnotifywatch --verbose prints the FSID of events.

Thanks,
Amir.

>
> 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 <asj@kernel.org>. All Rights Reserved.
> + *
> + * Simple fanotify monitor to verify mount-point event isolation.
> + */
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +#include <errno.h>
> +#include <string.h>
> +#include <stdint.h>
> +#include <sys/fanotify.h>
> +
> +int main(int argc, char *argv[])
> +{
> + int fd;
> + char buf[4096] __attribute__((aligned(8)));
> + setlinebuf(stdout);
> +
> + if (argc < 2) {
> + fprintf(stderr, "Usage: %s <path>\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 <asj@kernel.org>. 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
>