public inbox for linux-fsdevel@vger.kernel.org
 help / color / mirror / Atom feed
From: Amir Goldstein <amir73il@gmail.com>
To: Jan Kara <jack@suse.cz>
Cc: Christian Brauner <brauner@kernel.org>, linux-fsdevel@vger.kernel.org
Subject: [PATCH v2 04/10] fanotify: test event->type instead of event mask when possible
Date: Fri, 24 Apr 2026 19:04:57 +0200	[thread overview]
Message-ID: <20260424170503.2096847-5-amir73il@gmail.com> (raw)
In-Reply-To: <20260424170503.2096847-1-amir73il@gmail.com>

The fanotify_event already has a type field, so tests like
fanotify_is_mnt_event() should check the type and not the mask.

In fanotify_alloc_event() determine the mnt and fs_error event
types by data_type, which uniquely identifies those events.

The helper for classifying an fs permission event is renamed to
fanotify_is_fs_perm_event() and takes the group argument to verify
that this is a filesystem group type.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
 fs/notify/fanotify/fanotify.c      | 30 +++++++++++++++---------------
 fs/notify/fanotify/fanotify.h      | 29 +++++++++++++++++++++--------
 fs/notify/fanotify/fanotify_user.c | 18 +++++++++---------
 include/linux/fsnotify_backend.h   |  5 -----
 4 files changed, 45 insertions(+), 37 deletions(-)

diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index 494bba49634e1..80116026d3ae0 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -195,7 +195,7 @@ static int fanotify_merge(struct fsnotify_group *group,
 	 * the event structure we have created in fanotify_handle_event() is the
 	 * one we should check for permission response.
 	 */
-	if (fanotify_is_perm_event(new->mask))
+	if (fanotify_is_perm_event(new))
 		return 0;
 
 	hlist_for_each_entry(old, hlist, merge_list) {
@@ -204,7 +204,7 @@ static int fanotify_merge(struct fsnotify_group *group,
 		if (fanotify_should_merge(old, new)) {
 			old->mask |= new->mask;
 
-			if (fanotify_is_error_event(old->mask))
+			if (fanotify_is_error_event(old))
 				FANOTIFY_EE(old)->err_count++;
 
 			return 1;
@@ -711,11 +711,9 @@ static struct fanotify_event *fanotify_alloc_name_event(struct inode *dir,
 static struct fanotify_event *fanotify_alloc_error_event(
 						struct fsnotify_group *group,
 						__kernel_fsid_t *fsid,
-						const void *data, int data_type,
+						struct fs_error_report *report,
 						unsigned int *hash)
 {
-	struct fs_error_report *report =
-			fsnotify_data_error_report(data, data_type);
 	struct inode *inode;
 	struct fanotify_error_event *fee;
 	int fh_len;
@@ -759,6 +757,8 @@ static struct fanotify_event *fanotify_alloc_event(
 					      fid_mode);
 	struct inode *dirid = fanotify_dfid_inode(mask, data, data_type, dir);
 	const struct path *path = fsnotify_data_path(data, data_type);
+	struct fs_error_report *fs_error =
+		fsnotify_data_error_report(data, data_type);
 	u64 mnt_id = fsnotify_data_mnt_id(data, data_type);
 	struct mem_cgroup *old_memcg;
 	struct dentry *moved = NULL;
@@ -845,11 +845,10 @@ static struct fanotify_event *fanotify_alloc_event(
 	/* Whoever is interested in the event, pays for the allocation. */
 	old_memcg = set_active_memcg(group->memcg);
 
-	if (fanotify_is_perm_event(mask)) {
+	if (fanotify_is_fs_perm_event(group, mask)) {
 		event = fanotify_alloc_perm_event(data, data_type, gfp);
-	} else if (fanotify_is_error_event(mask)) {
-		event = fanotify_alloc_error_event(group, fsid, data,
-						   data_type, &hash);
+	} else if (fs_error) {
+		event = fanotify_alloc_error_event(group, fsid, fs_error, &hash);
 	} else if (name_event && (file_name || moved || child)) {
 		event = fanotify_alloc_name_event(dirid, fsid, file_name, child,
 						  moved, &hash, gfp);
@@ -916,7 +915,7 @@ static void fanotify_insert_event(struct fsnotify_group *group,
 
 	assert_spin_locked(&group->notification_lock);
 
-	if (!fanotify_is_hashed_event(event->mask))
+	if (!fanotify_is_hashed_event(event))
 		return;
 
 	pr_debug("%s: group=%p event=%p bucket=%u\n", __func__,
@@ -970,7 +969,8 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask,
 	pr_debug("%s: group=%p mask=%x report_mask=%x\n", __func__,
 		 group, mask, match_mask);
 
-	if (fanotify_is_perm_event(mask)) {
+	bool is_perm = fanotify_is_fs_perm_event(group, mask);
+	if (is_perm) {
 		/*
 		 * fsnotify_prepare_user_wait() fails if we race with mark
 		 * deletion.  Just let the operation pass in that case.
@@ -990,7 +990,7 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask,
 		 * We don't queue overflow events for permission events as
 		 * there the access is denied and so no event is in fact lost.
 		 */
-		if (!fanotify_is_perm_event(mask))
+		if (!is_perm)
 			fsnotify_queue_overflow(group);
 		goto finish;
 	}
@@ -1000,17 +1000,17 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask,
 				    fanotify_insert_event);
 	if (ret) {
 		/* Permission events shouldn't be merged */
-		BUG_ON(ret == 1 && mask & FANOTIFY_PERM_EVENTS);
+		WARN_ON(ret == 1 && is_perm);
 		/* Our event wasn't used in the end. Free it. */
 		fsnotify_destroy_event(group, fsn_event);
 
 		ret = 0;
-	} else if (fanotify_is_perm_event(mask)) {
+	} else if (is_perm) {
 		ret = fanotify_get_response(group, FANOTIFY_PERM(event),
 					    iter_info);
 	}
 finish:
-	if (fanotify_is_perm_event(mask))
+	if (is_perm)
 		fsnotify_finish_user_wait(iter_info);
 
 	return ret;
diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h
index a0619e7694d57..13e3787ddd558 100644
--- a/fs/notify/fanotify/fanotify.h
+++ b/fs/notify/fanotify/fanotify.h
@@ -265,6 +265,7 @@ struct fanotify_event {
 	struct pid *pid;
 };
 
+
 static inline void fanotify_init_event(struct fanotify_event *event,
 				       unsigned int hash, u32 mask)
 {
@@ -457,12 +458,24 @@ FANOTIFY_PERM(struct fanotify_event *event)
 	return container_of(event, struct fanotify_perm_event, fae);
 }
 
-static inline bool fanotify_is_perm_event(u32 mask)
+static inline bool fanotify_is_fs_perm_event(struct fsnotify_group *group,
+					     u32 mask)
 {
 	return IS_ENABLED(CONFIG_FANOTIFY_ACCESS_PERMISSIONS) &&
+		fsnotify_is_fs_watcher(group) &&
 		mask & FANOTIFY_PERM_EVENTS;
 }
 
+static inline bool fanotify_is_perm_event(struct fanotify_event *event)
+{
+	return event->type == FANOTIFY_EVENT_TYPE_PATH_PERM;
+}
+
+static inline bool fsnotify_is_overflow_event(struct fanotify_event *event)
+{
+	return event->type == FANOTIFY_EVENT_TYPE_OVERFLOW;
+}
+
 static inline bool fanotify_event_has_access_range(struct fanotify_event *event)
 {
 	if (!(event->mask & FANOTIFY_PRE_CONTENT_EVENTS))
@@ -476,14 +489,14 @@ static inline struct fanotify_event *FANOTIFY_E(struct fsnotify_event *fse)
 	return container_of(fse, struct fanotify_event, fse);
 }
 
-static inline bool fanotify_is_error_event(u32 mask)
+static inline bool fanotify_is_error_event(struct fanotify_event *event)
 {
-	return mask & FAN_FS_ERROR;
+	return event->type == FANOTIFY_EVENT_TYPE_FS_ERROR;
 }
 
-static inline bool fanotify_is_mnt_event(u32 mask)
+static inline bool fanotify_is_mnt_event(struct fanotify_event *event)
 {
-	return mask & (FAN_MNT_ATTACH | FAN_MNT_DETACH);
+	return event->type == FANOTIFY_EVENT_TYPE_MNT;
 }
 
 static inline const struct path *fanotify_event_path(struct fanotify_event *event)
@@ -506,10 +519,10 @@ static inline const struct path *fanotify_event_path(struct fanotify_event *even
 /*
  * Permission events and overflow event do not get merged - don't hash them.
  */
-static inline bool fanotify_is_hashed_event(u32 mask)
+static inline bool fanotify_is_hashed_event(struct fanotify_event *event)
 {
-	return !(fanotify_is_perm_event(mask) ||
-		 fsnotify_is_overflow_event(mask));
+	return !(fanotify_is_perm_event(event) ||
+		 fsnotify_is_overflow_event(event));
 }
 
 static inline unsigned int fanotify_event_hash_bucket(
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index 7afb017d40f50..c41c83d86518a 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -257,7 +257,7 @@ static size_t fanotify_event_len(unsigned int info_mode,
 	int fh_len;
 	int dot_len = 0;
 
-	if (fanotify_is_error_event(event->mask))
+	if (fanotify_is_error_event(event))
 		event_len += FANOTIFY_ERROR_INFO_LEN;
 
 	if (fanotify_event_has_any_dir_fh(event)) {
@@ -275,7 +275,7 @@ static size_t fanotify_event_len(unsigned int info_mode,
 		fh_len = fanotify_event_object_fh_len(event);
 		event_len += fanotify_fid_info_len(fh_len, dot_len);
 	}
-	if (fanotify_is_mnt_event(event->mask))
+	if (fanotify_is_mnt_event(event))
 		event_len += FANOTIFY_MNT_INFO_LEN;
 
 	if (info_mode & FAN_REPORT_PIDFD)
@@ -338,9 +338,9 @@ static struct fanotify_event *get_one_event(struct fsnotify_group *group,
 	 * same event we peeked above.
 	 */
 	fsnotify_remove_first_event(group);
-	if (fanotify_is_perm_event(event->mask))
+	if (fanotify_is_perm_event(event))
 		FANOTIFY_PERM(event)->state = FAN_EVENT_REPORTED;
-	if (fanotify_is_hashed_event(event->mask))
+	if (fanotify_is_hashed_event(event))
 		fanotify_unhash_event(group, event);
 out:
 	spin_unlock(&group->notification_lock);
@@ -800,7 +800,7 @@ static int copy_info_records_to_user(struct fanotify_event *event,
 		total_bytes += ret;
 	}
 
-	if (fanotify_is_error_event(event->mask)) {
+	if (fanotify_is_error_event(event)) {
 		ret = copy_error_info_to_user(event, buf, count);
 		if (ret < 0)
 			return ret;
@@ -818,7 +818,7 @@ static int copy_info_records_to_user(struct fanotify_event *event,
 		total_bytes += ret;
 	}
 
-	if (fanotify_is_mnt_event(event->mask)) {
+	if (fanotify_is_mnt_event(event)) {
 		ret = copy_mnt_info_to_user(event, buf, count);
 		if (ret < 0)
 			return ret;
@@ -965,7 +965,7 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
 	if (pidfd_file)
 		fd_install(pidfd, pidfd_file);
 
-	if (fanotify_is_perm_event(event->mask))
+	if (fanotify_is_perm_event(event))
 		FANOTIFY_PERM(event)->fd = fd;
 
 	return metadata.event_len;
@@ -1048,7 +1048,7 @@ static ssize_t fanotify_read(struct file *file, char __user *buf,
 		 * Permission events get queued to wait for response.  Other
 		 * events can be destroyed now.
 		 */
-		if (!fanotify_is_perm_event(event->mask)) {
+		if (!fanotify_is_perm_event(event)) {
 			fsnotify_destroy_event(group, &event->fse);
 		} else {
 			if (ret <= 0 || FANOTIFY_PERM(event)->fd < 0) {
@@ -1145,7 +1145,7 @@ static int fanotify_release(struct inode *ignored, struct file *file)
 	while ((fsn_event = fsnotify_remove_first_event(group))) {
 		struct fanotify_event *event = FANOTIFY_E(fsn_event);
 
-		if (!(event->mask & FANOTIFY_PERM_EVENTS)) {
+		if (!fanotify_is_perm_event(event)) {
 			spin_unlock(&group->notification_lock);
 			fsnotify_destroy_event(group, fsn_event);
 		} else {
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index 8f2821735f068..9ce08d03d041d 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -783,11 +783,6 @@ static inline void fsnotify_queue_overflow(struct fsnotify_group *group)
 	fsnotify_add_event(group, group->overflow_event, NULL);
 }
 
-static inline bool fsnotify_is_overflow_event(u32 mask)
-{
-	return mask & FS_Q_OVERFLOW;
-}
-
 static inline bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group)
 {
 	assert_spin_locked(&group->notification_lock);
-- 
2.54.0


  parent reply	other threads:[~2026-04-24 17:05 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-24 17:04 [PATCH v2 00/10] fanotify namespace monitoring Amir Goldstein
2026-04-24 17:04 ` [PATCH v2 01/10] fsnotify: rename fsnotify group flag macros Amir Goldstein
2026-04-24 17:04 ` [PATCH v2 02/10] fsnotify: introduce fsnotify group types Amir Goldstein
2026-04-24 17:04 ` [PATCH v2 03/10] fsnotify: separate the events bitmask macros by group type Amir Goldstein
2026-04-24 17:04 ` Amir Goldstein [this message]
2026-04-24 17:04 ` [PATCH v2 05/10] fsnotify: do not report mount events with fsnotify() Amir Goldstein
2026-04-24 17:04 ` [PATCH v2 06/10] fanotify: gate fs event classification by group type Amir Goldstein
2026-04-24 17:05 ` [PATCH v2 07/10] fanotify: gate fs events checks in fanotify_mark() " Amir Goldstein
2026-04-24 17:05 ` [PATCH v2 08/10] fanotify: add support for watching the namespaces tree Amir Goldstein
2026-04-24 17:05 ` [PATCH v2 09/10] selftests/filesystems: create fanotify test dir Amir Goldstein
2026-04-24 17:05 ` [PATCH v2 10/10] selftests/filesystems: add fanotify namespace notifications test Amir Goldstein

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=20260424170503.2096847-5-amir73il@gmail.com \
    --to=amir73il@gmail.com \
    --cc=brauner@kernel.org \
    --cc=jack@suse.cz \
    --cc=linux-fsdevel@vger.kernel.org \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox