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 02/10] fsnotify: introduce fsnotify group types
Date: Fri, 24 Apr 2026 19:04:55 +0200	[thread overview]
Message-ID: <20260424170503.2096847-3-amir73il@gmail.com> (raw)
In-Reply-To: <20260424170503.2096847-1-amir73il@gmail.com>

Currently an fanotify group can subscribe to events FAN_MNT_ATTACH/DETACH
only on mark type FAN_MARK_MNTNS and IFF the group was initialized with
FAN_REPORT_MNT.

Hence, mount events can not be mixed on the same group with filesystem
events and mntns marks cannot be mixed with filesystem type marks.

Define a new property for an fsnotify group called fsnotify_group_type
which describes the category of events and mark types and use a distinct
category FSNOTIFY_GROUP_TYPE_NS for the mount event groups.

Create helpers fsnotify_is_{fs,ns}_watcher() and the macro
FANOTIFY_NS_INIT_FLAGS and use them to generalize some code that was
checking the FAN_REPORT_MNT flag.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
 fs/notify/fanotify/fanotify.c      |  4 ++-
 fs/notify/fanotify/fanotify_user.c | 40 ++++++++++++++++++++++--------
 fs/notify/group.c                  | 10 +++++---
 include/linux/fanotify.h           |  8 ++++--
 include/linux/fsnotify_backend.h   | 24 ++++++++++++++++++
 5 files changed, 68 insertions(+), 18 deletions(-)

diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index 38290b9c07f7b..e768c25262e27 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -314,9 +314,11 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group,
 	pr_debug("%s: report_mask=%x mask=%x data=%p data_type=%d\n",
 		 __func__, iter_info->report_mask, event_mask, data, data_type);
 
-	if (FAN_GROUP_FLAG(group, FAN_REPORT_MNT)) {
+	if (fsnotify_is_ns_watcher(group)) {
 		if (data_type != FSNOTIFY_EVENT_MNT)
 			return 0;
+	} else if (WARN_ON_ONCE(!fsnotify_is_fs_watcher(group))) {
+		return 0;
 	} else if (!fid_mode) {
 		/* Do we have path to open a file descriptor? */
 		if (!path)
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index 49531a4fe71de..95e7c24c70249 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -1586,8 +1586,11 @@ static struct hlist_head *fanotify_alloc_merge_hash(void)
 DEFINE_CLASS(fsnotify_group,
 	     struct fsnotify_group *,
 	     if (!IS_ERR_OR_NULL(_T)) fsnotify_destroy_group(_T),
-	     fsnotify_alloc_group(ops, flags),
-	     const struct fsnotify_ops *ops, int flags)
+	     __fsnotify_alloc_group(ops, type,
+				    FSNOTIFY_GROUP_FLAG_USER,
+				    GFP_KERNEL_ACCOUNT),
+	     const struct fsnotify_ops *ops,
+	     enum fsnotify_group_type type)
 
 /* fanotify syscalls */
 SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
@@ -1597,18 +1600,22 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
 	unsigned int fid_mode = flags & FANOTIFY_FID_BITS;
 	unsigned int class = flags & FANOTIFY_CLASS_BITS;
 	unsigned int internal_flags = 0;
+	/* A group is either for watching filesystems or namespaces */
+	enum fsnotify_group_type type = (flags & FANOTIFY_NS_INIT_FLAGS) ?
+					FSNOTIFY_GROUP_TYPE_NS :
+					FSNOTIFY_GROUP_TYPE_FS;
 
 	pr_debug("%s: flags=%x event_f_flags=%x\n",
 		 __func__, flags, event_f_flags);
 
 	/*
 	 * An unprivileged user can setup an fanotify group with limited
-	 * functionality - an unprivileged group is limited to notification
-	 * events with file handles or mount ids and it cannot use unlimited
+	 * functionality - an unprivileged group cannot receive filesystem
+	 * notification events with file descriptors and cannot use unlimited
 	 * queue/marks.
 	 */
 	if (((flags & FANOTIFY_ADMIN_INIT_FLAGS) ||
-	     !(flags & (FANOTIFY_FID_BITS | FAN_REPORT_MNT))) &&
+	     !(flags & (FANOTIFY_FID_BITS | FANOTIFY_NS_INIT_FLAGS))) &&
 	    !capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
@@ -1636,8 +1643,11 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
 	if ((flags & FAN_REPORT_PIDFD) && (flags & FAN_REPORT_TID))
 		return -EINVAL;
 
-	/* Don't allow mixing mnt events with inode events for now */
-	if (flags & FAN_REPORT_MNT) {
+	/*
+	 * Namespace watchers do not support priority classes and do not
+	 * support reporting file info event extensions.
+	 */
+	if (type == FSNOTIFY_GROUP_TYPE_NS) {
 		if (class != FAN_CLASS_NOTIF)
 			return -EINVAL;
 		if (flags & (FANOTIFY_FID_BITS | FAN_REPORT_FD_ERROR))
@@ -1681,8 +1691,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
 	if (flags & FAN_NONBLOCK)
 		f_flags |= O_NONBLOCK;
 
-	CLASS(fsnotify_group, group)(&fanotify_fsnotify_ops,
-				     FSNOTIFY_GROUP_FLAG_USER);
+	CLASS(fsnotify_group, group)(&fanotify_fsnotify_ops, type);
 	/* fsnotify_alloc_group takes a ref.  Dropped in fanotify_release */
 	if (IS_ERR(group))
 		return PTR_ERR(group);
@@ -1885,6 +1894,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
 	unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS;
 	unsigned int mark_cmd = flags & FANOTIFY_MARK_CMD_BITS;
 	unsigned int ignore = flags & FANOTIFY_MARK_IGNORE_BITS;
+	enum fsnotify_group_type group_type;
 	unsigned int obj_type, fid_mode;
 	void *obj = NULL;
 	u32 umask = 0;
@@ -1903,15 +1913,19 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
 	switch (mark_type) {
 	case FAN_MARK_INODE:
 		obj_type = FSNOTIFY_OBJ_TYPE_INODE;
+		group_type = FSNOTIFY_GROUP_TYPE_FS;
 		break;
 	case FAN_MARK_MOUNT:
 		obj_type = FSNOTIFY_OBJ_TYPE_VFSMOUNT;
+		group_type = FSNOTIFY_GROUP_TYPE_FS;
 		break;
 	case FAN_MARK_FILESYSTEM:
 		obj_type = FSNOTIFY_OBJ_TYPE_SB;
+		group_type = FSNOTIFY_GROUP_TYPE_FS;
 		break;
 	case FAN_MARK_MNTNS:
 		obj_type = FSNOTIFY_OBJ_TYPE_MNTNS;
+		group_type = FSNOTIFY_GROUP_TYPE_NS;
 		break;
 	default:
 		return -EINVAL;
@@ -1960,6 +1974,9 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
 		return -EINVAL;
 	group = fd_file(f)->private_data;
 
+	if (group->type != group_type)
+		return -EINVAL;
+
 	/* Only report mount events on mnt namespace */
 	if (FAN_GROUP_FLAG(group, FAN_REPORT_MNT)) {
 		if (mask & ~FANOTIFY_MOUNT_EVENTS)
@@ -2005,14 +2022,15 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
 		return -EINVAL;
 
 	/*
-	 * Events that do not carry enough information to report
+	 * Filesystem events that do not carry enough information to report
 	 * event->fd require a group that supports reporting fid.  Those
 	 * events are not supported on a mount mark, because they do not
 	 * carry enough information (i.e. path) to be filtered by mount
 	 * point.
 	 */
 	fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS);
-	if (mask & ~(FANOTIFY_FD_EVENTS|FANOTIFY_MOUNT_EVENTS|FANOTIFY_EVENT_FLAGS) &&
+	if (fsnotify_is_fs_watcher(group) &&
+	    mask & ~(FANOTIFY_FD_EVENTS|FANOTIFY_EVENT_FLAGS) &&
 	    (!fid_mode || mark_type == FAN_MARK_MOUNT))
 		return -EINVAL;
 
diff --git a/fs/notify/group.c b/fs/notify/group.c
index cf445e270ba6a..754d87e3a0189 100644
--- a/fs/notify/group.c
+++ b/fs/notify/group.c
@@ -111,9 +111,9 @@ void fsnotify_put_group(struct fsnotify_group *group)
 }
 EXPORT_SYMBOL_GPL(fsnotify_put_group);
 
-static struct fsnotify_group *__fsnotify_alloc_group(
-				const struct fsnotify_ops *ops,
-				int flags, gfp_t gfp)
+struct fsnotify_group *__fsnotify_alloc_group(const struct fsnotify_ops *ops,
+					      enum fsnotify_group_type type,
+					      int flags, gfp_t gfp)
 {
 	struct fsnotify_group *group;
 
@@ -135,9 +135,11 @@ static struct fsnotify_group *__fsnotify_alloc_group(
 
 	group->ops = ops;
 	group->flags = flags;
+	group->type = type;
 
 	return group;
 }
+EXPORT_SYMBOL_GPL(__fsnotify_alloc_group);
 
 /*
  * Create a new fsnotify_group and hold a reference for the group returned.
@@ -148,7 +150,7 @@ struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops,
 	gfp_t gfp = (flags & FSNOTIFY_GROUP_FLAG_USER) ?
 		    GFP_KERNEL_ACCOUNT : GFP_KERNEL;
 
-	return __fsnotify_alloc_group(ops, flags, gfp);
+	return __fsnotify_alloc_group(ops, FSNOTIFY_GROUP_TYPE_FS, flags, gfp);
 }
 EXPORT_SYMBOL_GPL(fsnotify_alloc_group);
 
diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h
index 879cff5eccd4e..1a09400b843b5 100644
--- a/include/linux/fanotify.h
+++ b/include/linux/fanotify.h
@@ -25,7 +25,10 @@
 
 #define FANOTIFY_FID_BITS	(FAN_REPORT_DFID_NAME_TARGET)
 
-#define FANOTIFY_INFO_MODES	(FANOTIFY_FID_BITS | FAN_REPORT_PIDFD | FAN_REPORT_MNT)
+#define FANOTIFY_INFO_MODES	(FANOTIFY_FID_BITS | FAN_REPORT_PIDFD)
+
+/* fanotify_init() flags to create a namepsace event watcher */
+#define FANOTIFY_NS_INIT_FLAGS	(FAN_REPORT_MNT)
 
 /*
  * fanotify_init() flags that require CAP_SYS_ADMIN.
@@ -47,7 +50,8 @@
  * so one of the flags for reporting file handles is required.
  */
 #define FANOTIFY_USER_INIT_FLAGS	(FAN_CLASS_NOTIF | \
-					 FANOTIFY_FID_BITS | FAN_REPORT_MNT | \
+					 FANOTIFY_FID_BITS | \
+					 FANOTIFY_NS_INIT_FLAGS | \
 					 FAN_CLOEXEC | FAN_NONBLOCK)
 
 #define FANOTIFY_INIT_FLAGS	(FANOTIFY_ADMIN_INIT_FLAGS | \
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index 87524706792e7..698fc75b0b6d4 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -204,6 +204,15 @@ enum fsnotify_group_prio {
 	__FSNOTIFY_PRIO_NUM
 };
 
+/*
+ * Category of kernel objects watched by this group.
+ * Every category has its own mark types and event types.
+ */
+enum fsnotify_group_type {
+	FSNOTIFY_GROUP_TYPE_FS = 0,
+	FSNOTIFY_GROUP_TYPE_NS,
+};
+
 /*
  * A group is a "thing" that wants to receive notification about filesystem
  * events.  The mask holds the subset of event types this group cares about.
@@ -230,6 +239,7 @@ struct fsnotify_group {
 	unsigned int q_len;			/* events on the queue */
 	unsigned int max_events;		/* maximum events allowed on the list */
 	enum fsnotify_group_prio priority;	/* priority for sending events */
+	enum fsnotify_group_type type;		/* category of watched objects */
 	bool shutdown;		/* group is being shut down, don't queue more events */
 
 #define FSNOTIFY_GROUP_FLAG_USER	0x01 /* user allocated group */
@@ -280,6 +290,16 @@ struct fsnotify_group {
 	};
 };
 
+static inline bool fsnotify_is_fs_watcher(const struct fsnotify_group *group)
+{
+	return group->type == FSNOTIFY_GROUP_TYPE_FS;
+}
+
+static inline bool fsnotify_is_ns_watcher(const struct fsnotify_group *group)
+{
+	return group->type == FSNOTIFY_GROUP_TYPE_NS;
+}
+
 /*
  * These helpers are used to prevent deadlock when reclaiming inodes with
  * evictable marks of the same group that is allocating a new mark.
@@ -707,6 +727,10 @@ static inline void fsnotify_update_flags(struct dentry *dentry)
 /* called from fsnotify listeners, such as fanotify or dnotify */
 
 /* create a new group */
+extern struct fsnotify_group *__fsnotify_alloc_group(
+				const struct fsnotify_ops *ops,
+				enum fsnotify_group_type type,
+				int flags, gfp_t gfp);
 extern struct fsnotify_group *fsnotify_alloc_group(
 				const struct fsnotify_ops *ops,
 				int flags);
-- 
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 ` Amir Goldstein [this message]
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 ` [PATCH v2 04/10] fanotify: test event->type instead of event mask when possible Amir Goldstein
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-3-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