All of lore.kernel.org
 help / color / mirror / Atom feed
From: Wei Gao via ltp <ltp@lists.linux.it>
To: ltp@lists.linux.it
Cc: kernel test robot <oliver.sang@intel.com>, Jan Kara <jack@suse.cz>
Subject: [LTP] [PATCH v8] fanotify22.c: handle multiple asynchronous error events
Date: Thu,  7 May 2026 02:53:33 +0000	[thread overview]
Message-ID: <20260507025345.6722-1-wegao@suse.com> (raw)
In-Reply-To: <20260331111857.10995-1-wegao@suse.com>

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. Use a poll() and read() loop to wait
   until the expected events are delivered.

2) tcase4 failure: The kernel may deliver errors as independent events
   instead of a single merged event, as different worker kthreads can
   end up generating each event. As suggested by Jan Kara, this patch
   introduces a consolidate_events() helper. It iterates through the
   event buffer, identifies the primary event matching the expected error,
   accumulates the error_count from all independent events, and updates
   the primary event's count in-place for validation.

Reported-by: kernel test robot <oliver.sang@intel.com>
Closes: https://lore.kernel.org/oe-lkp/202602042124.87bd00e3-lkp@intel.com
Suggested-by: Jan Kara <jack@suse.cz>
Signed-off-by: Wei Gao <wegao@suse.com>
---
v7->v8:
- Fix a logic bug where the test would fail if a secondary error (like ESHUTDOWN) was the first event in the buffer
- Move variable declarations to the top of blocks to follow the preferred LTP coding style
 .../kernel/syscalls/fanotify/fanotify22.c     | 119 +++++++++++++++---
 1 file changed, 102 insertions(+), 17 deletions(-)

diff --git a/testcases/kernel/syscalls/fanotify/fanotify22.c b/testcases/kernel/syscalls/fanotify/fanotify22.c
index e8002b160..c124e1904 100644
--- a/testcases/kernel/syscalls/fanotify/fanotify22.c
+++ b/testcases/kernel/syscalls/fanotify/fanotify22.c
@@ -28,6 +28,7 @@
 #include "tst_test.h"
 #include <sys/fanotify.h>
 #include <sys/types.h>
+#include <poll.h>
 
 #ifdef HAVE_SYS_FANOTIFY_H
 #include "fanotify.h"
@@ -88,7 +89,6 @@ static void trigger_bad_link_lookup(void)
 			ret, BAD_LINK, errno, EUCLEAN);
 }
 
-
 static void tcase3_trigger(void)
 {
 	trigger_bad_link_lookup();
@@ -104,6 +104,7 @@ static void tcase4_trigger(void)
 static struct test_case {
 	char *name;
 	int error;
+	int error2;
 	unsigned int error_count;
 	struct fanotify_fid_t *fid;
 	void (*trigger_error)(void);
@@ -134,37 +135,79 @@ static struct test_case {
 		.trigger_error = &tcase4_trigger,
 		.error_count = 2,
 		.error = EFSCORRUPTED,
+		.error2 = ESHUTDOWN,
 		.fid = &bad_file_fid,
 	}
 };
 
+static struct fanotify_event_metadata *consolidate_events(char *buf, size_t len, const struct test_case *ex)
+{
+	struct fanotify_event_metadata *metadata, *primary = NULL;
+	struct fanotify_event_info_error *info, *primary_info = NULL;
+	unsigned int total_count = 0;
+	int event_num = 0;
+
+	for (metadata = (struct fanotify_event_metadata *)buf;
+			FAN_EVENT_OK(metadata, len);
+			metadata = FAN_EVENT_NEXT(metadata, len)) {
+
+		event_num++;
+		info = get_event_info_error(metadata);
+
+		if (!info) {
+			tst_res(TFAIL, "Event [%d] missing error info", event_num);
+			continue;
+		}
+
+		if (info->error != ex->error && (ex->error2 == 0 || info->error != ex->error2)) {
+			tst_res(TFAIL, "Event [%d] unexpected errno (%d)",
+					event_num, info->error);
+			continue;
+		}
+
+		if (!primary && info->error == ex->error) {
+			primary = metadata;
+			primary_info = info;
+		}
+		total_count += info->error_count;
+
+		tst_res(TINFO, "Event [%d]: errno=%d, error_count=%d",
+				event_num, info->error, info->error_count);
+	}
+
+	if (primary_info)
+		primary_info->error_count = total_count;
+
+	return primary;
+}
+
 static int check_error_event_info_fid(struct fanotify_event_info_fid *fid,
 				 const struct test_case *ex)
 {
 	struct file_handle *fh = (struct file_handle *) &fid->handle;
 
 	if (memcmp(&fid->fsid, &ex->fid->fsid, sizeof(fid->fsid))) {
-		tst_res(TFAIL, "%s: Received bad FSID type (%x...!=%x...)",
-			ex->name, FSID_VAL_MEMBER(fid->fsid, 0),
+		tst_res(TFAIL, "Received bad FSID type (%x...!=%x...)",
+			FSID_VAL_MEMBER(fid->fsid, 0),
 			ex->fid->fsid.val[0]);
 
 		return 1;
 	}
 	if (fh->handle_type != ex->fid->handle.handle_type) {
-		tst_res(TFAIL, "%s: Received bad file_handle type (%d!=%d)",
-			ex->name, fh->handle_type, ex->fid->handle.handle_type);
+		tst_res(TFAIL, "Received bad file_handle type (%d!=%d)",
+			fh->handle_type, ex->fid->handle.handle_type);
 		return 1;
 	}
 
 	if (fh->handle_bytes != ex->fid->handle.handle_bytes) {
-		tst_res(TFAIL, "%s: Received bad file_handle len (%d!=%d)",
-			ex->name, fh->handle_bytes, ex->fid->handle.handle_bytes);
+		tst_res(TFAIL, "Received bad file_handle len (%d!=%d)",
+			fh->handle_bytes, ex->fid->handle.handle_bytes);
 		return 1;
 	}
 
 	if (memcmp(fh->f_handle, ex->fid->handle.f_handle, fh->handle_bytes)) {
-		tst_res(TFAIL, "%s: Received wrong handle. "
-			"Expected (%x...) got (%x...) ", ex->name,
+		tst_res(TFAIL, "Received wrong handle. "
+			"Expected (%x...) got (%x...) ",
 			*(int *)ex->fid->handle.f_handle, *(int *)fh->f_handle);
 		return 1;
 	}
@@ -177,14 +220,15 @@ 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);
+		tst_res(TFAIL, "Unexpected error_count (%d!=%d)",
+			info_error->error_count, ex->error_count);
 		fail++;
 	}
 
-	if (info_error->error != ex->error) {
-		tst_res(TFAIL, "%s: Unexpected error code value (%d!=%d)",
-			ex->name, info_error->error, ex->error);
+	if (info_error->error != ex->error &&
+	    (ex->error2 == 0 || info_error->error != ex->error2)) {
+		tst_res(TFAIL, "Unexpected error code value (%d!=%d)",
+			info_error->error, ex->error);
 		fail++;
 	}
 
@@ -248,19 +292,60 @@ static void check_event(char *buf, size_t len, const struct test_case *ex)
 static void do_test(unsigned int i)
 {
 	const struct test_case *tcase = &testcases[i];
-	size_t read_len;
+	struct fanotify_event_metadata *m, *primary;
+	struct fanotify_event_info_error *e;
+	char *current_pos;
+	ssize_t ret;
+	size_t read_len = 0;
+	struct pollfd pfd;
+	unsigned int accumulated_count = 0;
+
+	tst_res(TINFO, "Test case: %s", tcase->name);
 
 	SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD|FAN_MARK_FILESYSTEM,
 			   FAN_FS_ERROR, AT_FDCWD, MOUNT_PATH);
 
 	tcase->trigger_error();
 
-	read_len = SAFE_READ(0, fd_notify, event_buf, BUF_SIZE);
+	pfd.fd = fd_notify;
+	pfd.events = POLLIN;
+
+	while (accumulated_count < tcase->error_count) {
+		if (poll(&pfd, 1, 5000) <= 0) {
+			tst_res(TFAIL, "Timeout waiting for events");
+			goto out;
+		}
+
+		if (BUF_SIZE - read_len < FAN_EVENT_METADATA_LEN)
+			tst_brk(TBROK, "Insufficient buffer space for next event");
+
+		current_pos = event_buf + read_len;
+		ret = SAFE_READ(0, fd_notify, current_pos, BUF_SIZE - read_len);
+
+		m = (struct fanotify_event_metadata *)current_pos;
+		while (FAN_EVENT_OK(m, ret)) {
+			e = get_event_info_error(m);
+
+			if (e)
+				accumulated_count += e->error_count;
+
+			read_len += m->event_len;
+			m = FAN_EVENT_NEXT(m, ret);
+		}
+	}
+
+	primary = consolidate_events(event_buf, read_len, tcase);
+
+	if (primary)
+		check_event((char *)primary, primary->event_len, tcase);
+	else
+		tst_res(TFAIL, "No primary error event found");
+
+out:
 
 	SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_REMOVE|FAN_MARK_FILESYSTEM,
 			   FAN_FS_ERROR, AT_FDCWD, MOUNT_PATH);
 
-	check_event(event_buf, read_len, tcase);
 	/* Unmount and mount the filesystem to get it out of the error state */
 	SAFE_UMOUNT(MOUNT_PATH);
 	SAFE_MOUNT(tst_device->dev, MOUNT_PATH, tst_device->fs_type, 0, NULL);
-- 
2.52.0


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

  parent reply	other threads:[~2026-05-07  2:54 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-10-29  1:27 [LTP] [PATCH v1] io_submit04: Add test case for RWF_NOWAIT flag Wei Gao via ltp
2024-02-06 15:59 ` Petr Vorel
2025-10-22  2:05 ` [LTP] [PATCH v2] " Wei Gao via ltp
2025-12-18 13:21   ` Andrea Cervesato via ltp
2025-12-24  8:49   ` [LTP] [PATCH v3] " Wei Gao via ltp
2026-01-05 12:53     ` Andrea Cervesato via ltp
2026-01-06  6:26       ` Wei Gao via ltp
2026-01-06  8:39         ` Andrea Cervesato via ltp
2026-01-06  8:39         ` Petr Vorel
2026-01-07  8:53           ` Jan Stancek via ltp
2026-01-07  6:10     ` [LTP] [PATCH v4] " Wei Gao via ltp
2026-02-18 12:21       ` Andrea Cervesato via ltp
2026-03-05  4:41         ` Wei Gao via ltp
2026-03-17  7:43       ` [LTP] [PATCH v5] " Wei Gao via ltp
2026-03-17  9:54         ` Andrea Cervesato via ltp
2026-03-17 11:46         ` [LTP] [PATCH v6] " Wei Gao via ltp
2026-03-20 12:54           ` Andrea Cervesato via ltp
2026-03-27 18:17           ` Petr Vorel
2026-03-30  8:08             ` Wei Gao via ltp
2026-04-04  1:00             ` Wei Gao via ltp
2026-03-31 11:18           ` [LTP] [PATCH v7] fanotify22.c: handle multiple asynchronous error events Wei Gao via ltp
2026-04-29 14:51             ` [LTP] " linuxtestproject.agent
2026-05-07  2:58               ` Wei Gao via ltp
2026-05-07  2:53             ` Wei Gao via ltp [this message]
2026-05-07  6:18               ` linuxtestproject.agent
2026-05-07  7:37               ` [LTP] [PATCH v8] " Andrea Cervesato via ltp
2026-05-11 11:30               ` Jan Kara
2026-05-13 10:33               ` Petr Vorel
2026-04-04  1:13           ` [LTP] [PATCH v7] io_submit04: Add test case for RWF_NOWAIT flag Wei Gao via ltp
2026-04-08 15:11             ` Cyril Hrubis
2026-04-09  2:26               ` Wei Gao via ltp
2026-04-09  8:03                 ` Cyril Hrubis
2026-04-09 13:45                   ` Cyril Hrubis

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260507025345.6722-1-wegao@suse.com \
    --to=ltp@lists.linux.it \
    --cc=jack@suse.cz \
    --cc=oliver.sang@intel.com \
    --cc=wegao@suse.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.