* [PATCH 1/1] generic: test fsnotify filesystem error reporting
2026-03-03 0:33 [PATCHSET v8 1/2] fstests: test generic file IO " Darrick J. Wong
@ 2026-03-03 0:40 ` Darrick J. Wong
2026-03-03 9:21 ` Amir Goldstein
2026-03-03 14:54 ` Christoph Hellwig
0 siblings, 2 replies; 22+ messages in thread
From: Darrick J. Wong @ 2026-03-03 0:40 UTC (permalink / raw)
To: zlang, djwong
Cc: linux-fsdevel, hch, gabriel, amir73il, jack, fstests, linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Test the fsnotify filesystem error reporting.
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
src/Makefile | 2
src/fs-monitor.c | 155 +++++++++++++++++++++++++++++++++
tests/generic/1838 | 228 ++++++++++++++++++++++++++++++++++++++++++++++++
tests/generic/1838.out | 20 ++++
4 files changed, 404 insertions(+), 1 deletion(-)
create mode 100644 src/fs-monitor.c
create mode 100755 tests/generic/1838
create mode 100644 tests/generic/1838.out
diff --git a/src/Makefile b/src/Makefile
index 577d816ae859b6..1c761da0ccff20 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 fs-monitor
EXTRA_EXECS = dmerror fill2attr fill2fs fill2fs_check scaleread.sh \
btrfs_crc32c_forged_name.py popdir.pl popattr.py \
diff --git a/src/fs-monitor.c b/src/fs-monitor.c
new file mode 100644
index 00000000000000..fef596a3966933
--- /dev/null
+++ b/src/fs-monitor.c
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2021, Collabora Ltd.
+ */
+
+#include <errno.h>
+#include <err.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/fanotify.h>
+#include <sys/types.h>
+#include <unistd.h>
+#ifndef __GLIBC__
+#include <asm-generic/int-ll64.h>
+#endif
+
+#ifndef FAN_FS_ERROR
+#define FAN_FS_ERROR 0x00008000
+#define FAN_EVENT_INFO_TYPE_ERROR 5
+
+struct fanotify_event_info_error {
+ struct fanotify_event_info_header hdr;
+ __s32 error;
+ __u32 error_count;
+};
+#endif
+
+#ifndef FILEID_INO32_GEN
+#define FILEID_INO32_GEN 1
+#endif
+
+#ifndef FILEID_INVALID
+#define FILEID_INVALID 0xff
+#endif
+
+static void print_fh(struct file_handle *fh)
+{
+ int i;
+ uint32_t *h = (uint32_t *) fh->f_handle;
+
+ printf("\tfh: ");
+ for (i = 0; i < fh->handle_bytes; i++)
+ printf("%hhx", fh->f_handle[i]);
+ printf("\n");
+
+ printf("\tdecoded fh: ");
+ if (fh->handle_type == FILEID_INO32_GEN)
+ printf("inode=%u gen=%u\n", h[0], h[1]);
+ else if (fh->handle_type == FILEID_INVALID && !fh->handle_bytes)
+ printf("Type %d (Superblock error)\n", fh->handle_type);
+ else
+ printf("Type %d (Unknown)\n", fh->handle_type);
+
+}
+
+static void handle_notifications(char *buffer, int len)
+{
+ struct fanotify_event_metadata *event =
+ (struct fanotify_event_metadata *) buffer;
+ struct fanotify_event_info_header *info;
+ struct fanotify_event_info_error *err;
+ struct fanotify_event_info_fid *fid;
+ int off;
+
+ for (; FAN_EVENT_OK(event, len); event = FAN_EVENT_NEXT(event, len)) {
+
+ if (event->mask != FAN_FS_ERROR) {
+ printf("unexpected FAN MARK: %llx\n",
+ (unsigned long long)event->mask);
+ goto next_event;
+ }
+
+ if (event->fd != FAN_NOFD) {
+ printf("Unexpected fd (!= FAN_NOFD)\n");
+ goto next_event;
+ }
+
+ printf("FAN_FS_ERROR (len=%d)\n", event->event_len);
+
+ for (off = sizeof(*event) ; off < event->event_len;
+ off += info->len) {
+ info = (struct fanotify_event_info_header *)
+ ((char *) event + off);
+
+ switch (info->info_type) {
+ case FAN_EVENT_INFO_TYPE_ERROR:
+ err = (struct fanotify_event_info_error *) info;
+
+ printf("\tGeneric Error Record: len=%d\n",
+ err->hdr.len);
+ printf("\terror: %d\n", err->error);
+ printf("\terror_count: %d\n", err->error_count);
+ break;
+
+ case FAN_EVENT_INFO_TYPE_FID:
+ fid = (struct fanotify_event_info_fid *) info;
+
+ printf("\tfsid: %x%x\n",
+#if defined(__GLIBC__)
+ fid->fsid.val[0], fid->fsid.val[1]);
+#else
+ fid->fsid.__val[0], fid->fsid.__val[1]);
+#endif
+ print_fh((struct file_handle *) &fid->handle);
+ break;
+
+ default:
+ printf("\tUnknown info type=%d len=%d:\n",
+ info->info_type, info->len);
+ }
+ }
+next_event:
+ printf("---\n\n");
+ fflush(stdout);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int fd;
+
+ char buffer[BUFSIZ];
+
+ if (argc < 2) {
+ printf("Missing path argument\n");
+ return 1;
+ }
+
+ fd = fanotify_init(FAN_CLASS_NOTIF|FAN_REPORT_FID, O_RDONLY);
+ if (fd < 0) {
+ perror("fanotify_init");
+ errx(1, "fanotify_init");
+ }
+
+ if (fanotify_mark(fd, FAN_MARK_ADD|FAN_MARK_FILESYSTEM,
+ FAN_FS_ERROR, AT_FDCWD, argv[1])) {
+ perror("fanotify_mark");
+ errx(1, "fanotify_mark");
+ }
+
+ printf("fanotify active\n");
+ fflush(stdout);
+
+ while (1) {
+ int n = read(fd, buffer, BUFSIZ);
+
+ if (n < 0)
+ errx(1, "read");
+
+ handle_notifications(buffer, n);
+ }
+
+ return 0;
+}
diff --git a/tests/generic/1838 b/tests/generic/1838
new file mode 100755
index 00000000000000..087851ddcbdb44
--- /dev/null
+++ b/tests/generic/1838
@@ -0,0 +1,228 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (c) 2024-2026 Oracle. All Rights Reserved.
+#
+# FS QA Test No. 1838
+#
+# Check that fsnotify can report file IO errors.
+
+. ./common/preamble
+_begin_fstest auto quick eio selfhealing
+
+# Override the default cleanup function.
+_cleanup()
+{
+ cd /
+ test -n "$fsmonitor_pid" && kill -TERM $fsmonitor_pid
+ rm -f $tmp.*
+ _dmerror_cleanup
+}
+
+# Import common functions.
+. ./common/fuzzy
+. ./common/filter
+. ./common/dmerror
+. ./common/systemd
+
+case "$FSTYP" in
+xfs)
+ # added as a part of xfs health monitoring
+ _require_xfs_io_command healthmon
+ # no out of place writes
+ _require_no_xfs_always_cow
+ ;;
+ext4)
+ # added at the same time as uevents
+ modprobe fs-$FSTYP
+ test -e /sys/fs/ext4/features/uevents || \
+ _notrun "$FSTYP does not support fsnotify ioerrors"
+ ;;
+*)
+ _notrun "$FSTYP does not support fsnotify ioerrors"
+ ;;
+esac
+
+_require_scratch
+_require_dm_target error
+_require_test_program fs-monitor
+_require_xfs_io_command "fiemap"
+_require_odirect
+
+# fsnotify only gives us a file handle, the error number, and the number of
+# times it was seen in between event deliveries. The handle is mostly useless
+# since we have no generic way to map that to a file path. Therefore we can
+# only coalesce all the I/O errors into one report.
+filter_fsnotify_errors() {
+ _filter_scratch | \
+ grep -E '(FAN_FS_ERROR|Generic Error Record|error: 5)' | \
+ sed -e "s/len=[0-9]*/len=XXX/g" | \
+ sort | \
+ uniq
+}
+
+_scratch_mkfs >> $seqres.full
+
+#
+# The dm-error map added by this test doesn't work on zoned devices because
+# table sizes need to be aligned to the zone size, and even for zoned on
+# conventional this test will get confused because of the internal RT device.
+#
+# That check requires a mounted file system, so do a dummy mount before setting
+# up DM.
+#
+_scratch_mount
+test $FSTYP = xfs && _require_xfs_scratch_non_zoned
+_scratch_unmount
+
+_dmerror_init
+_dmerror_mount >> $seqres.full 2>&1
+
+test $FSTYP = xfs && _xfs_force_bdev data $SCRATCH_MNT
+
+# Write a file with 4 file blocks worth of data, figure out the LBA to target
+victim=$SCRATCH_MNT/a
+file_blksz=$(_get_file_block_size $SCRATCH_MNT)
+$XFS_IO_PROG -f -c "pwrite -S 0x58 0 $((4 * file_blksz))" -c "fsync" $victim >> $seqres.full
+
+awk_len_prog='{print $4}'
+bmap_str="$($XFS_IO_PROG -c "fiemap -v" $victim | grep "^[[:space:]]*0:")"
+echo "$bmap_str" >> $seqres.full
+
+phys="$(echo "$bmap_str" | $AWK_PROG '{print $3}')"
+len="$(echo "$bmap_str" | $AWK_PROG "$awk_len_prog")"
+
+fs_blksz=$(_get_block_size $SCRATCH_MNT)
+echo "file_blksz:$file_blksz:fs_blksz:$fs_blksz" >> $seqres.full
+kernel_sectors_per_fs_block=$((fs_blksz / 512))
+
+# Did we get at least 4 fs blocks worth of extent?
+min_len_sectors=$(( 4 * kernel_sectors_per_fs_block ))
+test "$len" -lt $min_len_sectors && \
+ _fail "could not format a long enough extent on an empty fs??"
+
+phys_start=$(echo "$phys" | sed -e 's/\.\..*//g')
+
+echo "$phys:$len:$fs_blksz:$phys_start" >> $seqres.full
+echo "victim file:" >> $seqres.full
+od -tx1 -Ad -c $victim >> $seqres.full
+
+# Set the dmerror table so that all IO will pass through.
+_dmerror_reset_table
+
+cat >> $seqres.full << ENDL
+dmerror before:
+$DMERROR_TABLE
+$DMERROR_RTTABLE
+<end table>
+ENDL
+
+# All sector numbers that we feed to the kernel must be in units of 512b, but
+# they also must be aligned to the device's logical block size.
+logical_block_size=`$here/src/min_dio_alignment $SCRATCH_MNT $SCRATCH_DEV`
+kernel_sectors_per_device_lba=$((logical_block_size / 512))
+
+# Mark as bad one of the device LBAs in the middle of the extent. Target the
+# second LBA of the third block of the four-block file extent that we allocated
+# earlier, but without overflowing into the fourth file block.
+bad_sector=$(( phys_start + (2 * kernel_sectors_per_fs_block) ))
+bad_len=$kernel_sectors_per_device_lba
+if (( kernel_sectors_per_device_lba < kernel_sectors_per_fs_block )); then
+ bad_sector=$((bad_sector + kernel_sectors_per_device_lba))
+fi
+if (( (bad_sector % kernel_sectors_per_device_lba) != 0)); then
+ echo "bad_sector $bad_sector not congruent with device logical block size $logical_block_size"
+fi
+
+# Remount to flush the page cache, start fsnotify, and make the LBA bad
+_dmerror_unmount
+_dmerror_mount
+
+$here/src/fs-monitor $SCRATCH_MNT > $tmp.fsmonitor &
+fsmonitor_pid=$!
+sleep 1
+
+_dmerror_mark_range_bad $bad_sector $bad_len
+
+cat >> $seqres.full << ENDL
+dmerror after marking bad:
+$DMERROR_TABLE
+$DMERROR_RTTABLE
+<end table>
+ENDL
+
+_dmerror_load_error_table
+
+# See if buffered reads pick it up
+echo "Try buffered read"
+$XFS_IO_PROG -c "pread 0 $((4 * file_blksz))" $victim >> $seqres.full
+
+# See if directio reads pick it up
+echo "Try directio read"
+$XFS_IO_PROG -d -c "pread 0 $((4 * file_blksz))" $victim >> $seqres.full
+
+# See if directio writes pick it up
+echo "Try directio write"
+$XFS_IO_PROG -d -c "pwrite -S 0x58 0 $((4 * file_blksz))" -c fsync $victim >> $seqres.full
+
+# See if buffered writes pick it up
+echo "Try buffered write"
+$XFS_IO_PROG -c "pwrite -S 0x58 0 $((4 * file_blksz))" -c fsync $victim >> $seqres.full
+
+# Now mark the bad range good so that unmount won't fail due to IO errors.
+echo "Fix device"
+_dmerror_mark_range_good $bad_sector $bad_len
+_dmerror_load_error_table
+
+cat >> $seqres.full << ENDL
+dmerror after marking good:
+$DMERROR_TABLE
+$DMERROR_RTTABLE
+<end table>
+ENDL
+
+# Unmount filesystem to start fresh
+echo "Kill fsnotify"
+_dmerror_unmount
+sleep 1
+kill -TERM $fsmonitor_pid
+unset fsmonitor_pid
+echo fsnotify log >> $seqres.full
+cat $tmp.fsmonitor >> $seqres.full
+cat $tmp.fsmonitor | filter_fsnotify_errors
+
+# Start fsnotify again so that can verify that the errors don't persist after
+# we flip back to the good dm table.
+echo "Remount and restart fsnotify"
+_dmerror_mount
+$here/src/fs-monitor $SCRATCH_MNT > $tmp.fsmonitor &
+fsmonitor_pid=$!
+sleep 1
+
+# See if buffered reads pick it up
+echo "Try buffered read again"
+$XFS_IO_PROG -c "pread 0 $((4 * file_blksz))" $victim >> $seqres.full
+
+# See if directio reads pick it up
+echo "Try directio read again"
+$XFS_IO_PROG -d -c "pread 0 $((4 * file_blksz))" $victim >> $seqres.full
+
+# See if directio writes pick it up
+echo "Try directio write again"
+$XFS_IO_PROG -d -c "pwrite -S 0x58 0 $((4 * file_blksz))" -c fsync $victim >> $seqres.full
+
+# See if buffered writes pick it up
+echo "Try buffered write again"
+$XFS_IO_PROG -c "pwrite -S 0x58 0 $((4 * file_blksz))" -c fsync $victim >> $seqres.full
+
+# Unmount fs and kill fsnotify, then wait for it to finish
+echo "Kill fsnotify again"
+_dmerror_unmount
+sleep 1
+kill -TERM $fsmonitor_pid
+unset fsmonitor_pid
+cat $tmp.fsmonitor >> $seqres.full
+cat $tmp.fsmonitor | filter_fsnotify_errors
+
+# success, all done
+status=0
+exit
diff --git a/tests/generic/1838.out b/tests/generic/1838.out
new file mode 100644
index 00000000000000..adae590fe0b2ea
--- /dev/null
+++ b/tests/generic/1838.out
@@ -0,0 +1,20 @@
+QA output created by 1838
+Try buffered read
+pread: Input/output error
+Try directio read
+pread: Input/output error
+Try directio write
+pwrite: Input/output error
+Try buffered write
+fsync: Input/output error
+Fix device
+Kill fsnotify
+ Generic Error Record: len=XXX
+ error: 5
+FAN_FS_ERROR (len=XXX)
+Remount and restart fsnotify
+Try buffered read again
+Try directio read again
+Try directio write again
+Try buffered write again
+Kill fsnotify again
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH 1/1] generic: test fsnotify filesystem error reporting
2026-03-03 0:40 ` [PATCH 1/1] generic: test fsnotify filesystem " Darrick J. Wong
@ 2026-03-03 9:21 ` Amir Goldstein
2026-03-03 14:51 ` Christoph Hellwig
2026-03-03 14:54 ` Christoph Hellwig
1 sibling, 1 reply; 22+ messages in thread
From: Amir Goldstein @ 2026-03-03 9:21 UTC (permalink / raw)
To: Darrick J. Wong
Cc: zlang, linux-fsdevel, hch, gabriel, jack, fstests, linux-xfs
On Tue, Mar 3, 2026 at 1:40 AM Darrick J. Wong <djwong@kernel.org> wrote:
>
> From: Darrick J. Wong <djwong@kernel.org>
>
> Test the fsnotify filesystem error reporting.
For the record, I feel that I need to say to all the people whom we pushed back
on fanotify tests in fstests until there was a good enough reason to do so,
that this seems like a good reason to do so ;)
But also for future test writers, please note that FAN_FS_ERROR is an
exception to the rule and please keep writing new fanotify/inotify tests in LTP
(until there is a good enough reason...)
>
> Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
> ---
> src/Makefile | 2
> src/fs-monitor.c | 155 +++++++++++++++++++++++++++++++++
> tests/generic/1838 | 228 ++++++++++++++++++++++++++++++++++++++++++++++++
> tests/generic/1838.out | 20 ++++
> 4 files changed, 404 insertions(+), 1 deletion(-)
> create mode 100644 src/fs-monitor.c
> create mode 100755 tests/generic/1838
> create mode 100644 tests/generic/1838.out
>
>
...
> diff --git a/tests/generic/1838 b/tests/generic/1838
> new file mode 100755
> index 00000000000000..087851ddcbdb44
> --- /dev/null
> +++ b/tests/generic/1838
> @@ -0,0 +1,228 @@
> +#! /bin/bash
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +# Copyright (c) 2024-2026 Oracle. All Rights Reserved.
> +#
> +# FS QA Test No. 1838
> +#
> +# Check that fsnotify can report file IO errors.
> +
> +. ./common/preamble
> +_begin_fstest auto quick eio selfhealing
> +
> +# Override the default cleanup function.
> +_cleanup()
> +{
> + cd /
> + test -n "$fsmonitor_pid" && kill -TERM $fsmonitor_pid
> + rm -f $tmp.*
> + _dmerror_cleanup
> +}
> +
> +# Import common functions.
> +. ./common/fuzzy
> +. ./common/filter
> +. ./common/dmerror
> +. ./common/systemd
> +
> +case "$FSTYP" in
> +xfs)
> + # added as a part of xfs health monitoring
> + _require_xfs_io_command healthmon
> + # no out of place writes
> + _require_no_xfs_always_cow
> + ;;
> +ext4)
> + # added at the same time as uevents
> + modprobe fs-$FSTYP
> + test -e /sys/fs/ext4/features/uevents || \
> + _notrun "$FSTYP does not support fsnotify ioerrors"
> + ;;
> +*)
> + _notrun "$FSTYP does not support fsnotify ioerrors"
> + ;;
> +esac
> +
_require_fsnotify_errors ?
> +_require_scratch
> +_require_dm_target error
> +_require_test_program fs-monitor
> +_require_xfs_io_command "fiemap"
> +_require_odirect
> +
> +# fsnotify only gives us a file handle, the error number, and the number of
> +# times it was seen in between event deliveries. The handle is mostly useless
> +# since we have no generic way to map that to a file path. Therefore we can
> +# only coalesce all the I/O errors into one report.
> +filter_fsnotify_errors() {
> + _filter_scratch | \
> + grep -E '(FAN_FS_ERROR|Generic Error Record|error: 5)' | \
> + sed -e "s/len=[0-9]*/len=XXX/g" | \
> + sort | \
> + uniq
> +}
move to common/filter?
Apart from those nits, no further comments.
Thanks,
Amir.
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 1/1] generic: test fsnotify filesystem error reporting
2026-03-03 9:21 ` Amir Goldstein
@ 2026-03-03 14:51 ` Christoph Hellwig
2026-03-03 14:56 ` Amir Goldstein
2026-03-04 10:10 ` Jan Kara
0 siblings, 2 replies; 22+ messages in thread
From: Christoph Hellwig @ 2026-03-03 14:51 UTC (permalink / raw)
To: Amir Goldstein
Cc: Darrick J. Wong, zlang, linux-fsdevel, hch, gabriel, jack,
fstests, linux-xfs
On Tue, Mar 03, 2026 at 10:21:04AM +0100, Amir Goldstein wrote:
> On Tue, Mar 3, 2026 at 1:40 AM Darrick J. Wong <djwong@kernel.org> wrote:
> >
> > From: Darrick J. Wong <djwong@kernel.org>
> >
> > Test the fsnotify filesystem error reporting.
>
> For the record, I feel that I need to say to all the people whom we pushed back
> on fanotify tests in fstests until there was a good enough reason to do so,
> that this seems like a good reason to do so ;)
Who pushed backed on that? Because IMHO hiding stuff in ltp is a sure
way it doesn't get exercisesd regularly?
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 1/1] generic: test fsnotify filesystem error reporting
2026-03-03 0:40 ` [PATCH 1/1] generic: test fsnotify filesystem " Darrick J. Wong
2026-03-03 9:21 ` Amir Goldstein
@ 2026-03-03 14:54 ` Christoph Hellwig
2026-03-03 16:06 ` Gabriel Krisman Bertazi
2026-03-03 16:49 ` Darrick J. Wong
1 sibling, 2 replies; 22+ messages in thread
From: Christoph Hellwig @ 2026-03-03 14:54 UTC (permalink / raw)
To: Darrick J. Wong
Cc: zlang, linux-fsdevel, hch, gabriel, amir73il, jack, fstests,
linux-xfs
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright 2021, Collabora Ltd.
> + */
Where is this coming from?
> +#ifndef __GLIBC__
> +#include <asm-generic/int-ll64.h>
> +#endif
And what is this for? Looks pretty whacky.
> +case "$FSTYP" in
> +xfs)
> + # added as a part of xfs health monitoring
> + _require_xfs_io_command healthmon
> + # no out of place writes
> + _require_no_xfs_always_cow
> + ;;
> +ext4)
> + # added at the same time as uevents
> + modprobe fs-$FSTYP
> + test -e /sys/fs/ext4/features/uevents || \
> + _notrun "$FSTYP does not support fsnotify ioerrors"
> + ;;
> +*)
> + _notrun "$FSTYP does not support fsnotify ioerrors"
> + ;;
> +esac
Please abstract this out into a documented helper in common/
> +#
> +# The dm-error map added by this test doesn't work on zoned devices because
> +# table sizes need to be aligned to the zone size, and even for zoned on
> +# conventional this test will get confused because of the internal RT device.
> +#
> +# That check requires a mounted file system, so do a dummy mount before setting
> +# up DM.
> +#
> +_scratch_mount
> +test $FSTYP = xfs && _require_xfs_scratch_non_zoned
> +_scratch_unmount
Hmm, this is a bit sad. Can we align the map? Or should we carve in
and add proper error injection to the block code, which has been
somewhere on my todo list forever because dm-error and friends are
so painful to setup. Maybe I need to expedite that.
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 1/1] generic: test fsnotify filesystem error reporting
2026-03-03 14:51 ` Christoph Hellwig
@ 2026-03-03 14:56 ` Amir Goldstein
2026-03-04 10:10 ` Jan Kara
1 sibling, 0 replies; 22+ messages in thread
From: Amir Goldstein @ 2026-03-03 14:56 UTC (permalink / raw)
To: Christoph Hellwig
Cc: Darrick J. Wong, zlang, linux-fsdevel, hch, gabriel, jack,
fstests, linux-xfs
On Tue, Mar 3, 2026 at 3:51 PM Christoph Hellwig <hch@infradead.org> wrote:
>
> On Tue, Mar 03, 2026 at 10:21:04AM +0100, Amir Goldstein wrote:
> > On Tue, Mar 3, 2026 at 1:40 AM Darrick J. Wong <djwong@kernel.org> wrote:
> > >
> > > From: Darrick J. Wong <djwong@kernel.org>
> > >
> > > Test the fsnotify filesystem error reporting.
> >
> > For the record, I feel that I need to say to all the people whom we pushed back
> > on fanotify tests in fstests until there was a good enough reason to do so,
> > that this seems like a good reason to do so ;)
>
> Who pushed backed on that? Because IMHO hiding stuff in ltp is a sure
> way it doesn't get exercisesd regularly?
>
Jan and myself pushed back on adding generic fanotify tests to fstest
because we already have most fanotify tests in LTP.
LTP is run by many testers on many boxes and many release
kernels and we are happy with this project to host tests for the
subsystem that we maintain.
Thanks,
Amir.
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 1/1] generic: test fsnotify filesystem error reporting
2026-03-03 14:54 ` Christoph Hellwig
@ 2026-03-03 16:06 ` Gabriel Krisman Bertazi
2026-03-03 16:12 ` Christoph Hellwig
2026-03-03 16:49 ` Darrick J. Wong
1 sibling, 1 reply; 22+ messages in thread
From: Gabriel Krisman Bertazi @ 2026-03-03 16:06 UTC (permalink / raw)
To: Christoph Hellwig
Cc: Darrick J. Wong, zlang, linux-fsdevel, hch, amir73il, jack,
fstests, linux-xfs
Christoph Hellwig <hch@infradead.org> writes:
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright 2021, Collabora Ltd.
>> + */
>
> Where is this coming from?
This code is heavily based, if not the same, to what I originally wrote
as a kernel tree "samples/fs-monitor.c" when I was employed by
Collabora. I appreciate Darrick keeping the note actually.
>
>> +#ifndef __GLIBC__
>> +#include <asm-generic/int-ll64.h>
>> +#endif
>
> And what is this for? Looks pretty whacky.
Comes from kernel commit 3193e8942fc7 ("samples: fix building fs-monitor
on musl systems") to fix building with musl. We don't need it here.
--
Gabriel Krisman Bertazi
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 1/1] generic: test fsnotify filesystem error reporting
2026-03-03 16:06 ` Gabriel Krisman Bertazi
@ 2026-03-03 16:12 ` Christoph Hellwig
2026-03-03 16:38 ` Darrick J. Wong
0 siblings, 1 reply; 22+ messages in thread
From: Christoph Hellwig @ 2026-03-03 16:12 UTC (permalink / raw)
To: Gabriel Krisman Bertazi
Cc: Christoph Hellwig, Darrick J. Wong, zlang, linux-fsdevel, hch,
amir73il, jack, fstests, linux-xfs
On Tue, Mar 03, 2026 at 11:06:52AM -0500, Gabriel Krisman Bertazi wrote:
> Christoph Hellwig <hch@infradead.org> writes:
>
> >> +// SPDX-License-Identifier: GPL-2.0
> >> +/*
> >> + * Copyright 2021, Collabora Ltd.
> >> + */
> >
> > Where is this coming from?
>
> This code is heavily based, if not the same, to what I originally wrote
> as a kernel tree "samples/fs-monitor.c" when I was employed by
> Collabora. I appreciate Darrick keeping the note actually.
The note is good. But if we import code from somewhere, we should
document where it is coming from, both for attribution and to ease
any future resyncs if needed.
> >> +#ifndef __GLIBC__
> >> +#include <asm-generic/int-ll64.h>
> >> +#endif
> >
> > And what is this for? Looks pretty whacky.
>
> Comes from kernel commit 3193e8942fc7 ("samples: fix building fs-monitor
> on musl systems") to fix building with musl. We don't need it here.
In the place that needs it it really should have a comment explainig
the logic behind it.
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 1/1] generic: test fsnotify filesystem error reporting
2026-03-03 16:12 ` Christoph Hellwig
@ 2026-03-03 16:38 ` Darrick J. Wong
0 siblings, 0 replies; 22+ messages in thread
From: Darrick J. Wong @ 2026-03-03 16:38 UTC (permalink / raw)
To: Christoph Hellwig
Cc: Gabriel Krisman Bertazi, zlang, linux-fsdevel, hch, amir73il,
jack, fstests, linux-xfs
On Tue, Mar 03, 2026 at 08:12:55AM -0800, Christoph Hellwig wrote:
> On Tue, Mar 03, 2026 at 11:06:52AM -0500, Gabriel Krisman Bertazi wrote:
> > Christoph Hellwig <hch@infradead.org> writes:
> >
> > >> +// SPDX-License-Identifier: GPL-2.0
> > >> +/*
> > >> + * Copyright 2021, Collabora Ltd.
> > >> + */
> > >
> > > Where is this coming from?
> >
> > This code is heavily based, if not the same, to what I originally wrote
> > as a kernel tree "samples/fs-monitor.c" when I was employed by
> > Collabora. I appreciate Darrick keeping the note actually.
>
> The note is good. But if we import code from somewhere, we should
> document where it is coming from, both for attribution and to ease
> any future resyncs if needed.
Yeah, I copied this straight from the kernel tree, which is why it
contains this wart:
> > >> +#ifndef __GLIBC__
> > >> +#include <asm-generic/int-ll64.h>
> > >> +#endif
> > >
> > > And what is this for? Looks pretty whacky.
> >
> > Comes from kernel commit 3193e8942fc7 ("samples: fix building fs-monitor
> > on musl systems") to fix building with musl. We don't need it here.
>
> In the place that needs it it really should have a comment explainig
> the logic behind it.
I don't know that people *don't* try to run fstests with musl. But as
they seem surprisingly patient with continuously fixing up xfsprogs,
perhaps it's ok to clean this up on the way into fstests.
I'll add more attribution for the c file pointing back to where it came
from.
--D
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 1/1] generic: test fsnotify filesystem error reporting
2026-03-03 14:54 ` Christoph Hellwig
2026-03-03 16:06 ` Gabriel Krisman Bertazi
@ 2026-03-03 16:49 ` Darrick J. Wong
2026-03-03 16:53 ` Christoph Hellwig
1 sibling, 1 reply; 22+ messages in thread
From: Darrick J. Wong @ 2026-03-03 16:49 UTC (permalink / raw)
To: Christoph Hellwig
Cc: zlang, linux-fsdevel, hch, gabriel, amir73il, jack, fstests,
linux-xfs
On Tue, Mar 03, 2026 at 06:54:29AM -0800, Christoph Hellwig wrote:
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright 2021, Collabora Ltd.
> > + */
>
> Where is this coming from?
>
> > +#ifndef __GLIBC__
> > +#include <asm-generic/int-ll64.h>
> > +#endif
>
> And what is this for? Looks pretty whacky.
>
> > +case "$FSTYP" in
> > +xfs)
> > + # added as a part of xfs health monitoring
> > + _require_xfs_io_command healthmon
> > + # no out of place writes
> > + _require_no_xfs_always_cow
> > + ;;
> > +ext4)
> > + # added at the same time as uevents
> > + modprobe fs-$FSTYP
> > + test -e /sys/fs/ext4/features/uevents || \
> > + _notrun "$FSTYP does not support fsnotify ioerrors"
> > + ;;
> > +*)
> > + _notrun "$FSTYP does not support fsnotify ioerrors"
> > + ;;
> > +esac
>
> Please abstract this out into a documented helper in common/
Ok. I'm not sure how to check for feature support on ext4 anymore since
the uevents patch didn't get merged, and then I clearly forgot to rip
that out of this helper here.
> > +#
> > +# The dm-error map added by this test doesn't work on zoned devices because
> > +# table sizes need to be aligned to the zone size, and even for zoned on
> > +# conventional this test will get confused because of the internal RT device.
> > +#
> > +# That check requires a mounted file system, so do a dummy mount before setting
> > +# up DM.
> > +#
> > +_scratch_mount
> > +test $FSTYP = xfs && _require_xfs_scratch_non_zoned
> > +_scratch_unmount
>
> Hmm, this is a bit sad. Can we align the map? Or should we carve in
> and add proper error injection to the block code, which has been
> somewhere on my todo list forever because dm-error and friends are
> so painful to setup. Maybe I need to expedite that.
I think it's theoretically possible to figure out that there's a zone
size and then round outwards the error-target part of the dm table to
align with a zone. I have a lot more doubts about whether or not doing
that in bash/awk is a good idea though. It'd be a lot easier if either
the block layer did error injection or if someone just fixes those
limitations in dm itself.
--D
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 1/1] generic: test fsnotify filesystem error reporting
2026-03-03 16:49 ` Darrick J. Wong
@ 2026-03-03 16:53 ` Christoph Hellwig
2026-03-03 17:59 ` Darrick J. Wong
0 siblings, 1 reply; 22+ messages in thread
From: Christoph Hellwig @ 2026-03-03 16:53 UTC (permalink / raw)
To: Darrick J. Wong
Cc: Christoph Hellwig, zlang, linux-fsdevel, hch, gabriel, amir73il,
jack, fstests, linux-xfs
On Tue, Mar 03, 2026 at 08:49:01AM -0800, Darrick J. Wong wrote:
> > > +ext4)
> > > + # added at the same time as uevents
> > > + modprobe fs-$FSTYP
> > > + test -e /sys/fs/ext4/features/uevents || \
> > > + _notrun "$FSTYP does not support fsnotify ioerrors"
> > > + ;;
> > > +*)
> > > + _notrun "$FSTYP does not support fsnotify ioerrors"
> > > + ;;
> > > +esac
> >
> > Please abstract this out into a documented helper in common/
>
> Ok. I'm not sure how to check for feature support on ext4 anymore since
> the uevents patch didn't get merged, and then I clearly forgot to rip
> that out of this helper here.
Oh. Well, drop that then and move the xfs side and the default n
into a common helper instead of hardcoding it in the test.
> > and add proper error injection to the block code, which has been
> > somewhere on my todo list forever because dm-error and friends are
> > so painful to setup. Maybe I need to expedite that.
>
> I think it's theoretically possible to figure out that there's a zone
> size and then round outwards the error-target part of the dm table to
> align with a zone.
It's the sysfs chunk size. btrfs/237 harcodes reading that out,
which could be easily lifted into a helper.
> I have a lot more doubts about whether or not doing
> that in bash/awk is a good idea though. It'd be a lot easier if either
> the block layer did error injection or if someone just fixes those
> limitations in dm itself.
I'll sign up to do the block layer stuff. Doing so should allow us
to run a lot more of the error injetion tests on zoned xfs, which
would be good. So I guess you should keep it as-is for now,
and I'll do a sweep later.
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 1/1] generic: test fsnotify filesystem error reporting
2026-03-03 16:53 ` Christoph Hellwig
@ 2026-03-03 17:59 ` Darrick J. Wong
0 siblings, 0 replies; 22+ messages in thread
From: Darrick J. Wong @ 2026-03-03 17:59 UTC (permalink / raw)
To: Christoph Hellwig
Cc: zlang, linux-fsdevel, hch, gabriel, amir73il, jack, fstests,
linux-xfs
On Tue, Mar 03, 2026 at 08:53:12AM -0800, Christoph Hellwig wrote:
> On Tue, Mar 03, 2026 at 08:49:01AM -0800, Darrick J. Wong wrote:
> > > > +ext4)
> > > > + # added at the same time as uevents
> > > > + modprobe fs-$FSTYP
> > > > + test -e /sys/fs/ext4/features/uevents || \
> > > > + _notrun "$FSTYP does not support fsnotify ioerrors"
> > > > + ;;
> > > > +*)
> > > > + _notrun "$FSTYP does not support fsnotify ioerrors"
> > > > + ;;
> > > > +esac
> > >
> > > Please abstract this out into a documented helper in common/
> >
> > Ok. I'm not sure how to check for feature support on ext4 anymore since
> > the uevents patch didn't get merged, and then I clearly forgot to rip
> > that out of this helper here.
>
> Oh. Well, drop that then and move the xfs side and the default n
> into a common helper instead of hardcoding it in the test.
/me discovers that Baolin Liu added a "err_report_sec" sysfs knob to
ext4 in 7.0-rc1, so I can just change the helper to look for that. I'll
move the logic to common/rc.
> > > and add proper error injection to the block code, which has been
> > > somewhere on my todo list forever because dm-error and friends are
> > > so painful to setup. Maybe I need to expedite that.
> >
> > I think it's theoretically possible to figure out that there's a zone
> > size and then round outwards the error-target part of the dm table to
> > align with a zone.
>
> It's the sysfs chunk size. btrfs/237 harcodes reading that out,
> which could be easily lifted into a helper.
>
> > I have a lot more doubts about whether or not doing
> > that in bash/awk is a good idea though. It'd be a lot easier if either
> > the block layer did error injection or if someone just fixes those
> > limitations in dm itself.
>
> I'll sign up to do the block layer stuff. Doing so should allow us
> to run a lot more of the error injetion tests on zoned xfs, which
> would be good. So I guess you should keep it as-is for now,
> and I'll do a sweep later.
Ok, thanks. :)
--D
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 1/1] generic: test fsnotify filesystem error reporting
2026-03-03 14:51 ` Christoph Hellwig
2026-03-03 14:56 ` Amir Goldstein
@ 2026-03-04 10:10 ` Jan Kara
1 sibling, 0 replies; 22+ messages in thread
From: Jan Kara @ 2026-03-04 10:10 UTC (permalink / raw)
To: Christoph Hellwig
Cc: Amir Goldstein, Darrick J. Wong, zlang, linux-fsdevel, hch,
gabriel, jack, fstests, linux-xfs
On Tue 03-03-26 06:51:19, Christoph Hellwig wrote:
> On Tue, Mar 03, 2026 at 10:21:04AM +0100, Amir Goldstein wrote:
> > On Tue, Mar 3, 2026 at 1:40 AM Darrick J. Wong <djwong@kernel.org> wrote:
> > >
> > > From: Darrick J. Wong <djwong@kernel.org>
> > >
> > > Test the fsnotify filesystem error reporting.
> >
> > For the record, I feel that I need to say to all the people whom we pushed back
> > on fanotify tests in fstests until there was a good enough reason to do so,
> > that this seems like a good reason to do so ;)
>
> Who pushed backed on that? Because IMHO hiding stuff in ltp is a sure
> way it doesn't get exercisesd regularly?
Amir wrote it well, I'd just add the 0-day runs LTP, distro people run LTP
and lot of other test bots also run LTP so I wouldn't say fsnotify tests
are not exercised regularly. For record I don't expect regular filesystem
developers to need to run fsnotify tests as the code is generally well
separated from individual filesystems. Filesystem error reporting is kind
of special in this regard so I agree having it in fstests makes sense.
Honza
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCHSET v9 1/2] fstests: test generic file IO error reporting
[not found] <20260310033846.GH1105363@frogsfrogsfrogs>
@ 2026-03-10 3:42 ` Darrick J. Wong
2026-03-10 3:50 ` [PATCH 1/1] generic: test fsnotify filesystem " Darrick J. Wong
0 siblings, 1 reply; 22+ messages in thread
From: Darrick J. Wong @ 2026-03-10 3:42 UTC (permalink / raw)
To: zlang, djwong
Cc: jack, fstests, amir73il, gabriel, linux-fsdevel, linux-xfs, hch
Hi all,
Refactor the iomap file I/O error handling code so that failures are
reported in a generic way to fsnotify. Then connect the XFS health
reporting to the same fsnotify, and now XFS can notify userspace of
problems.
v9: tweak fstests per userspace changes; improve attribution of the
generic fserror test; fix some bugs pointed out by zorro
If you're going to start using this code, I strongly recommend pulling
from my git trees, which are linked below.
With a bit of luck, this should all go splendidly.
Comments and questions are, as always, welcome.
--D
kernel git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/xfs-linux.git/log/?h=filesystem-error-reporting
fstests git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/xfstests-dev.git/log/?h=filesystem-error-reporting
---
Commits in this patchset:
* generic: test fsnotify filesystem error reporting
---
common/rc | 25 ++++++
doc/group-names.txt | 1
src/Makefile | 2
src/fs-monitor.c | 153 ++++++++++++++++++++++++++++++++++
tests/generic/1838 | 214 ++++++++++++++++++++++++++++++++++++++++++++++++
tests/generic/1838.out | 20 ++++
6 files changed, 414 insertions(+), 1 deletion(-)
create mode 100644 src/fs-monitor.c
create mode 100755 tests/generic/1838
create mode 100644 tests/generic/1838.out
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 1/1] generic: test fsnotify filesystem error reporting
2026-03-10 3:42 ` [PATCHSET v9 1/2] fstests: test generic file IO error reporting Darrick J. Wong
@ 2026-03-10 3:50 ` Darrick J. Wong
2026-03-10 7:07 ` Amir Goldstein
` (2 more replies)
0 siblings, 3 replies; 22+ messages in thread
From: Darrick J. Wong @ 2026-03-10 3:50 UTC (permalink / raw)
To: zlang, djwong
Cc: jack, fstests, amir73il, gabriel, linux-fsdevel, linux-xfs, hch
From: Darrick J. Wong <djwong@kernel.org>
Test the fsnotify filesystem error reporting.
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
common/rc | 25 ++++++
doc/group-names.txt | 1
src/Makefile | 2
src/fs-monitor.c | 153 ++++++++++++++++++++++++++++++++++
tests/generic/1838 | 214 ++++++++++++++++++++++++++++++++++++++++++++++++
tests/generic/1838.out | 20 ++++
6 files changed, 414 insertions(+), 1 deletion(-)
create mode 100644 src/fs-monitor.c
create mode 100755 tests/generic/1838
create mode 100644 tests/generic/1838.out
diff --git a/common/rc b/common/rc
index fd4ca9641822cf..ccb78baf5bd41a 100644
--- a/common/rc
+++ b/common/rc
@@ -3013,6 +3013,11 @@ _require_xfs_io_command()
echo $testio | grep -q "Inappropriate ioctl" && \
_notrun "xfs_io $command support is missing"
;;
+ "healthmon")
+ test -z "$param" && param="-p"
+ testio=`$XFS_IO_PROG -c "healthmon $param" $TEST_DIR 2>&1`
+ param_checked="$param"
+ ;;
"label")
testio=`$XFS_IO_PROG -c "label" $TEST_DIR 2>&1`
;;
@@ -6149,6 +6154,26 @@ _require_max_file_range_blocks()
esac
}
+_require_fanotify_ioerrors()
+{
+ local x
+
+ case "$FSTYP" in
+ xfs)
+ # added as a part of xfs health monitoring
+ _require_xfs_io_command healthmon
+ return 0
+ ;;
+ ext4)
+ # added at the same time as err_report_sec
+ x="$(_get_fs_sysfs_attr $TEST_DEV err_report_sec)"
+ test -n "$x" && return 0
+ ;;
+ esac
+
+ _notrun "$FSTYP does not support fanotify ioerrors"
+}
+
################################################################################
# make sure this script returns success
/bin/true
diff --git a/doc/group-names.txt b/doc/group-names.txt
index 10b49e50517797..158f84d36d3154 100644
--- a/doc/group-names.txt
+++ b/doc/group-names.txt
@@ -117,6 +117,7 @@ samefs overlayfs when all layers are on the same fs
scrub filesystem metadata scrubbers
seed btrfs seeded filesystems
seek llseek functionality
+selfhealing self healing filesystem code
selftest tests with fixed results, used to validate testing setup
send btrfs send/receive
shrinkfs decreasing the size of a filesystem
diff --git a/src/Makefile b/src/Makefile
index 577d816ae859b6..1c761da0ccff20 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 fs-monitor
EXTRA_EXECS = dmerror fill2attr fill2fs fill2fs_check scaleread.sh \
btrfs_crc32c_forged_name.py popdir.pl popattr.py \
diff --git a/src/fs-monitor.c b/src/fs-monitor.c
new file mode 100644
index 00000000000000..0cf09677a3efda
--- /dev/null
+++ b/src/fs-monitor.c
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2021, Collabora Ltd.
+ * Copied from https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/samples/fanotify/fs-monitor.c
+ */
+
+#include <errno.h>
+#include <err.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/fanotify.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#ifndef FAN_FS_ERROR
+#define FAN_FS_ERROR 0x00008000
+#define FAN_EVENT_INFO_TYPE_ERROR 5
+
+struct fanotify_event_info_error {
+ struct fanotify_event_info_header hdr;
+ __s32 error;
+ __u32 error_count;
+};
+#endif
+
+#ifndef FILEID_INO32_GEN
+#define FILEID_INO32_GEN 1
+#endif
+
+#ifndef FILEID_INVALID
+#define FILEID_INVALID 0xff
+#endif
+
+static void print_fh(struct file_handle *fh)
+{
+ int i;
+ uint32_t *h = (uint32_t *) fh->f_handle;
+
+ printf("\tfh: ");
+ for (i = 0; i < fh->handle_bytes; i++)
+ printf("%hhx", fh->f_handle[i]);
+ printf("\n");
+
+ printf("\tdecoded fh: ");
+ if (fh->handle_type == FILEID_INO32_GEN)
+ printf("inode=%u gen=%u\n", h[0], h[1]);
+ else if (fh->handle_type == FILEID_INVALID && !fh->handle_bytes)
+ printf("Type %d (Superblock error)\n", fh->handle_type);
+ else
+ printf("Type %d (Unknown)\n", fh->handle_type);
+
+}
+
+static void handle_notifications(char *buffer, int len)
+{
+ struct fanotify_event_metadata *event =
+ (struct fanotify_event_metadata *) buffer;
+ struct fanotify_event_info_header *info;
+ struct fanotify_event_info_error *err;
+ struct fanotify_event_info_fid *fid;
+ int off;
+
+ for (; FAN_EVENT_OK(event, len); event = FAN_EVENT_NEXT(event, len)) {
+
+ if (event->mask != FAN_FS_ERROR) {
+ printf("unexpected FAN MARK: %llx\n",
+ (unsigned long long)event->mask);
+ goto next_event;
+ }
+
+ if (event->fd != FAN_NOFD) {
+ printf("Unexpected fd (!= FAN_NOFD)\n");
+ goto next_event;
+ }
+
+ printf("FAN_FS_ERROR (len=%d)\n", event->event_len);
+
+ for (off = sizeof(*event) ; off < event->event_len;
+ off += info->len) {
+ info = (struct fanotify_event_info_header *)
+ ((char *) event + off);
+
+ switch (info->info_type) {
+ case FAN_EVENT_INFO_TYPE_ERROR:
+ err = (struct fanotify_event_info_error *) info;
+
+ printf("\tGeneric Error Record: len=%d\n",
+ err->hdr.len);
+ printf("\terror: %d\n", err->error);
+ printf("\terror_count: %d\n", err->error_count);
+ break;
+
+ case FAN_EVENT_INFO_TYPE_FID:
+ fid = (struct fanotify_event_info_fid *) info;
+
+ printf("\tfsid: %x%x\n",
+#if defined(__GLIBC__)
+ fid->fsid.val[0], fid->fsid.val[1]);
+#else
+ fid->fsid.__val[0], fid->fsid.__val[1]);
+#endif
+ print_fh((struct file_handle *) &fid->handle);
+ break;
+
+ default:
+ printf("\tUnknown info type=%d len=%d:\n",
+ info->info_type, info->len);
+ }
+ }
+next_event:
+ printf("---\n\n");
+ fflush(stdout);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int fd;
+
+ char buffer[BUFSIZ];
+
+ if (argc < 2) {
+ printf("Missing path argument\n");
+ return 1;
+ }
+
+ fd = fanotify_init(FAN_CLASS_NOTIF|FAN_REPORT_FID, O_RDONLY);
+ if (fd < 0) {
+ perror("fanotify_init");
+ errx(1, "fanotify_init");
+ }
+
+ if (fanotify_mark(fd, FAN_MARK_ADD|FAN_MARK_FILESYSTEM,
+ FAN_FS_ERROR, AT_FDCWD, argv[1])) {
+ perror("fanotify_mark");
+ errx(1, "fanotify_mark");
+ }
+
+ printf("fanotify active\n");
+ fflush(stdout);
+
+ while (1) {
+ int n = read(fd, buffer, BUFSIZ);
+
+ if (n < 0)
+ errx(1, "read");
+
+ handle_notifications(buffer, n);
+ }
+
+ return 0;
+}
diff --git a/tests/generic/1838 b/tests/generic/1838
new file mode 100755
index 00000000000000..940811baae3a6e
--- /dev/null
+++ b/tests/generic/1838
@@ -0,0 +1,214 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (c) 2024-2026 Oracle. All Rights Reserved.
+#
+# FS QA Test No. 1838
+#
+# Check that fsnotify can report file IO errors.
+
+. ./common/preamble
+_begin_fstest auto quick eio selfhealing
+
+# Override the default cleanup function.
+_cleanup()
+{
+ cd /
+ test -n "$fsmonitor_pid" && kill -TERM $fsmonitor_pid
+ rm -f $tmp.*
+ _dmerror_cleanup
+}
+
+# Import common functions.
+. ./common/fuzzy
+. ./common/filter
+. ./common/dmerror
+. ./common/systemd
+
+_require_scratch
+_require_dm_target error
+_require_test_program fs-monitor
+_require_xfs_io_command "fiemap"
+_require_odirect
+_require_fanotify_ioerrors
+
+# no out of place writes
+test "$FSTYP" = "xfs" && _require_no_xfs_always_cow
+
+# fsnotify only gives us a file handle, the error number, and the number of
+# times it was seen in between event deliveries. The handle is mostly useless
+# since we have no generic way to map that to a file path. Therefore we can
+# only coalesce all the I/O errors into one report.
+filter_fsnotify_errors() {
+ _filter_scratch | \
+ grep -E '(FAN_FS_ERROR|Generic Error Record|error: 5)' | \
+ sed -e "s/len=[0-9]*/len=XXX/g" | \
+ sort | \
+ uniq
+}
+
+_scratch_mkfs >> $seqres.full
+
+#
+# The dm-error map added by this test doesn't work on zoned devices because
+# table sizes need to be aligned to the zone size, and even for zoned on
+# conventional this test will get confused because of the internal RT device.
+#
+# That check requires a mounted file system, so do a dummy mount before setting
+# up DM.
+#
+_scratch_mount
+test $FSTYP = xfs && _require_xfs_scratch_non_zoned
+_scratch_unmount
+
+_dmerror_init
+_dmerror_mount >> $seqres.full 2>&1
+
+test $FSTYP = xfs && _xfs_force_bdev data $SCRATCH_MNT
+
+# Write a file with 4 file blocks worth of data, figure out the LBA to target
+victim=$SCRATCH_MNT/a
+file_blksz=$(_get_file_block_size $SCRATCH_MNT)
+$XFS_IO_PROG -f -c "pwrite -S 0x58 0 $((4 * file_blksz))" -c "fsync" $victim >> $seqres.full
+
+awk_len_prog='{print $4}'
+bmap_str="$($XFS_IO_PROG -c "fiemap -v" $victim | grep "^[[:space:]]*0:")"
+echo "$bmap_str" >> $seqres.full
+
+phys="$(echo "$bmap_str" | $AWK_PROG '{print $3}')"
+len="$(echo "$bmap_str" | $AWK_PROG "$awk_len_prog")"
+
+fs_blksz=$(_get_block_size $SCRATCH_MNT)
+echo "file_blksz:$file_blksz:fs_blksz:$fs_blksz" >> $seqres.full
+kernel_sectors_per_fs_block=$((fs_blksz / 512))
+
+# Did we get at least 4 fs blocks worth of extent?
+min_len_sectors=$(( 4 * kernel_sectors_per_fs_block ))
+test "$len" -lt $min_len_sectors && \
+ _fail "could not format a long enough extent on an empty fs??"
+
+phys_start=$(echo "$phys" | sed -e 's/\.\..*//g')
+
+echo "$phys:$len:$fs_blksz:$phys_start" >> $seqres.full
+echo "victim file:" >> $seqres.full
+od -tx1 -Ad -c $victim >> $seqres.full
+
+# Set the dmerror table so that all IO will pass through.
+_dmerror_reset_table
+
+cat >> $seqres.full << ENDL
+dmerror before:
+$DMERROR_TABLE
+$DMERROR_RTTABLE
+<end table>
+ENDL
+
+# All sector numbers that we feed to the kernel must be in units of 512b, but
+# they also must be aligned to the device's logical block size.
+logical_block_size=`$here/src/min_dio_alignment $SCRATCH_MNT $SCRATCH_DEV`
+kernel_sectors_per_device_lba=$((logical_block_size / 512))
+
+# Mark as bad one of the device LBAs in the middle of the extent. Target the
+# second LBA of the third block of the four-block file extent that we allocated
+# earlier, but without overflowing into the fourth file block.
+bad_sector=$(( phys_start + (2 * kernel_sectors_per_fs_block) ))
+bad_len=$kernel_sectors_per_device_lba
+if (( kernel_sectors_per_device_lba < kernel_sectors_per_fs_block )); then
+ bad_sector=$((bad_sector + kernel_sectors_per_device_lba))
+fi
+if (( (bad_sector % kernel_sectors_per_device_lba) != 0)); then
+ echo "bad_sector $bad_sector not congruent with device logical block size $logical_block_size"
+fi
+
+# Remount to flush the page cache, start fsnotify, and make the LBA bad
+_dmerror_unmount
+_dmerror_mount
+
+$here/src/fs-monitor $SCRATCH_MNT > $tmp.fsmonitor &
+fsmonitor_pid=$!
+sleep 1
+
+_dmerror_mark_range_bad $bad_sector $bad_len
+
+cat >> $seqres.full << ENDL
+dmerror after marking bad:
+$DMERROR_TABLE
+$DMERROR_RTTABLE
+<end table>
+ENDL
+
+_dmerror_load_error_table
+
+# See if buffered reads pick it up
+echo "Try buffered read"
+$XFS_IO_PROG -c "pread 0 $((4 * file_blksz))" $victim >> $seqres.full
+
+# See if directio reads pick it up
+echo "Try directio read"
+$XFS_IO_PROG -d -c "pread 0 $((4 * file_blksz))" $victim >> $seqres.full
+
+# See if directio writes pick it up
+echo "Try directio write"
+$XFS_IO_PROG -d -c "pwrite -S 0x58 0 $((4 * file_blksz))" -c fsync $victim >> $seqres.full
+
+# See if buffered writes pick it up
+echo "Try buffered write"
+$XFS_IO_PROG -c "pwrite -S 0x58 0 $((4 * file_blksz))" -c fsync $victim >> $seqres.full
+
+# Now mark the bad range good so that unmount won't fail due to IO errors.
+echo "Fix device"
+_dmerror_mark_range_good $bad_sector $bad_len
+_dmerror_load_error_table
+
+cat >> $seqres.full << ENDL
+dmerror after marking good:
+$DMERROR_TABLE
+$DMERROR_RTTABLE
+<end table>
+ENDL
+
+# Unmount filesystem to start fresh
+echo "Kill fsnotify"
+_dmerror_unmount
+sleep 1
+kill -TERM $fsmonitor_pid
+unset fsmonitor_pid
+echo fsnotify log >> $seqres.full
+cat $tmp.fsmonitor >> $seqres.full
+cat $tmp.fsmonitor | filter_fsnotify_errors
+
+# Start fsnotify again so that can verify that the errors don't persist after
+# we flip back to the good dm table.
+echo "Remount and restart fsnotify"
+_dmerror_mount
+$here/src/fs-monitor $SCRATCH_MNT > $tmp.fsmonitor &
+fsmonitor_pid=$!
+sleep 1
+
+# See if buffered reads pick it up
+echo "Try buffered read again"
+$XFS_IO_PROG -c "pread 0 $((4 * file_blksz))" $victim >> $seqres.full
+
+# See if directio reads pick it up
+echo "Try directio read again"
+$XFS_IO_PROG -d -c "pread 0 $((4 * file_blksz))" $victim >> $seqres.full
+
+# See if directio writes pick it up
+echo "Try directio write again"
+$XFS_IO_PROG -d -c "pwrite -S 0x58 0 $((4 * file_blksz))" -c fsync $victim >> $seqres.full
+
+# See if buffered writes pick it up
+echo "Try buffered write again"
+$XFS_IO_PROG -c "pwrite -S 0x58 0 $((4 * file_blksz))" -c fsync $victim >> $seqres.full
+
+# Unmount fs and kill fsnotify, then wait for it to finish
+echo "Kill fsnotify again"
+_dmerror_unmount
+sleep 1
+kill -TERM $fsmonitor_pid
+unset fsmonitor_pid
+cat $tmp.fsmonitor >> $seqres.full
+cat $tmp.fsmonitor | filter_fsnotify_errors
+
+# success, all done
+status=0
+exit
diff --git a/tests/generic/1838.out b/tests/generic/1838.out
new file mode 100644
index 00000000000000..adae590fe0b2ea
--- /dev/null
+++ b/tests/generic/1838.out
@@ -0,0 +1,20 @@
+QA output created by 1838
+Try buffered read
+pread: Input/output error
+Try directio read
+pread: Input/output error
+Try directio write
+pwrite: Input/output error
+Try buffered write
+fsync: Input/output error
+Fix device
+Kill fsnotify
+ Generic Error Record: len=XXX
+ error: 5
+FAN_FS_ERROR (len=XXX)
+Remount and restart fsnotify
+Try buffered read again
+Try directio read again
+Try directio write again
+Try buffered write again
+Kill fsnotify again
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH 1/1] generic: test fsnotify filesystem error reporting
2026-03-10 3:50 ` [PATCH 1/1] generic: test fsnotify filesystem " Darrick J. Wong
@ 2026-03-10 7:07 ` Amir Goldstein
2026-03-13 18:01 ` Zorro Lang
2026-03-16 9:08 ` Christoph Hellwig
2 siblings, 0 replies; 22+ messages in thread
From: Amir Goldstein @ 2026-03-10 7:07 UTC (permalink / raw)
To: Darrick J. Wong
Cc: zlang, jack, fstests, gabriel, linux-fsdevel, linux-xfs, hch
On Tue, Mar 10, 2026 at 4:50 AM Darrick J. Wong <djwong@kernel.org> wrote:
>
> From: Darrick J. Wong <djwong@kernel.org>
>
> Test the fsnotify filesystem error reporting.
>
> Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Feel free to add:
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
> ---
> common/rc | 25 ++++++
> doc/group-names.txt | 1
> src/Makefile | 2
> src/fs-monitor.c | 153 ++++++++++++++++++++++++++++++++++
> tests/generic/1838 | 214 ++++++++++++++++++++++++++++++++++++++++++++++++
> tests/generic/1838.out | 20 ++++
> 6 files changed, 414 insertions(+), 1 deletion(-)
> create mode 100644 src/fs-monitor.c
> create mode 100755 tests/generic/1838
> create mode 100644 tests/generic/1838.out
>
>
> diff --git a/common/rc b/common/rc
> index fd4ca9641822cf..ccb78baf5bd41a 100644
> --- a/common/rc
> +++ b/common/rc
> @@ -3013,6 +3013,11 @@ _require_xfs_io_command()
> echo $testio | grep -q "Inappropriate ioctl" && \
> _notrun "xfs_io $command support is missing"
> ;;
> + "healthmon")
> + test -z "$param" && param="-p"
> + testio=`$XFS_IO_PROG -c "healthmon $param" $TEST_DIR 2>&1`
> + param_checked="$param"
> + ;;
> "label")
> testio=`$XFS_IO_PROG -c "label" $TEST_DIR 2>&1`
> ;;
> @@ -6149,6 +6154,26 @@ _require_max_file_range_blocks()
> esac
> }
>
> +_require_fanotify_ioerrors()
> +{
> + local x
> +
> + case "$FSTYP" in
> + xfs)
> + # added as a part of xfs health monitoring
> + _require_xfs_io_command healthmon
> + return 0
> + ;;
> + ext4)
> + # added at the same time as err_report_sec
> + x="$(_get_fs_sysfs_attr $TEST_DEV err_report_sec)"
> + test -n "$x" && return 0
> + ;;
> + esac
> +
> + _notrun "$FSTYP does not support fanotify ioerrors"
> +}
> +
> ################################################################################
> # make sure this script returns success
> /bin/true
> diff --git a/doc/group-names.txt b/doc/group-names.txt
> index 10b49e50517797..158f84d36d3154 100644
> --- a/doc/group-names.txt
> +++ b/doc/group-names.txt
> @@ -117,6 +117,7 @@ samefs overlayfs when all layers are on the same fs
> scrub filesystem metadata scrubbers
> seed btrfs seeded filesystems
> seek llseek functionality
> +selfhealing self healing filesystem code
> selftest tests with fixed results, used to validate testing setup
> send btrfs send/receive
> shrinkfs decreasing the size of a filesystem
> diff --git a/src/Makefile b/src/Makefile
> index 577d816ae859b6..1c761da0ccff20 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 fs-monitor
>
> EXTRA_EXECS = dmerror fill2attr fill2fs fill2fs_check scaleread.sh \
> btrfs_crc32c_forged_name.py popdir.pl popattr.py \
> diff --git a/src/fs-monitor.c b/src/fs-monitor.c
> new file mode 100644
> index 00000000000000..0cf09677a3efda
> --- /dev/null
> +++ b/src/fs-monitor.c
> @@ -0,0 +1,153 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright 2021, Collabora Ltd.
> + * Copied from https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/samples/fanotify/fs-monitor.c
> + */
> +
> +#include <errno.h>
> +#include <err.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <fcntl.h>
> +#include <sys/fanotify.h>
> +#include <sys/types.h>
> +#include <unistd.h>
> +
> +#ifndef FAN_FS_ERROR
> +#define FAN_FS_ERROR 0x00008000
> +#define FAN_EVENT_INFO_TYPE_ERROR 5
> +
> +struct fanotify_event_info_error {
> + struct fanotify_event_info_header hdr;
> + __s32 error;
> + __u32 error_count;
> +};
> +#endif
> +
> +#ifndef FILEID_INO32_GEN
> +#define FILEID_INO32_GEN 1
> +#endif
> +
> +#ifndef FILEID_INVALID
> +#define FILEID_INVALID 0xff
> +#endif
> +
> +static void print_fh(struct file_handle *fh)
> +{
> + int i;
> + uint32_t *h = (uint32_t *) fh->f_handle;
> +
> + printf("\tfh: ");
> + for (i = 0; i < fh->handle_bytes; i++)
> + printf("%hhx", fh->f_handle[i]);
> + printf("\n");
> +
> + printf("\tdecoded fh: ");
> + if (fh->handle_type == FILEID_INO32_GEN)
> + printf("inode=%u gen=%u\n", h[0], h[1]);
> + else if (fh->handle_type == FILEID_INVALID && !fh->handle_bytes)
> + printf("Type %d (Superblock error)\n", fh->handle_type);
> + else
> + printf("Type %d (Unknown)\n", fh->handle_type);
> +
> +}
> +
> +static void handle_notifications(char *buffer, int len)
> +{
> + struct fanotify_event_metadata *event =
> + (struct fanotify_event_metadata *) buffer;
> + struct fanotify_event_info_header *info;
> + struct fanotify_event_info_error *err;
> + struct fanotify_event_info_fid *fid;
> + int off;
> +
> + for (; FAN_EVENT_OK(event, len); event = FAN_EVENT_NEXT(event, len)) {
> +
> + if (event->mask != FAN_FS_ERROR) {
> + printf("unexpected FAN MARK: %llx\n",
> + (unsigned long long)event->mask);
> + goto next_event;
> + }
> +
> + if (event->fd != FAN_NOFD) {
> + printf("Unexpected fd (!= FAN_NOFD)\n");
> + goto next_event;
> + }
> +
> + printf("FAN_FS_ERROR (len=%d)\n", event->event_len);
> +
> + for (off = sizeof(*event) ; off < event->event_len;
> + off += info->len) {
> + info = (struct fanotify_event_info_header *)
> + ((char *) event + off);
> +
> + switch (info->info_type) {
> + case FAN_EVENT_INFO_TYPE_ERROR:
> + err = (struct fanotify_event_info_error *) info;
> +
> + printf("\tGeneric Error Record: len=%d\n",
> + err->hdr.len);
> + printf("\terror: %d\n", err->error);
> + printf("\terror_count: %d\n", err->error_count);
> + break;
> +
> + case FAN_EVENT_INFO_TYPE_FID:
> + fid = (struct fanotify_event_info_fid *) info;
> +
> + printf("\tfsid: %x%x\n",
> +#if defined(__GLIBC__)
> + fid->fsid.val[0], fid->fsid.val[1]);
> +#else
> + fid->fsid.__val[0], fid->fsid.__val[1]);
> +#endif
> + print_fh((struct file_handle *) &fid->handle);
> + break;
> +
> + default:
> + printf("\tUnknown info type=%d len=%d:\n",
> + info->info_type, info->len);
> + }
> + }
> +next_event:
> + printf("---\n\n");
> + fflush(stdout);
> + }
> +}
> +
> +int main(int argc, char **argv)
> +{
> + int fd;
> +
> + char buffer[BUFSIZ];
> +
> + if (argc < 2) {
> + printf("Missing path argument\n");
> + return 1;
> + }
> +
> + fd = fanotify_init(FAN_CLASS_NOTIF|FAN_REPORT_FID, O_RDONLY);
> + if (fd < 0) {
> + perror("fanotify_init");
> + errx(1, "fanotify_init");
> + }
> +
> + if (fanotify_mark(fd, FAN_MARK_ADD|FAN_MARK_FILESYSTEM,
> + FAN_FS_ERROR, AT_FDCWD, argv[1])) {
> + perror("fanotify_mark");
> + errx(1, "fanotify_mark");
> + }
> +
> + printf("fanotify active\n");
> + fflush(stdout);
> +
> + while (1) {
> + int n = read(fd, buffer, BUFSIZ);
> +
> + if (n < 0)
> + errx(1, "read");
> +
> + handle_notifications(buffer, n);
> + }
> +
> + return 0;
> +}
> diff --git a/tests/generic/1838 b/tests/generic/1838
> new file mode 100755
> index 00000000000000..940811baae3a6e
> --- /dev/null
> +++ b/tests/generic/1838
> @@ -0,0 +1,214 @@
> +#! /bin/bash
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +# Copyright (c) 2024-2026 Oracle. All Rights Reserved.
> +#
> +# FS QA Test No. 1838
> +#
> +# Check that fsnotify can report file IO errors.
> +
> +. ./common/preamble
> +_begin_fstest auto quick eio selfhealing
> +
> +# Override the default cleanup function.
> +_cleanup()
> +{
> + cd /
> + test -n "$fsmonitor_pid" && kill -TERM $fsmonitor_pid
> + rm -f $tmp.*
> + _dmerror_cleanup
> +}
> +
> +# Import common functions.
> +. ./common/fuzzy
> +. ./common/filter
> +. ./common/dmerror
> +. ./common/systemd
> +
> +_require_scratch
> +_require_dm_target error
> +_require_test_program fs-monitor
> +_require_xfs_io_command "fiemap"
> +_require_odirect
> +_require_fanotify_ioerrors
> +
> +# no out of place writes
> +test "$FSTYP" = "xfs" && _require_no_xfs_always_cow
> +
> +# fsnotify only gives us a file handle, the error number, and the number of
> +# times it was seen in between event deliveries. The handle is mostly useless
> +# since we have no generic way to map that to a file path. Therefore we can
> +# only coalesce all the I/O errors into one report.
> +filter_fsnotify_errors() {
> + _filter_scratch | \
> + grep -E '(FAN_FS_ERROR|Generic Error Record|error: 5)' | \
> + sed -e "s/len=[0-9]*/len=XXX/g" | \
> + sort | \
> + uniq
> +}
> +
> +_scratch_mkfs >> $seqres.full
> +
> +#
> +# The dm-error map added by this test doesn't work on zoned devices because
> +# table sizes need to be aligned to the zone size, and even for zoned on
> +# conventional this test will get confused because of the internal RT device.
> +#
> +# That check requires a mounted file system, so do a dummy mount before setting
> +# up DM.
> +#
> +_scratch_mount
> +test $FSTYP = xfs && _require_xfs_scratch_non_zoned
> +_scratch_unmount
> +
> +_dmerror_init
> +_dmerror_mount >> $seqres.full 2>&1
> +
> +test $FSTYP = xfs && _xfs_force_bdev data $SCRATCH_MNT
> +
> +# Write a file with 4 file blocks worth of data, figure out the LBA to target
> +victim=$SCRATCH_MNT/a
> +file_blksz=$(_get_file_block_size $SCRATCH_MNT)
> +$XFS_IO_PROG -f -c "pwrite -S 0x58 0 $((4 * file_blksz))" -c "fsync" $victim >> $seqres.full
> +
> +awk_len_prog='{print $4}'
> +bmap_str="$($XFS_IO_PROG -c "fiemap -v" $victim | grep "^[[:space:]]*0:")"
> +echo "$bmap_str" >> $seqres.full
> +
> +phys="$(echo "$bmap_str" | $AWK_PROG '{print $3}')"
> +len="$(echo "$bmap_str" | $AWK_PROG "$awk_len_prog")"
> +
> +fs_blksz=$(_get_block_size $SCRATCH_MNT)
> +echo "file_blksz:$file_blksz:fs_blksz:$fs_blksz" >> $seqres.full
> +kernel_sectors_per_fs_block=$((fs_blksz / 512))
> +
> +# Did we get at least 4 fs blocks worth of extent?
> +min_len_sectors=$(( 4 * kernel_sectors_per_fs_block ))
> +test "$len" -lt $min_len_sectors && \
> + _fail "could not format a long enough extent on an empty fs??"
> +
> +phys_start=$(echo "$phys" | sed -e 's/\.\..*//g')
> +
> +echo "$phys:$len:$fs_blksz:$phys_start" >> $seqres.full
> +echo "victim file:" >> $seqres.full
> +od -tx1 -Ad -c $victim >> $seqres.full
> +
> +# Set the dmerror table so that all IO will pass through.
> +_dmerror_reset_table
> +
> +cat >> $seqres.full << ENDL
> +dmerror before:
> +$DMERROR_TABLE
> +$DMERROR_RTTABLE
> +<end table>
> +ENDL
> +
> +# All sector numbers that we feed to the kernel must be in units of 512b, but
> +# they also must be aligned to the device's logical block size.
> +logical_block_size=`$here/src/min_dio_alignment $SCRATCH_MNT $SCRATCH_DEV`
> +kernel_sectors_per_device_lba=$((logical_block_size / 512))
> +
> +# Mark as bad one of the device LBAs in the middle of the extent. Target the
> +# second LBA of the third block of the four-block file extent that we allocated
> +# earlier, but without overflowing into the fourth file block.
> +bad_sector=$(( phys_start + (2 * kernel_sectors_per_fs_block) ))
> +bad_len=$kernel_sectors_per_device_lba
> +if (( kernel_sectors_per_device_lba < kernel_sectors_per_fs_block )); then
> + bad_sector=$((bad_sector + kernel_sectors_per_device_lba))
> +fi
> +if (( (bad_sector % kernel_sectors_per_device_lba) != 0)); then
> + echo "bad_sector $bad_sector not congruent with device logical block size $logical_block_size"
> +fi
> +
> +# Remount to flush the page cache, start fsnotify, and make the LBA bad
> +_dmerror_unmount
> +_dmerror_mount
> +
> +$here/src/fs-monitor $SCRATCH_MNT > $tmp.fsmonitor &
> +fsmonitor_pid=$!
> +sleep 1
> +
> +_dmerror_mark_range_bad $bad_sector $bad_len
> +
> +cat >> $seqres.full << ENDL
> +dmerror after marking bad:
> +$DMERROR_TABLE
> +$DMERROR_RTTABLE
> +<end table>
> +ENDL
> +
> +_dmerror_load_error_table
> +
> +# See if buffered reads pick it up
> +echo "Try buffered read"
> +$XFS_IO_PROG -c "pread 0 $((4 * file_blksz))" $victim >> $seqres.full
> +
> +# See if directio reads pick it up
> +echo "Try directio read"
> +$XFS_IO_PROG -d -c "pread 0 $((4 * file_blksz))" $victim >> $seqres.full
> +
> +# See if directio writes pick it up
> +echo "Try directio write"
> +$XFS_IO_PROG -d -c "pwrite -S 0x58 0 $((4 * file_blksz))" -c fsync $victim >> $seqres.full
> +
> +# See if buffered writes pick it up
> +echo "Try buffered write"
> +$XFS_IO_PROG -c "pwrite -S 0x58 0 $((4 * file_blksz))" -c fsync $victim >> $seqres.full
> +
> +# Now mark the bad range good so that unmount won't fail due to IO errors.
> +echo "Fix device"
> +_dmerror_mark_range_good $bad_sector $bad_len
> +_dmerror_load_error_table
> +
> +cat >> $seqres.full << ENDL
> +dmerror after marking good:
> +$DMERROR_TABLE
> +$DMERROR_RTTABLE
> +<end table>
> +ENDL
> +
> +# Unmount filesystem to start fresh
> +echo "Kill fsnotify"
> +_dmerror_unmount
> +sleep 1
> +kill -TERM $fsmonitor_pid
> +unset fsmonitor_pid
> +echo fsnotify log >> $seqres.full
> +cat $tmp.fsmonitor >> $seqres.full
> +cat $tmp.fsmonitor | filter_fsnotify_errors
> +
> +# Start fsnotify again so that can verify that the errors don't persist after
> +# we flip back to the good dm table.
> +echo "Remount and restart fsnotify"
> +_dmerror_mount
> +$here/src/fs-monitor $SCRATCH_MNT > $tmp.fsmonitor &
> +fsmonitor_pid=$!
> +sleep 1
> +
> +# See if buffered reads pick it up
> +echo "Try buffered read again"
> +$XFS_IO_PROG -c "pread 0 $((4 * file_blksz))" $victim >> $seqres.full
> +
> +# See if directio reads pick it up
> +echo "Try directio read again"
> +$XFS_IO_PROG -d -c "pread 0 $((4 * file_blksz))" $victim >> $seqres.full
> +
> +# See if directio writes pick it up
> +echo "Try directio write again"
> +$XFS_IO_PROG -d -c "pwrite -S 0x58 0 $((4 * file_blksz))" -c fsync $victim >> $seqres.full
> +
> +# See if buffered writes pick it up
> +echo "Try buffered write again"
> +$XFS_IO_PROG -c "pwrite -S 0x58 0 $((4 * file_blksz))" -c fsync $victim >> $seqres.full
> +
> +# Unmount fs and kill fsnotify, then wait for it to finish
> +echo "Kill fsnotify again"
> +_dmerror_unmount
> +sleep 1
> +kill -TERM $fsmonitor_pid
> +unset fsmonitor_pid
> +cat $tmp.fsmonitor >> $seqres.full
> +cat $tmp.fsmonitor | filter_fsnotify_errors
> +
> +# success, all done
> +status=0
> +exit
> diff --git a/tests/generic/1838.out b/tests/generic/1838.out
> new file mode 100644
> index 00000000000000..adae590fe0b2ea
> --- /dev/null
> +++ b/tests/generic/1838.out
> @@ -0,0 +1,20 @@
> +QA output created by 1838
> +Try buffered read
> +pread: Input/output error
> +Try directio read
> +pread: Input/output error
> +Try directio write
> +pwrite: Input/output error
> +Try buffered write
> +fsync: Input/output error
> +Fix device
> +Kill fsnotify
> + Generic Error Record: len=XXX
> + error: 5
> +FAN_FS_ERROR (len=XXX)
> +Remount and restart fsnotify
> +Try buffered read again
> +Try directio read again
> +Try directio write again
> +Try buffered write again
> +Kill fsnotify again
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 1/1] generic: test fsnotify filesystem error reporting
2026-03-10 3:50 ` [PATCH 1/1] generic: test fsnotify filesystem " Darrick J. Wong
2026-03-10 7:07 ` Amir Goldstein
@ 2026-03-13 18:01 ` Zorro Lang
2026-03-13 23:27 ` Darrick J. Wong
2026-03-16 9:08 ` Christoph Hellwig
2 siblings, 1 reply; 22+ messages in thread
From: Zorro Lang @ 2026-03-13 18:01 UTC (permalink / raw)
To: Darrick J. Wong
Cc: jack, fstests, amir73il, gabriel, linux-fsdevel, linux-xfs, hch
On Mon, Mar 09, 2026 at 08:50:08PM -0700, Darrick J. Wong wrote:
> From: Darrick J. Wong <djwong@kernel.org>
>
> Test the fsnotify filesystem error reporting.
>
> Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
> ---
> common/rc | 25 ++++++
> doc/group-names.txt | 1
> src/Makefile | 2
> src/fs-monitor.c | 153 ++++++++++++++++++++++++++++++++++
I'll add "src/fs-monitor" into .gitignore file when I merge this patch.
Others look good to me.
Reviewed-by: Zorro Lang <zlang@redhat.com>
> tests/generic/1838 | 214 ++++++++++++++++++++++++++++++++++++++++++++++++
> tests/generic/1838.out | 20 ++++
> 6 files changed, 414 insertions(+), 1 deletion(-)
> create mode 100644 src/fs-monitor.c
> create mode 100755 tests/generic/1838
> create mode 100644 tests/generic/1838.out
>
>
> diff --git a/common/rc b/common/rc
> index fd4ca9641822cf..ccb78baf5bd41a 100644
> --- a/common/rc
> +++ b/common/rc
> @@ -3013,6 +3013,11 @@ _require_xfs_io_command()
> echo $testio | grep -q "Inappropriate ioctl" && \
> _notrun "xfs_io $command support is missing"
> ;;
> + "healthmon")
> + test -z "$param" && param="-p"
> + testio=`$XFS_IO_PROG -c "healthmon $param" $TEST_DIR 2>&1`
> + param_checked="$param"
> + ;;
> "label")
> testio=`$XFS_IO_PROG -c "label" $TEST_DIR 2>&1`
> ;;
> @@ -6149,6 +6154,26 @@ _require_max_file_range_blocks()
> esac
> }
>
> +_require_fanotify_ioerrors()
> +{
> + local x
> +
> + case "$FSTYP" in
> + xfs)
> + # added as a part of xfs health monitoring
> + _require_xfs_io_command healthmon
> + return 0
> + ;;
> + ext4)
> + # added at the same time as err_report_sec
> + x="$(_get_fs_sysfs_attr $TEST_DEV err_report_sec)"
> + test -n "$x" && return 0
> + ;;
> + esac
> +
> + _notrun "$FSTYP does not support fanotify ioerrors"
> +}
> +
> ################################################################################
> # make sure this script returns success
> /bin/true
> diff --git a/doc/group-names.txt b/doc/group-names.txt
> index 10b49e50517797..158f84d36d3154 100644
> --- a/doc/group-names.txt
> +++ b/doc/group-names.txt
> @@ -117,6 +117,7 @@ samefs overlayfs when all layers are on the same fs
> scrub filesystem metadata scrubbers
> seed btrfs seeded filesystems
> seek llseek functionality
> +selfhealing self healing filesystem code
> selftest tests with fixed results, used to validate testing setup
> send btrfs send/receive
> shrinkfs decreasing the size of a filesystem
> diff --git a/src/Makefile b/src/Makefile
> index 577d816ae859b6..1c761da0ccff20 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 fs-monitor
>
> EXTRA_EXECS = dmerror fill2attr fill2fs fill2fs_check scaleread.sh \
> btrfs_crc32c_forged_name.py popdir.pl popattr.py \
> diff --git a/src/fs-monitor.c b/src/fs-monitor.c
> new file mode 100644
> index 00000000000000..0cf09677a3efda
> --- /dev/null
> +++ b/src/fs-monitor.c
> @@ -0,0 +1,153 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright 2021, Collabora Ltd.
> + * Copied from https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/samples/fanotify/fs-monitor.c
> + */
> +
> +#include <errno.h>
> +#include <err.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <fcntl.h>
> +#include <sys/fanotify.h>
> +#include <sys/types.h>
> +#include <unistd.h>
> +
> +#ifndef FAN_FS_ERROR
> +#define FAN_FS_ERROR 0x00008000
> +#define FAN_EVENT_INFO_TYPE_ERROR 5
> +
> +struct fanotify_event_info_error {
> + struct fanotify_event_info_header hdr;
> + __s32 error;
> + __u32 error_count;
> +};
> +#endif
> +
> +#ifndef FILEID_INO32_GEN
> +#define FILEID_INO32_GEN 1
> +#endif
> +
> +#ifndef FILEID_INVALID
> +#define FILEID_INVALID 0xff
> +#endif
> +
> +static void print_fh(struct file_handle *fh)
> +{
> + int i;
> + uint32_t *h = (uint32_t *) fh->f_handle;
> +
> + printf("\tfh: ");
> + for (i = 0; i < fh->handle_bytes; i++)
> + printf("%hhx", fh->f_handle[i]);
> + printf("\n");
> +
> + printf("\tdecoded fh: ");
> + if (fh->handle_type == FILEID_INO32_GEN)
> + printf("inode=%u gen=%u\n", h[0], h[1]);
> + else if (fh->handle_type == FILEID_INVALID && !fh->handle_bytes)
> + printf("Type %d (Superblock error)\n", fh->handle_type);
> + else
> + printf("Type %d (Unknown)\n", fh->handle_type);
> +
> +}
> +
> +static void handle_notifications(char *buffer, int len)
> +{
> + struct fanotify_event_metadata *event =
> + (struct fanotify_event_metadata *) buffer;
> + struct fanotify_event_info_header *info;
> + struct fanotify_event_info_error *err;
> + struct fanotify_event_info_fid *fid;
> + int off;
> +
> + for (; FAN_EVENT_OK(event, len); event = FAN_EVENT_NEXT(event, len)) {
> +
> + if (event->mask != FAN_FS_ERROR) {
> + printf("unexpected FAN MARK: %llx\n",
> + (unsigned long long)event->mask);
> + goto next_event;
> + }
> +
> + if (event->fd != FAN_NOFD) {
> + printf("Unexpected fd (!= FAN_NOFD)\n");
> + goto next_event;
> + }
> +
> + printf("FAN_FS_ERROR (len=%d)\n", event->event_len);
> +
> + for (off = sizeof(*event) ; off < event->event_len;
> + off += info->len) {
> + info = (struct fanotify_event_info_header *)
> + ((char *) event + off);
> +
> + switch (info->info_type) {
> + case FAN_EVENT_INFO_TYPE_ERROR:
> + err = (struct fanotify_event_info_error *) info;
> +
> + printf("\tGeneric Error Record: len=%d\n",
> + err->hdr.len);
> + printf("\terror: %d\n", err->error);
> + printf("\terror_count: %d\n", err->error_count);
> + break;
> +
> + case FAN_EVENT_INFO_TYPE_FID:
> + fid = (struct fanotify_event_info_fid *) info;
> +
> + printf("\tfsid: %x%x\n",
> +#if defined(__GLIBC__)
> + fid->fsid.val[0], fid->fsid.val[1]);
> +#else
> + fid->fsid.__val[0], fid->fsid.__val[1]);
> +#endif
> + print_fh((struct file_handle *) &fid->handle);
> + break;
> +
> + default:
> + printf("\tUnknown info type=%d len=%d:\n",
> + info->info_type, info->len);
> + }
> + }
> +next_event:
> + printf("---\n\n");
> + fflush(stdout);
> + }
> +}
> +
> +int main(int argc, char **argv)
> +{
> + int fd;
> +
> + char buffer[BUFSIZ];
> +
> + if (argc < 2) {
> + printf("Missing path argument\n");
> + return 1;
> + }
> +
> + fd = fanotify_init(FAN_CLASS_NOTIF|FAN_REPORT_FID, O_RDONLY);
> + if (fd < 0) {
> + perror("fanotify_init");
> + errx(1, "fanotify_init");
> + }
> +
> + if (fanotify_mark(fd, FAN_MARK_ADD|FAN_MARK_FILESYSTEM,
> + FAN_FS_ERROR, AT_FDCWD, argv[1])) {
> + perror("fanotify_mark");
> + errx(1, "fanotify_mark");
> + }
> +
> + printf("fanotify active\n");
> + fflush(stdout);
> +
> + while (1) {
> + int n = read(fd, buffer, BUFSIZ);
> +
> + if (n < 0)
> + errx(1, "read");
> +
> + handle_notifications(buffer, n);
> + }
> +
> + return 0;
> +}
> diff --git a/tests/generic/1838 b/tests/generic/1838
> new file mode 100755
> index 00000000000000..940811baae3a6e
> --- /dev/null
> +++ b/tests/generic/1838
> @@ -0,0 +1,214 @@
> +#! /bin/bash
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +# Copyright (c) 2024-2026 Oracle. All Rights Reserved.
> +#
> +# FS QA Test No. 1838
> +#
> +# Check that fsnotify can report file IO errors.
> +
> +. ./common/preamble
> +_begin_fstest auto quick eio selfhealing
> +
> +# Override the default cleanup function.
> +_cleanup()
> +{
> + cd /
> + test -n "$fsmonitor_pid" && kill -TERM $fsmonitor_pid
> + rm -f $tmp.*
> + _dmerror_cleanup
> +}
> +
> +# Import common functions.
> +. ./common/fuzzy
> +. ./common/filter
> +. ./common/dmerror
> +. ./common/systemd
> +
> +_require_scratch
> +_require_dm_target error
> +_require_test_program fs-monitor
> +_require_xfs_io_command "fiemap"
> +_require_odirect
> +_require_fanotify_ioerrors
> +
> +# no out of place writes
> +test "$FSTYP" = "xfs" && _require_no_xfs_always_cow
> +
> +# fsnotify only gives us a file handle, the error number, and the number of
> +# times it was seen in between event deliveries. The handle is mostly useless
> +# since we have no generic way to map that to a file path. Therefore we can
> +# only coalesce all the I/O errors into one report.
> +filter_fsnotify_errors() {
> + _filter_scratch | \
> + grep -E '(FAN_FS_ERROR|Generic Error Record|error: 5)' | \
> + sed -e "s/len=[0-9]*/len=XXX/g" | \
> + sort | \
> + uniq
> +}
> +
> +_scratch_mkfs >> $seqres.full
> +
> +#
> +# The dm-error map added by this test doesn't work on zoned devices because
> +# table sizes need to be aligned to the zone size, and even for zoned on
> +# conventional this test will get confused because of the internal RT device.
> +#
> +# That check requires a mounted file system, so do a dummy mount before setting
> +# up DM.
> +#
> +_scratch_mount
> +test $FSTYP = xfs && _require_xfs_scratch_non_zoned
> +_scratch_unmount
> +
> +_dmerror_init
> +_dmerror_mount >> $seqres.full 2>&1
> +
> +test $FSTYP = xfs && _xfs_force_bdev data $SCRATCH_MNT
> +
> +# Write a file with 4 file blocks worth of data, figure out the LBA to target
> +victim=$SCRATCH_MNT/a
> +file_blksz=$(_get_file_block_size $SCRATCH_MNT)
> +$XFS_IO_PROG -f -c "pwrite -S 0x58 0 $((4 * file_blksz))" -c "fsync" $victim >> $seqres.full
> +
> +awk_len_prog='{print $4}'
> +bmap_str="$($XFS_IO_PROG -c "fiemap -v" $victim | grep "^[[:space:]]*0:")"
> +echo "$bmap_str" >> $seqres.full
> +
> +phys="$(echo "$bmap_str" | $AWK_PROG '{print $3}')"
> +len="$(echo "$bmap_str" | $AWK_PROG "$awk_len_prog")"
> +
> +fs_blksz=$(_get_block_size $SCRATCH_MNT)
> +echo "file_blksz:$file_blksz:fs_blksz:$fs_blksz" >> $seqres.full
> +kernel_sectors_per_fs_block=$((fs_blksz / 512))
> +
> +# Did we get at least 4 fs blocks worth of extent?
> +min_len_sectors=$(( 4 * kernel_sectors_per_fs_block ))
> +test "$len" -lt $min_len_sectors && \
> + _fail "could not format a long enough extent on an empty fs??"
> +
> +phys_start=$(echo "$phys" | sed -e 's/\.\..*//g')
> +
> +echo "$phys:$len:$fs_blksz:$phys_start" >> $seqres.full
> +echo "victim file:" >> $seqres.full
> +od -tx1 -Ad -c $victim >> $seqres.full
> +
> +# Set the dmerror table so that all IO will pass through.
> +_dmerror_reset_table
> +
> +cat >> $seqres.full << ENDL
> +dmerror before:
> +$DMERROR_TABLE
> +$DMERROR_RTTABLE
> +<end table>
> +ENDL
> +
> +# All sector numbers that we feed to the kernel must be in units of 512b, but
> +# they also must be aligned to the device's logical block size.
> +logical_block_size=`$here/src/min_dio_alignment $SCRATCH_MNT $SCRATCH_DEV`
> +kernel_sectors_per_device_lba=$((logical_block_size / 512))
> +
> +# Mark as bad one of the device LBAs in the middle of the extent. Target the
> +# second LBA of the third block of the four-block file extent that we allocated
> +# earlier, but without overflowing into the fourth file block.
> +bad_sector=$(( phys_start + (2 * kernel_sectors_per_fs_block) ))
> +bad_len=$kernel_sectors_per_device_lba
> +if (( kernel_sectors_per_device_lba < kernel_sectors_per_fs_block )); then
> + bad_sector=$((bad_sector + kernel_sectors_per_device_lba))
> +fi
> +if (( (bad_sector % kernel_sectors_per_device_lba) != 0)); then
> + echo "bad_sector $bad_sector not congruent with device logical block size $logical_block_size"
> +fi
> +
> +# Remount to flush the page cache, start fsnotify, and make the LBA bad
> +_dmerror_unmount
> +_dmerror_mount
> +
> +$here/src/fs-monitor $SCRATCH_MNT > $tmp.fsmonitor &
> +fsmonitor_pid=$!
> +sleep 1
> +
> +_dmerror_mark_range_bad $bad_sector $bad_len
> +
> +cat >> $seqres.full << ENDL
> +dmerror after marking bad:
> +$DMERROR_TABLE
> +$DMERROR_RTTABLE
> +<end table>
> +ENDL
> +
> +_dmerror_load_error_table
> +
> +# See if buffered reads pick it up
> +echo "Try buffered read"
> +$XFS_IO_PROG -c "pread 0 $((4 * file_blksz))" $victim >> $seqres.full
> +
> +# See if directio reads pick it up
> +echo "Try directio read"
> +$XFS_IO_PROG -d -c "pread 0 $((4 * file_blksz))" $victim >> $seqres.full
> +
> +# See if directio writes pick it up
> +echo "Try directio write"
> +$XFS_IO_PROG -d -c "pwrite -S 0x58 0 $((4 * file_blksz))" -c fsync $victim >> $seqres.full
> +
> +# See if buffered writes pick it up
> +echo "Try buffered write"
> +$XFS_IO_PROG -c "pwrite -S 0x58 0 $((4 * file_blksz))" -c fsync $victim >> $seqres.full
> +
> +# Now mark the bad range good so that unmount won't fail due to IO errors.
> +echo "Fix device"
> +_dmerror_mark_range_good $bad_sector $bad_len
> +_dmerror_load_error_table
> +
> +cat >> $seqres.full << ENDL
> +dmerror after marking good:
> +$DMERROR_TABLE
> +$DMERROR_RTTABLE
> +<end table>
> +ENDL
> +
> +# Unmount filesystem to start fresh
> +echo "Kill fsnotify"
> +_dmerror_unmount
> +sleep 1
> +kill -TERM $fsmonitor_pid
> +unset fsmonitor_pid
> +echo fsnotify log >> $seqres.full
> +cat $tmp.fsmonitor >> $seqres.full
> +cat $tmp.fsmonitor | filter_fsnotify_errors
> +
> +# Start fsnotify again so that can verify that the errors don't persist after
> +# we flip back to the good dm table.
> +echo "Remount and restart fsnotify"
> +_dmerror_mount
> +$here/src/fs-monitor $SCRATCH_MNT > $tmp.fsmonitor &
> +fsmonitor_pid=$!
> +sleep 1
> +
> +# See if buffered reads pick it up
> +echo "Try buffered read again"
> +$XFS_IO_PROG -c "pread 0 $((4 * file_blksz))" $victim >> $seqres.full
> +
> +# See if directio reads pick it up
> +echo "Try directio read again"
> +$XFS_IO_PROG -d -c "pread 0 $((4 * file_blksz))" $victim >> $seqres.full
> +
> +# See if directio writes pick it up
> +echo "Try directio write again"
> +$XFS_IO_PROG -d -c "pwrite -S 0x58 0 $((4 * file_blksz))" -c fsync $victim >> $seqres.full
> +
> +# See if buffered writes pick it up
> +echo "Try buffered write again"
> +$XFS_IO_PROG -c "pwrite -S 0x58 0 $((4 * file_blksz))" -c fsync $victim >> $seqres.full
> +
> +# Unmount fs and kill fsnotify, then wait for it to finish
> +echo "Kill fsnotify again"
> +_dmerror_unmount
> +sleep 1
> +kill -TERM $fsmonitor_pid
> +unset fsmonitor_pid
> +cat $tmp.fsmonitor >> $seqres.full
> +cat $tmp.fsmonitor | filter_fsnotify_errors
> +
> +# success, all done
> +status=0
> +exit
> diff --git a/tests/generic/1838.out b/tests/generic/1838.out
> new file mode 100644
> index 00000000000000..adae590fe0b2ea
> --- /dev/null
> +++ b/tests/generic/1838.out
> @@ -0,0 +1,20 @@
> +QA output created by 1838
> +Try buffered read
> +pread: Input/output error
> +Try directio read
> +pread: Input/output error
> +Try directio write
> +pwrite: Input/output error
> +Try buffered write
> +fsync: Input/output error
> +Fix device
> +Kill fsnotify
> + Generic Error Record: len=XXX
> + error: 5
> +FAN_FS_ERROR (len=XXX)
> +Remount and restart fsnotify
> +Try buffered read again
> +Try directio read again
> +Try directio write again
> +Try buffered write again
> +Kill fsnotify again
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 1/1] generic: test fsnotify filesystem error reporting
2026-03-13 18:01 ` Zorro Lang
@ 2026-03-13 23:27 ` Darrick J. Wong
0 siblings, 0 replies; 22+ messages in thread
From: Darrick J. Wong @ 2026-03-13 23:27 UTC (permalink / raw)
To: Zorro Lang
Cc: jack, fstests, amir73il, gabriel, linux-fsdevel, linux-xfs, hch
On Sat, Mar 14, 2026 at 02:01:02AM +0800, Zorro Lang wrote:
> On Mon, Mar 09, 2026 at 08:50:08PM -0700, Darrick J. Wong wrote:
> > From: Darrick J. Wong <djwong@kernel.org>
> >
> > Test the fsnotify filesystem error reporting.
> >
> > Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
> > ---
> > common/rc | 25 ++++++
> > doc/group-names.txt | 1
> > src/Makefile | 2
> > src/fs-monitor.c | 153 ++++++++++++++++++++++++++++++++++
>
> I'll add "src/fs-monitor" into .gitignore file when I merge this patch.
> Others look good to me.
Oops, thanks for fixing that for me!
--D
> Reviewed-by: Zorro Lang <zlang@redhat.com>
>
> > tests/generic/1838 | 214 ++++++++++++++++++++++++++++++++++++++++++++++++
> > tests/generic/1838.out | 20 ++++
> > 6 files changed, 414 insertions(+), 1 deletion(-)
> > create mode 100644 src/fs-monitor.c
> > create mode 100755 tests/generic/1838
> > create mode 100644 tests/generic/1838.out
> >
> >
> > diff --git a/common/rc b/common/rc
> > index fd4ca9641822cf..ccb78baf5bd41a 100644
> > --- a/common/rc
> > +++ b/common/rc
> > @@ -3013,6 +3013,11 @@ _require_xfs_io_command()
> > echo $testio | grep -q "Inappropriate ioctl" && \
> > _notrun "xfs_io $command support is missing"
> > ;;
> > + "healthmon")
> > + test -z "$param" && param="-p"
> > + testio=`$XFS_IO_PROG -c "healthmon $param" $TEST_DIR 2>&1`
> > + param_checked="$param"
> > + ;;
> > "label")
> > testio=`$XFS_IO_PROG -c "label" $TEST_DIR 2>&1`
> > ;;
> > @@ -6149,6 +6154,26 @@ _require_max_file_range_blocks()
> > esac
> > }
> >
> > +_require_fanotify_ioerrors()
> > +{
> > + local x
> > +
> > + case "$FSTYP" in
> > + xfs)
> > + # added as a part of xfs health monitoring
> > + _require_xfs_io_command healthmon
> > + return 0
> > + ;;
> > + ext4)
> > + # added at the same time as err_report_sec
> > + x="$(_get_fs_sysfs_attr $TEST_DEV err_report_sec)"
> > + test -n "$x" && return 0
> > + ;;
> > + esac
> > +
> > + _notrun "$FSTYP does not support fanotify ioerrors"
> > +}
> > +
> > ################################################################################
> > # make sure this script returns success
> > /bin/true
> > diff --git a/doc/group-names.txt b/doc/group-names.txt
> > index 10b49e50517797..158f84d36d3154 100644
> > --- a/doc/group-names.txt
> > +++ b/doc/group-names.txt
> > @@ -117,6 +117,7 @@ samefs overlayfs when all layers are on the same fs
> > scrub filesystem metadata scrubbers
> > seed btrfs seeded filesystems
> > seek llseek functionality
> > +selfhealing self healing filesystem code
> > selftest tests with fixed results, used to validate testing setup
> > send btrfs send/receive
> > shrinkfs decreasing the size of a filesystem
> > diff --git a/src/Makefile b/src/Makefile
> > index 577d816ae859b6..1c761da0ccff20 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 fs-monitor
> >
> > EXTRA_EXECS = dmerror fill2attr fill2fs fill2fs_check scaleread.sh \
> > btrfs_crc32c_forged_name.py popdir.pl popattr.py \
> > diff --git a/src/fs-monitor.c b/src/fs-monitor.c
> > new file mode 100644
> > index 00000000000000..0cf09677a3efda
> > --- /dev/null
> > +++ b/src/fs-monitor.c
> > @@ -0,0 +1,153 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright 2021, Collabora Ltd.
> > + * Copied from https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/samples/fanotify/fs-monitor.c
> > + */
> > +
> > +#include <errno.h>
> > +#include <err.h>
> > +#include <stdlib.h>
> > +#include <stdio.h>
> > +#include <fcntl.h>
> > +#include <sys/fanotify.h>
> > +#include <sys/types.h>
> > +#include <unistd.h>
> > +
> > +#ifndef FAN_FS_ERROR
> > +#define FAN_FS_ERROR 0x00008000
> > +#define FAN_EVENT_INFO_TYPE_ERROR 5
> > +
> > +struct fanotify_event_info_error {
> > + struct fanotify_event_info_header hdr;
> > + __s32 error;
> > + __u32 error_count;
> > +};
> > +#endif
> > +
> > +#ifndef FILEID_INO32_GEN
> > +#define FILEID_INO32_GEN 1
> > +#endif
> > +
> > +#ifndef FILEID_INVALID
> > +#define FILEID_INVALID 0xff
> > +#endif
> > +
> > +static void print_fh(struct file_handle *fh)
> > +{
> > + int i;
> > + uint32_t *h = (uint32_t *) fh->f_handle;
> > +
> > + printf("\tfh: ");
> > + for (i = 0; i < fh->handle_bytes; i++)
> > + printf("%hhx", fh->f_handle[i]);
> > + printf("\n");
> > +
> > + printf("\tdecoded fh: ");
> > + if (fh->handle_type == FILEID_INO32_GEN)
> > + printf("inode=%u gen=%u\n", h[0], h[1]);
> > + else if (fh->handle_type == FILEID_INVALID && !fh->handle_bytes)
> > + printf("Type %d (Superblock error)\n", fh->handle_type);
> > + else
> > + printf("Type %d (Unknown)\n", fh->handle_type);
> > +
> > +}
> > +
> > +static void handle_notifications(char *buffer, int len)
> > +{
> > + struct fanotify_event_metadata *event =
> > + (struct fanotify_event_metadata *) buffer;
> > + struct fanotify_event_info_header *info;
> > + struct fanotify_event_info_error *err;
> > + struct fanotify_event_info_fid *fid;
> > + int off;
> > +
> > + for (; FAN_EVENT_OK(event, len); event = FAN_EVENT_NEXT(event, len)) {
> > +
> > + if (event->mask != FAN_FS_ERROR) {
> > + printf("unexpected FAN MARK: %llx\n",
> > + (unsigned long long)event->mask);
> > + goto next_event;
> > + }
> > +
> > + if (event->fd != FAN_NOFD) {
> > + printf("Unexpected fd (!= FAN_NOFD)\n");
> > + goto next_event;
> > + }
> > +
> > + printf("FAN_FS_ERROR (len=%d)\n", event->event_len);
> > +
> > + for (off = sizeof(*event) ; off < event->event_len;
> > + off += info->len) {
> > + info = (struct fanotify_event_info_header *)
> > + ((char *) event + off);
> > +
> > + switch (info->info_type) {
> > + case FAN_EVENT_INFO_TYPE_ERROR:
> > + err = (struct fanotify_event_info_error *) info;
> > +
> > + printf("\tGeneric Error Record: len=%d\n",
> > + err->hdr.len);
> > + printf("\terror: %d\n", err->error);
> > + printf("\terror_count: %d\n", err->error_count);
> > + break;
> > +
> > + case FAN_EVENT_INFO_TYPE_FID:
> > + fid = (struct fanotify_event_info_fid *) info;
> > +
> > + printf("\tfsid: %x%x\n",
> > +#if defined(__GLIBC__)
> > + fid->fsid.val[0], fid->fsid.val[1]);
> > +#else
> > + fid->fsid.__val[0], fid->fsid.__val[1]);
> > +#endif
> > + print_fh((struct file_handle *) &fid->handle);
> > + break;
> > +
> > + default:
> > + printf("\tUnknown info type=%d len=%d:\n",
> > + info->info_type, info->len);
> > + }
> > + }
> > +next_event:
> > + printf("---\n\n");
> > + fflush(stdout);
> > + }
> > +}
> > +
> > +int main(int argc, char **argv)
> > +{
> > + int fd;
> > +
> > + char buffer[BUFSIZ];
> > +
> > + if (argc < 2) {
> > + printf("Missing path argument\n");
> > + return 1;
> > + }
> > +
> > + fd = fanotify_init(FAN_CLASS_NOTIF|FAN_REPORT_FID, O_RDONLY);
> > + if (fd < 0) {
> > + perror("fanotify_init");
> > + errx(1, "fanotify_init");
> > + }
> > +
> > + if (fanotify_mark(fd, FAN_MARK_ADD|FAN_MARK_FILESYSTEM,
> > + FAN_FS_ERROR, AT_FDCWD, argv[1])) {
> > + perror("fanotify_mark");
> > + errx(1, "fanotify_mark");
> > + }
> > +
> > + printf("fanotify active\n");
> > + fflush(stdout);
> > +
> > + while (1) {
> > + int n = read(fd, buffer, BUFSIZ);
> > +
> > + if (n < 0)
> > + errx(1, "read");
> > +
> > + handle_notifications(buffer, n);
> > + }
> > +
> > + return 0;
> > +}
> > diff --git a/tests/generic/1838 b/tests/generic/1838
> > new file mode 100755
> > index 00000000000000..940811baae3a6e
> > --- /dev/null
> > +++ b/tests/generic/1838
> > @@ -0,0 +1,214 @@
> > +#! /bin/bash
> > +# SPDX-License-Identifier: GPL-2.0-or-later
> > +# Copyright (c) 2024-2026 Oracle. All Rights Reserved.
> > +#
> > +# FS QA Test No. 1838
> > +#
> > +# Check that fsnotify can report file IO errors.
> > +
> > +. ./common/preamble
> > +_begin_fstest auto quick eio selfhealing
> > +
> > +# Override the default cleanup function.
> > +_cleanup()
> > +{
> > + cd /
> > + test -n "$fsmonitor_pid" && kill -TERM $fsmonitor_pid
> > + rm -f $tmp.*
> > + _dmerror_cleanup
> > +}
> > +
> > +# Import common functions.
> > +. ./common/fuzzy
> > +. ./common/filter
> > +. ./common/dmerror
> > +. ./common/systemd
> > +
> > +_require_scratch
> > +_require_dm_target error
> > +_require_test_program fs-monitor
> > +_require_xfs_io_command "fiemap"
> > +_require_odirect
> > +_require_fanotify_ioerrors
> > +
> > +# no out of place writes
> > +test "$FSTYP" = "xfs" && _require_no_xfs_always_cow
> > +
> > +# fsnotify only gives us a file handle, the error number, and the number of
> > +# times it was seen in between event deliveries. The handle is mostly useless
> > +# since we have no generic way to map that to a file path. Therefore we can
> > +# only coalesce all the I/O errors into one report.
> > +filter_fsnotify_errors() {
> > + _filter_scratch | \
> > + grep -E '(FAN_FS_ERROR|Generic Error Record|error: 5)' | \
> > + sed -e "s/len=[0-9]*/len=XXX/g" | \
> > + sort | \
> > + uniq
> > +}
> > +
> > +_scratch_mkfs >> $seqres.full
> > +
> > +#
> > +# The dm-error map added by this test doesn't work on zoned devices because
> > +# table sizes need to be aligned to the zone size, and even for zoned on
> > +# conventional this test will get confused because of the internal RT device.
> > +#
> > +# That check requires a mounted file system, so do a dummy mount before setting
> > +# up DM.
> > +#
> > +_scratch_mount
> > +test $FSTYP = xfs && _require_xfs_scratch_non_zoned
> > +_scratch_unmount
> > +
> > +_dmerror_init
> > +_dmerror_mount >> $seqres.full 2>&1
> > +
> > +test $FSTYP = xfs && _xfs_force_bdev data $SCRATCH_MNT
> > +
> > +# Write a file with 4 file blocks worth of data, figure out the LBA to target
> > +victim=$SCRATCH_MNT/a
> > +file_blksz=$(_get_file_block_size $SCRATCH_MNT)
> > +$XFS_IO_PROG -f -c "pwrite -S 0x58 0 $((4 * file_blksz))" -c "fsync" $victim >> $seqres.full
> > +
> > +awk_len_prog='{print $4}'
> > +bmap_str="$($XFS_IO_PROG -c "fiemap -v" $victim | grep "^[[:space:]]*0:")"
> > +echo "$bmap_str" >> $seqres.full
> > +
> > +phys="$(echo "$bmap_str" | $AWK_PROG '{print $3}')"
> > +len="$(echo "$bmap_str" | $AWK_PROG "$awk_len_prog")"
> > +
> > +fs_blksz=$(_get_block_size $SCRATCH_MNT)
> > +echo "file_blksz:$file_blksz:fs_blksz:$fs_blksz" >> $seqres.full
> > +kernel_sectors_per_fs_block=$((fs_blksz / 512))
> > +
> > +# Did we get at least 4 fs blocks worth of extent?
> > +min_len_sectors=$(( 4 * kernel_sectors_per_fs_block ))
> > +test "$len" -lt $min_len_sectors && \
> > + _fail "could not format a long enough extent on an empty fs??"
> > +
> > +phys_start=$(echo "$phys" | sed -e 's/\.\..*//g')
> > +
> > +echo "$phys:$len:$fs_blksz:$phys_start" >> $seqres.full
> > +echo "victim file:" >> $seqres.full
> > +od -tx1 -Ad -c $victim >> $seqres.full
> > +
> > +# Set the dmerror table so that all IO will pass through.
> > +_dmerror_reset_table
> > +
> > +cat >> $seqres.full << ENDL
> > +dmerror before:
> > +$DMERROR_TABLE
> > +$DMERROR_RTTABLE
> > +<end table>
> > +ENDL
> > +
> > +# All sector numbers that we feed to the kernel must be in units of 512b, but
> > +# they also must be aligned to the device's logical block size.
> > +logical_block_size=`$here/src/min_dio_alignment $SCRATCH_MNT $SCRATCH_DEV`
> > +kernel_sectors_per_device_lba=$((logical_block_size / 512))
> > +
> > +# Mark as bad one of the device LBAs in the middle of the extent. Target the
> > +# second LBA of the third block of the four-block file extent that we allocated
> > +# earlier, but without overflowing into the fourth file block.
> > +bad_sector=$(( phys_start + (2 * kernel_sectors_per_fs_block) ))
> > +bad_len=$kernel_sectors_per_device_lba
> > +if (( kernel_sectors_per_device_lba < kernel_sectors_per_fs_block )); then
> > + bad_sector=$((bad_sector + kernel_sectors_per_device_lba))
> > +fi
> > +if (( (bad_sector % kernel_sectors_per_device_lba) != 0)); then
> > + echo "bad_sector $bad_sector not congruent with device logical block size $logical_block_size"
> > +fi
> > +
> > +# Remount to flush the page cache, start fsnotify, and make the LBA bad
> > +_dmerror_unmount
> > +_dmerror_mount
> > +
> > +$here/src/fs-monitor $SCRATCH_MNT > $tmp.fsmonitor &
> > +fsmonitor_pid=$!
> > +sleep 1
> > +
> > +_dmerror_mark_range_bad $bad_sector $bad_len
> > +
> > +cat >> $seqres.full << ENDL
> > +dmerror after marking bad:
> > +$DMERROR_TABLE
> > +$DMERROR_RTTABLE
> > +<end table>
> > +ENDL
> > +
> > +_dmerror_load_error_table
> > +
> > +# See if buffered reads pick it up
> > +echo "Try buffered read"
> > +$XFS_IO_PROG -c "pread 0 $((4 * file_blksz))" $victim >> $seqres.full
> > +
> > +# See if directio reads pick it up
> > +echo "Try directio read"
> > +$XFS_IO_PROG -d -c "pread 0 $((4 * file_blksz))" $victim >> $seqres.full
> > +
> > +# See if directio writes pick it up
> > +echo "Try directio write"
> > +$XFS_IO_PROG -d -c "pwrite -S 0x58 0 $((4 * file_blksz))" -c fsync $victim >> $seqres.full
> > +
> > +# See if buffered writes pick it up
> > +echo "Try buffered write"
> > +$XFS_IO_PROG -c "pwrite -S 0x58 0 $((4 * file_blksz))" -c fsync $victim >> $seqres.full
> > +
> > +# Now mark the bad range good so that unmount won't fail due to IO errors.
> > +echo "Fix device"
> > +_dmerror_mark_range_good $bad_sector $bad_len
> > +_dmerror_load_error_table
> > +
> > +cat >> $seqres.full << ENDL
> > +dmerror after marking good:
> > +$DMERROR_TABLE
> > +$DMERROR_RTTABLE
> > +<end table>
> > +ENDL
> > +
> > +# Unmount filesystem to start fresh
> > +echo "Kill fsnotify"
> > +_dmerror_unmount
> > +sleep 1
> > +kill -TERM $fsmonitor_pid
> > +unset fsmonitor_pid
> > +echo fsnotify log >> $seqres.full
> > +cat $tmp.fsmonitor >> $seqres.full
> > +cat $tmp.fsmonitor | filter_fsnotify_errors
> > +
> > +# Start fsnotify again so that can verify that the errors don't persist after
> > +# we flip back to the good dm table.
> > +echo "Remount and restart fsnotify"
> > +_dmerror_mount
> > +$here/src/fs-monitor $SCRATCH_MNT > $tmp.fsmonitor &
> > +fsmonitor_pid=$!
> > +sleep 1
> > +
> > +# See if buffered reads pick it up
> > +echo "Try buffered read again"
> > +$XFS_IO_PROG -c "pread 0 $((4 * file_blksz))" $victim >> $seqres.full
> > +
> > +# See if directio reads pick it up
> > +echo "Try directio read again"
> > +$XFS_IO_PROG -d -c "pread 0 $((4 * file_blksz))" $victim >> $seqres.full
> > +
> > +# See if directio writes pick it up
> > +echo "Try directio write again"
> > +$XFS_IO_PROG -d -c "pwrite -S 0x58 0 $((4 * file_blksz))" -c fsync $victim >> $seqres.full
> > +
> > +# See if buffered writes pick it up
> > +echo "Try buffered write again"
> > +$XFS_IO_PROG -c "pwrite -S 0x58 0 $((4 * file_blksz))" -c fsync $victim >> $seqres.full
> > +
> > +# Unmount fs and kill fsnotify, then wait for it to finish
> > +echo "Kill fsnotify again"
> > +_dmerror_unmount
> > +sleep 1
> > +kill -TERM $fsmonitor_pid
> > +unset fsmonitor_pid
> > +cat $tmp.fsmonitor >> $seqres.full
> > +cat $tmp.fsmonitor | filter_fsnotify_errors
> > +
> > +# success, all done
> > +status=0
> > +exit
> > diff --git a/tests/generic/1838.out b/tests/generic/1838.out
> > new file mode 100644
> > index 00000000000000..adae590fe0b2ea
> > --- /dev/null
> > +++ b/tests/generic/1838.out
> > @@ -0,0 +1,20 @@
> > +QA output created by 1838
> > +Try buffered read
> > +pread: Input/output error
> > +Try directio read
> > +pread: Input/output error
> > +Try directio write
> > +pwrite: Input/output error
> > +Try buffered write
> > +fsync: Input/output error
> > +Fix device
> > +Kill fsnotify
> > + Generic Error Record: len=XXX
> > + error: 5
> > +FAN_FS_ERROR (len=XXX)
> > +Remount and restart fsnotify
> > +Try buffered read again
> > +Try directio read again
> > +Try directio write again
> > +Try buffered write again
> > +Kill fsnotify again
> >
>
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 1/1] generic: test fsnotify filesystem error reporting
2026-03-10 3:50 ` [PATCH 1/1] generic: test fsnotify filesystem " Darrick J. Wong
2026-03-10 7:07 ` Amir Goldstein
2026-03-13 18:01 ` Zorro Lang
@ 2026-03-16 9:08 ` Christoph Hellwig
2026-03-16 16:21 ` Darrick J. Wong
2 siblings, 1 reply; 22+ messages in thread
From: Christoph Hellwig @ 2026-03-16 9:08 UTC (permalink / raw)
To: Darrick J. Wong
Cc: zlang, jack, fstests, amir73il, gabriel, linux-fsdevel, linux-xfs,
hch
On Mon, Mar 09, 2026 at 08:50:08PM -0700, Darrick J. Wong wrote:
> From: Darrick J. Wong <djwong@kernel.org>
>
> Test the fsnotify filesystem error reporting.
Still would be helpful to explain what is being tested and how and
the source of the test tool.
> +#ifndef FILEID_INO32_GEN
> +#define FILEID_INO32_GEN 1
> +#endif
> +
> +#ifndef FILEID_INVALID
> +#define FILEID_INVALID 0xff
> +#endif
> +
> +static void print_fh(struct file_handle *fh)
> +{
> + int i;
> + uint32_t *h = (uint32_t *) fh->f_handle;
> +
> + printf("\tfh: ");
> + for (i = 0; i < fh->handle_bytes; i++)
> + printf("%hhx", fh->f_handle[i]);
> + printf("\n");
> +
> + printf("\tdecoded fh: ");
> + if (fh->handle_type == FILEID_INO32_GEN)
> + printf("inode=%u gen=%u\n", h[0], h[1]);
> + else if (fh->handle_type == FILEID_INVALID && !fh->handle_bytes)
> + printf("Type %d (Superblock error)\n", fh->handle_type);
> + else
> + printf("Type %d (Unknown)\n", fh->handle_type);
Isn't this always going to print unknown for normal xfs mounts without
inode32?
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 1/1] generic: test fsnotify filesystem error reporting
2026-03-16 9:08 ` Christoph Hellwig
@ 2026-03-16 16:21 ` Darrick J. Wong
2026-03-16 18:40 ` Zorro Lang
0 siblings, 1 reply; 22+ messages in thread
From: Darrick J. Wong @ 2026-03-16 16:21 UTC (permalink / raw)
To: Christoph Hellwig
Cc: zlang, jack, fstests, amir73il, gabriel, linux-fsdevel, linux-xfs,
hch
On Mon, Mar 16, 2026 at 02:08:11AM -0700, Christoph Hellwig wrote:
> On Mon, Mar 09, 2026 at 08:50:08PM -0700, Darrick J. Wong wrote:
> > From: Darrick J. Wong <djwong@kernel.org>
> >
> > Test the fsnotify filesystem error reporting.
>
> Still would be helpful to explain what is being tested and how and
> the source of the test tool.
"Use dmerror to inject a media error for a file's storage, then run some
IO and make sure that fanotify reports the IO errors."
(I'm not sure what the process is for updating commit messages once
something's in patches-in-queue...)
> > +#ifndef FILEID_INO32_GEN
> > +#define FILEID_INO32_GEN 1
> > +#endif
> > +
> > +#ifndef FILEID_INVALID
> > +#define FILEID_INVALID 0xff
> > +#endif
> > +
> > +static void print_fh(struct file_handle *fh)
> > +{
> > + int i;
> > + uint32_t *h = (uint32_t *) fh->f_handle;
> > +
> > + printf("\tfh: ");
> > + for (i = 0; i < fh->handle_bytes; i++)
> > + printf("%hhx", fh->f_handle[i]);
> > + printf("\n");
> > +
> > + printf("\tdecoded fh: ");
> > + if (fh->handle_type == FILEID_INO32_GEN)
> > + printf("inode=%u gen=%u\n", h[0], h[1]);
> > + else if (fh->handle_type == FILEID_INVALID && !fh->handle_bytes)
> > + printf("Type %d (Superblock error)\n", fh->handle_type);
> > + else
> > + printf("Type %d (Unknown)\n", fh->handle_type);
>
>
> Isn't this always going to print unknown for normal xfs mounts without
> inode32?
Yes, though generic/791 filters out the file handle and (TBH) I don't
really want people getting ideas about cracking file handles. Probably
we should just eliminate this whole part of the function, but that would
make future forklift upgrades from the kernel harder.
--D
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 1/1] generic: test fsnotify filesystem error reporting
2026-03-16 16:21 ` Darrick J. Wong
@ 2026-03-16 18:40 ` Zorro Lang
2026-03-16 22:16 ` Darrick J. Wong
0 siblings, 1 reply; 22+ messages in thread
From: Zorro Lang @ 2026-03-16 18:40 UTC (permalink / raw)
To: Darrick J. Wong
Cc: Christoph Hellwig, jack, fstests, amir73il, gabriel,
linux-fsdevel, linux-xfs, hch
On Mon, Mar 16, 2026 at 09:21:47AM -0700, Darrick J. Wong wrote:
> On Mon, Mar 16, 2026 at 02:08:11AM -0700, Christoph Hellwig wrote:
> > On Mon, Mar 09, 2026 at 08:50:08PM -0700, Darrick J. Wong wrote:
> > > From: Darrick J. Wong <djwong@kernel.org>
> > >
> > > Test the fsnotify filesystem error reporting.
> >
> > Still would be helpful to explain what is being tested and how and
> > the source of the test tool.
>
> "Use dmerror to inject a media error for a file's storage, then run some
> IO and make sure that fanotify reports the IO errors."
>
> (I'm not sure what the process is for updating commit messages once
> something's in patches-in-queue...)
patches-in-queue is a scratch branch, I always re-push(-f) to this branch.
So please feel free to tell me what do you want to update in this patch
(I'm going to make the next fstests release soon:).
Thanks,
Zorro
>
> > > +#ifndef FILEID_INO32_GEN
> > > +#define FILEID_INO32_GEN 1
> > > +#endif
> > > +
> > > +#ifndef FILEID_INVALID
> > > +#define FILEID_INVALID 0xff
> > > +#endif
> > > +
> > > +static void print_fh(struct file_handle *fh)
> > > +{
> > > + int i;
> > > + uint32_t *h = (uint32_t *) fh->f_handle;
> > > +
> > > + printf("\tfh: ");
> > > + for (i = 0; i < fh->handle_bytes; i++)
> > > + printf("%hhx", fh->f_handle[i]);
> > > + printf("\n");
> > > +
> > > + printf("\tdecoded fh: ");
> > > + if (fh->handle_type == FILEID_INO32_GEN)
> > > + printf("inode=%u gen=%u\n", h[0], h[1]);
> > > + else if (fh->handle_type == FILEID_INVALID && !fh->handle_bytes)
> > > + printf("Type %d (Superblock error)\n", fh->handle_type);
> > > + else
> > > + printf("Type %d (Unknown)\n", fh->handle_type);
> >
> >
> > Isn't this always going to print unknown for normal xfs mounts without
> > inode32?
>
> Yes, though generic/791 filters out the file handle and (TBH) I don't
> really want people getting ideas about cracking file handles. Probably
> we should just eliminate this whole part of the function, but that would
> make future forklift upgrades from the kernel harder.
>
> --D
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 1/1] generic: test fsnotify filesystem error reporting
2026-03-16 18:40 ` Zorro Lang
@ 2026-03-16 22:16 ` Darrick J. Wong
2026-03-17 3:43 ` Zorro Lang
0 siblings, 1 reply; 22+ messages in thread
From: Darrick J. Wong @ 2026-03-16 22:16 UTC (permalink / raw)
To: Zorro Lang
Cc: Christoph Hellwig, jack, fstests, amir73il, gabriel,
linux-fsdevel, linux-xfs, hch
On Tue, Mar 17, 2026 at 02:40:41AM +0800, Zorro Lang wrote:
> On Mon, Mar 16, 2026 at 09:21:47AM -0700, Darrick J. Wong wrote:
> > On Mon, Mar 16, 2026 at 02:08:11AM -0700, Christoph Hellwig wrote:
> > > On Mon, Mar 09, 2026 at 08:50:08PM -0700, Darrick J. Wong wrote:
> > > > From: Darrick J. Wong <djwong@kernel.org>
> > > >
> > > > Test the fsnotify filesystem error reporting.
> > >
> > > Still would be helpful to explain what is being tested and how and
> > > the source of the test tool.
> >
> > "Use dmerror to inject a media error for a file's storage, then run some
> > IO and make sure that fanotify reports the IO errors."
> >
> > (I'm not sure what the process is for updating commit messages once
> > something's in patches-in-queue...)
>
> patches-in-queue is a scratch branch, I always re-push(-f) to this branch.
> So please feel free to tell me what do you want to update in this patch
> (I'm going to make the next fstests release soon:).
Just the two changes I've mentioned so far in the threads, please.
I've more fixes to make to these tests, so I'll send those patches
shortly.
--D
> Thanks,
> Zorro
>
> >
> > > > +#ifndef FILEID_INO32_GEN
> > > > +#define FILEID_INO32_GEN 1
> > > > +#endif
> > > > +
> > > > +#ifndef FILEID_INVALID
> > > > +#define FILEID_INVALID 0xff
> > > > +#endif
> > > > +
> > > > +static void print_fh(struct file_handle *fh)
> > > > +{
> > > > + int i;
> > > > + uint32_t *h = (uint32_t *) fh->f_handle;
> > > > +
> > > > + printf("\tfh: ");
> > > > + for (i = 0; i < fh->handle_bytes; i++)
> > > > + printf("%hhx", fh->f_handle[i]);
> > > > + printf("\n");
> > > > +
> > > > + printf("\tdecoded fh: ");
> > > > + if (fh->handle_type == FILEID_INO32_GEN)
> > > > + printf("inode=%u gen=%u\n", h[0], h[1]);
> > > > + else if (fh->handle_type == FILEID_INVALID && !fh->handle_bytes)
> > > > + printf("Type %d (Superblock error)\n", fh->handle_type);
> > > > + else
> > > > + printf("Type %d (Unknown)\n", fh->handle_type);
> > >
> > >
> > > Isn't this always going to print unknown for normal xfs mounts without
> > > inode32?
> >
> > Yes, though generic/791 filters out the file handle and (TBH) I don't
> > really want people getting ideas about cracking file handles. Probably
> > we should just eliminate this whole part of the function, but that would
> > make future forklift upgrades from the kernel harder.
> >
> > --D
> >
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 1/1] generic: test fsnotify filesystem error reporting
2026-03-16 22:16 ` Darrick J. Wong
@ 2026-03-17 3:43 ` Zorro Lang
0 siblings, 0 replies; 22+ messages in thread
From: Zorro Lang @ 2026-03-17 3:43 UTC (permalink / raw)
To: Darrick J. Wong
Cc: Christoph Hellwig, jack, fstests, amir73il, gabriel,
linux-fsdevel, linux-xfs, hch
On Mon, Mar 16, 2026 at 03:16:58PM -0700, Darrick J. Wong wrote:
> On Tue, Mar 17, 2026 at 02:40:41AM +0800, Zorro Lang wrote:
> > On Mon, Mar 16, 2026 at 09:21:47AM -0700, Darrick J. Wong wrote:
> > > On Mon, Mar 16, 2026 at 02:08:11AM -0700, Christoph Hellwig wrote:
> > > > On Mon, Mar 09, 2026 at 08:50:08PM -0700, Darrick J. Wong wrote:
> > > > > From: Darrick J. Wong <djwong@kernel.org>
> > > > >
> > > > > Test the fsnotify filesystem error reporting.
> > > >
> > > > Still would be helpful to explain what is being tested and how and
> > > > the source of the test tool.
> > >
> > > "Use dmerror to inject a media error for a file's storage, then run some
> > > IO and make sure that fanotify reports the IO errors."
> > >
> > > (I'm not sure what the process is for updating commit messages once
> > > something's in patches-in-queue...)
> >
> > patches-in-queue is a scratch branch, I always re-push(-f) to this branch.
> > So please feel free to tell me what do you want to update in this patch
> > (I'm going to make the next fstests release soon:).
>
> Just the two changes I've mentioned so far in the threads, please.
Sure, I just changed the commit log of this patch to:
"Use dmerror to inject a media error for a file's storage, then run some
IO and make sure that fanotify reports the IO errors."
but what's the 2nd change? Did I miss something? ...
>
> I've more fixes to make to these tests, so I'll send those patches
> shortly.
>
> --D
>
> > Thanks,
> > Zorro
> >
> > >
> > > > > +#ifndef FILEID_INO32_GEN
> > > > > +#define FILEID_INO32_GEN 1
> > > > > +#endif
> > > > > +
> > > > > +#ifndef FILEID_INVALID
> > > > > +#define FILEID_INVALID 0xff
> > > > > +#endif
> > > > > +
> > > > > +static void print_fh(struct file_handle *fh)
> > > > > +{
> > > > > + int i;
> > > > > + uint32_t *h = (uint32_t *) fh->f_handle;
> > > > > +
> > > > > + printf("\tfh: ");
> > > > > + for (i = 0; i < fh->handle_bytes; i++)
> > > > > + printf("%hhx", fh->f_handle[i]);
> > > > > + printf("\n");
> > > > > +
> > > > > + printf("\tdecoded fh: ");
> > > > > + if (fh->handle_type == FILEID_INO32_GEN)
> > > > > + printf("inode=%u gen=%u\n", h[0], h[1]);
> > > > > + else if (fh->handle_type == FILEID_INVALID && !fh->handle_bytes)
> > > > > + printf("Type %d (Superblock error)\n", fh->handle_type);
> > > > > + else
> > > > > + printf("Type %d (Unknown)\n", fh->handle_type);
> > > >
> > > >
> > > > Isn't this always going to print unknown for normal xfs mounts without
> > > > inode32?
> > >
> > > Yes, though generic/791 filters out the file handle and (TBH) I don't
> > > really want people getting ideas about cracking file handles. Probably
> > > we should just eliminate this whole part of the function, but that would
> > > make future forklift upgrades from the kernel harder.
... This looks like not a certain decision/change. Is this the 2nd change you want
to do? If so, could you please provide what's the specific changes you want to make :)
Thanks,
Zorro
> > >
> > > --D
> > >
> >
>
^ permalink raw reply [flat|nested] 22+ messages in thread
end of thread, other threads:[~2026-03-17 3:43 UTC | newest]
Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20260310033846.GH1105363@frogsfrogsfrogs>
2026-03-10 3:42 ` [PATCHSET v9 1/2] fstests: test generic file IO error reporting Darrick J. Wong
2026-03-10 3:50 ` [PATCH 1/1] generic: test fsnotify filesystem " Darrick J. Wong
2026-03-10 7:07 ` Amir Goldstein
2026-03-13 18:01 ` Zorro Lang
2026-03-13 23:27 ` Darrick J. Wong
2026-03-16 9:08 ` Christoph Hellwig
2026-03-16 16:21 ` Darrick J. Wong
2026-03-16 18:40 ` Zorro Lang
2026-03-16 22:16 ` Darrick J. Wong
2026-03-17 3:43 ` Zorro Lang
2026-03-03 0:33 [PATCHSET v8 1/2] fstests: test generic file IO " Darrick J. Wong
2026-03-03 0:40 ` [PATCH 1/1] generic: test fsnotify filesystem " Darrick J. Wong
2026-03-03 9:21 ` Amir Goldstein
2026-03-03 14:51 ` Christoph Hellwig
2026-03-03 14:56 ` Amir Goldstein
2026-03-04 10:10 ` Jan Kara
2026-03-03 14:54 ` Christoph Hellwig
2026-03-03 16:06 ` Gabriel Krisman Bertazi
2026-03-03 16:12 ` Christoph Hellwig
2026-03-03 16:38 ` Darrick J. Wong
2026-03-03 16:49 ` Darrick J. Wong
2026-03-03 16:53 ` Christoph Hellwig
2026-03-03 17:59 ` Darrick J. Wong
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox