[LTP] [PATCH v1] fanotify22.c: handle multiple asynchronous error events

Wei Gao via ltp
2026-03-04T13:38:56Z

Since the introduction of the asynchronous fserror reporting framework
(kernel commit 81d2e13a57c9), fanotify22 has encountered sporadic failures
due to the non-deterministic nature of event delivery and merging:

1) tcase3 failure: A race condition occurs when the test reads the
notification fd between two events. Adding a short delay
(usleep) ensures all events are dispatched and ready before the
read() call.

2) tcase4 failure: The kernel may deliver errors as independent events
instead of a single merged event, The test logic is updated to
validate the expected error_count by either a single merged event
or the accumulation of multiple independent events in the buffer.

Reported-by: kernel test robot <oliver.sang@intel.com>
Closes: https://lore.kernel.org/oe-lkp/202602042124.87bd00e3-lkp@intel.com
Signed-off-by: Wei Gao <wegao@suse.com>
---
.../kernel/syscalls/fanotify/fanotify22.c | 32 ++++++++++++++++---
1 file changed, 28 insertions(+), 4 deletions(-)

diff --git a/testcases/kernel/syscalls/fanotify/fanotify22.c b/testcases/kernel/syscalls/fanotify/fanotify22.c
index 6578474a7..82eed7ba9 100644
--- a/testcases/kernel/syscalls/fanotify/fanotify22.c
+++ b/testcases/kernel/syscalls/fanotify/fanotify22.c
@@ -53,6 +53,8 @@ static struct fanotify_fid_t null_fid;
static struct fanotify_fid_t bad_file_fid;
static struct fanotify_fid_t bad_link_fid;

+static int event_count;
+
static void trigger_fs_abort(void)
{
SAFE_MOUNT(tst_device->dev, MOUNT_PATH, tst_device->fs_type,
@@ -88,7 +90,6 @@ static void trigger_bad_link_lookup(void)
ret, BAD_LINK, errno, EUCLEAN);
}

-
static void tcase3_trigger(void)
{
trigger_bad_link_lookup();
@@ -176,9 +177,10 @@ static int check_error_event_info_error(struct fanotify_event_info_error *info_e
{
int fail = 0;

- if (info_error->error_count != ex->error_count) {
- tst_res(TFAIL, "%s: Unexpected error_count (%d!=%d)",
- ex->name, info_error->error_count, ex->error_count);
+ if (info_error->error_count != ex->error_count && event_count != ex->error_count) {
+ tst_res(TFAIL, "%s: Unexpected error_count (%d!=%d && %d!=%d)",
+ ex->name, info_error->error_count, ex->error_count,
+ event_count, ex->error_count);
fail++;
}

@@ -255,8 +257,30 @@ static void do_test(unsigned int i)

tcase->trigger_error();

+ usleep(100000);
+
read_len = SAFE_READ(0, fd_notify, event_buf, BUF_SIZE);

+ struct fanotify_event_metadata *metadata;
+ size_t len = read_len;
+
+ event_count = 0;
+
+ for (metadata = (struct fanotify_event_metadata *)event_buf;
+ FAN_EVENT_OK(metadata, len);
+ metadata = FAN_EVENT_NEXT(metadata, len)) {
+ event_count++;
+ struct fanotify_event_info_error *info_error = get_event_info_error(metadata);
+
+ if (info_error) {
+ tst_res(TINFO, "Event [%d]: errno=%d (expected %d), error_count=%d (expected total %d)",
+ event_count, info_error->error, tcase->error,
+ info_error->error_count, tcase->error_count);
+ } else {
+ tst_res(TINFO, "Event [%d]: No error info record found", event_count);
+ }
+ }
+
SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_REMOVE|FAN_MARK_FILESYSTEM,
FAN_FS_ERROR, AT_FDCWD, MOUNT_PATH);

--
2.52.0