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>,
	Lennart Poettering <lennart@poettering.net>,
	Tejun Heo <tj@kernel.org>,
	"T . J . Mercier" <tjmercier@google.com>,
	linux-fsdevel@vger.kernel.org
Subject: [RFC][PATCH 2/5] fanotify: use high bits for FAN_NS_CREATE/FAN_NS_DELETE
Date: Sat,  7 Mar 2026 12:05:47 +0100	[thread overview]
Message-ID: <20260307110550.373762-3-amir73il@gmail.com> (raw)
In-Reply-To: <20260307110550.373762-1-amir73il@gmail.com>

For the uapi, but keep using FS_CREATE/FS_DELETE internally, because
we do not mix inode events with ns listeners.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
 fs/notify/fanotify/fanotify.c      | 11 +++--
 fs/notify/fanotify/fanotify_user.c | 31 ++++++++++---
 fs/notify/fdinfo.c                 |  9 +++-
 include/linux/fanotify.h           |  5 ++-
 include/uapi/linux/fanotify.h      | 70 +++++++++++++++++-------------
 5 files changed, 81 insertions(+), 45 deletions(-)

diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index 3818b4d53dcad..4b9c89772404e 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -304,9 +304,8 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group,
 				     const void *data, int data_type,
 				     struct inode *dir)
 {
-	__u32 marks_mask = 0, marks_ignore_mask = 0;
-	__u32 test_mask, user_mask = FANOTIFY_OUTGOING_EVENTS |
-				     FANOTIFY_EVENT_FLAGS;
+	__u32 test_mask, marks_mask = 0, marks_ignore_mask = 0;
+	__u64 user_mask = FANOTIFY_OUTGOING_EVENTS | FANOTIFY_EVENT_FLAGS;
 	const struct path *path = fsnotify_data_path(data, data_type);
 	unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS);
 	struct fsnotify_mark *mark;
@@ -980,8 +979,12 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask,
 	BUILD_BUG_ON(FAN_FS_ERROR != FS_ERROR);
 	BUILD_BUG_ON(FAN_RENAME != FS_RENAME);
 	BUILD_BUG_ON(FAN_PRE_ACCESS != FS_PRE_ACCESS);
+	/* NS events live in upper 32 bits; verify the >> 32 round-trip used in copy_event_to_user */
+	BUILD_BUG_ON(upper_32_bits(FAN_NS_CREATE) != FAN_CREATE);
+	BUILD_BUG_ON(upper_32_bits(FAN_NS_DELETE) != FAN_DELETE);
 
-	BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 24);
+	/* ALL_FANOTIFY_EVENT_BITS now spans 64 bits (NS events in upper 32) */
+	BUILD_BUG_ON(HWEIGHT64(ALL_FANOTIFY_EVENT_BITS) != 26);
 
 	mask = fanotify_group_event_mask(group, iter_info, &match_mask,
 					 mask, data, data_type, dir);
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index 126069101669a..3b23ec1ade8fc 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -883,7 +883,15 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
 	metadata.metadata_len = FAN_EVENT_METADATA_LEN;
 	metadata.vers = FANOTIFY_METADATA_VERSION;
 	metadata.reserved = 0;
-	metadata.mask = event->mask & FANOTIFY_OUTGOING_EVENTS;
+	metadata.mask = event->mask;
+	/*
+	 * NS events are stored internally as FS_CREATE/FS_DELETE (lower 32
+	 * bits) but reported to userspace as FAN_NS_CREATE/FAN_NS_DELETE
+	 * (upper 32 bits).  Shift them back up for the UAPI event mask.
+	 */
+	if (fanotify_is_ns_event(event))
+		metadata.mask <<= 32;
+	metadata.mask &= FANOTIFY_OUTGOING_EVENTS;
 	metadata.pid = pid_vnr(event->pid);
 	/*
 	 * For an unprivileged listener, event->pid can be used to identify the
@@ -1916,7 +1924,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
 	struct fan_fsid __fsid, *fsid = NULL;
 	struct user_namespace *user_ns = NULL;
 	struct mnt_namespace *mntns;
-	u32 valid_mask = FANOTIFY_EVENTS | FANOTIFY_EVENT_FLAGS;
+	u64 valid_mask = FANOTIFY_EVENTS | FANOTIFY_EVENT_FLAGS;
 	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;
@@ -1928,8 +1936,11 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
 	pr_debug("%s: fanotify_fd=%d flags=%x dfd=%d pathname=%p mask=%llx\n",
 		 __func__, fanotify_fd, flags, dfd, pathname, mask);
 
-	/* we only use the lower 32 bits as of right now. */
-	if (upper_32_bits(mask))
+	/*
+	 * NS events (FAN_NS_CREATE/FAN_NS_DELETE) live in the upper 32 bits
+	 * and are only valid for FAN_MARK_USERNS.  Reject any other upper bits.
+	 */
+	if (upper_32_bits(mask) && mark_type != FAN_MARK_USERNS)
 		return -EINVAL;
 
 	if (flags & ~FANOTIFY_MARK_FLAGS)
@@ -2056,7 +2067,8 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
 	 * point.
 	 */
 	fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS);
-	if (mask & ~(FANOTIFY_FD_EVENTS|FANOTIFY_MOUNT_EVENTS|FANOTIFY_EVENT_FLAGS) &&
+	if (mask & ~(FANOTIFY_FD_EVENTS|FANOTIFY_MOUNT_EVENTS|FANOTIFY_NS_EVENTS|
+		     FANOTIFY_EVENT_FLAGS) &&
 	    (!fid_mode || mark_type == FAN_MARK_MOUNT))
 		return -EINVAL;
 
@@ -2178,7 +2190,14 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
 			mask |= FAN_EVENT_ON_CHILD;
 	}
 
-	/* create/update an inode mark */
+	/*
+	 * Translate upper-bit UAPI NS events to the internal FS_CREATE/
+	 * FS_DELETE bits used by fsnotify.
+	 */
+	if (obj_type == FSNOTIFY_OBJ_TYPE_USERNS)
+		mask >>= 32;
+
+	/* create/update an fsnotify mark */
 	switch (mark_cmd) {
 	case FAN_MARK_ADD:
 		ret = fanotify_add_mark(group, obj, obj_type, mask, flags,
diff --git a/fs/notify/fdinfo.c b/fs/notify/fdinfo.c
index 946cffaf16e18..6106fad1dcf1b 100644
--- a/fs/notify/fdinfo.c
+++ b/fs/notify/fdinfo.c
@@ -135,8 +135,13 @@ static void fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark)
 	} else if (mark->connector->type == FSNOTIFY_OBJ_TYPE_USERNS) {
 		struct user_namespace *userns = fsnotify_conn_userns(mark->connector);
 
-		seq_printf(m, "fanotify user_ns_id:%llu mflags:%x mask:%x ignored_mask:%x\n",
-			   userns->ns.ns_id, mflags, mark->mask, mark->ignore_mask);
+		/*
+		 * Userns marks store FS_CREATE/FS_DELETE internally but expose
+		 * FAN_NS_CREATE/FAN_NS_DELETE (upper 32 bits) to userspace.
+		 */
+		seq_printf(m, "fanotify user_ns_id:%llu mflags:%x mask:%llx ignored_mask:%llx\n",
+			   userns->ns.ns_id, mflags,
+			   (u64)mark->mask << 32, (u64)mark->ignore_mask << 32);
 	}
 }
 
diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h
index 279082ae40fe2..e85034063a115 100644
--- a/include/linux/fanotify.h
+++ b/include/linux/fanotify.h
@@ -115,13 +115,14 @@
 #define FANOTIFY_MOUNT_EVENTS	(FAN_MNT_ATTACH | FAN_MNT_DETACH)
 
 /* Events that can be reported with data type FSNOTIFY_EVENT_NS */
-#define FANOTIFY_NS_EVENTS	(FAN_CREATE | FAN_DELETE)
+#define FANOTIFY_NS_EVENTS	(FAN_NS_CREATE | FAN_NS_DELETE)
 
 /* Events that user can request to be notified on */
 #define FANOTIFY_EVENTS		(FANOTIFY_PATH_EVENTS | \
 				 FANOTIFY_INODE_EVENTS | \
 				 FANOTIFY_ERROR_EVENTS | \
-				 FANOTIFY_MOUNT_EVENTS)
+				 FANOTIFY_MOUNT_EVENTS | \
+				 FANOTIFY_NS_EVENTS)
 
 /* Extra flags that may be reported with event or control handling of events */
 #define FANOTIFY_EVENT_FLAGS	(FAN_EVENT_ON_CHILD | FAN_ONDIR)
diff --git a/include/uapi/linux/fanotify.h b/include/uapi/linux/fanotify.h
index 6b4f470ee7e01..45ad484ceb473 100644
--- a/include/uapi/linux/fanotify.h
+++ b/include/uapi/linux/fanotify.h
@@ -5,37 +5,45 @@
 #include <linux/types.h>
 
 /* the following events that user-space can register for */
-#define FAN_ACCESS		0x00000001	/* File was accessed */
-#define FAN_MODIFY		0x00000002	/* File was modified */
-#define FAN_ATTRIB		0x00000004	/* Metadata changed */
-#define FAN_CLOSE_WRITE		0x00000008	/* Writable file closed */
-#define FAN_CLOSE_NOWRITE	0x00000010	/* Unwritable file closed */
-#define FAN_OPEN		0x00000020	/* File was opened */
-#define FAN_MOVED_FROM		0x00000040	/* File was moved from X */
-#define FAN_MOVED_TO		0x00000080	/* File was moved to Y */
-#define FAN_CREATE		0x00000100	/* Subfile was created */
-#define FAN_DELETE		0x00000200	/* Subfile was deleted */
-#define FAN_DELETE_SELF		0x00000400	/* Self was deleted */
-#define FAN_MOVE_SELF		0x00000800	/* Self was moved */
-#define FAN_OPEN_EXEC		0x00001000	/* File was opened for exec */
-
-#define FAN_Q_OVERFLOW		0x00004000	/* Event queued overflowed */
-#define FAN_FS_ERROR		0x00008000	/* Filesystem error */
-
-#define FAN_OPEN_PERM		0x00010000	/* File open in perm check */
-#define FAN_ACCESS_PERM		0x00020000	/* File accessed in perm check */
-#define FAN_OPEN_EXEC_PERM	0x00040000	/* File open/exec in perm check */
-/* #define FAN_DIR_MODIFY	0x00080000 */	/* Deprecated (reserved) */
-
-#define FAN_PRE_ACCESS		0x00100000	/* Pre-content access hook */
-#define FAN_MNT_ATTACH		0x01000000	/* Mount was attached */
-#define FAN_MNT_DETACH		0x02000000	/* Mount was detached */
-
-#define FAN_EVENT_ON_CHILD	0x08000000	/* Interested in child events */
-
-#define FAN_RENAME		0x10000000	/* File was renamed */
-
-#define FAN_ONDIR		0x40000000	/* Event occurred against dir */
+#define FAN_ACCESS		0x00000001ULL	/* File was accessed */
+#define FAN_MODIFY		0x00000002ULL	/* File was modified */
+#define FAN_ATTRIB		0x00000004ULL	/* Metadata changed */
+#define FAN_CLOSE_WRITE		0x00000008ULL	/* Writable file closed */
+#define FAN_CLOSE_NOWRITE	0x00000010ULL	/* Unwritable file closed */
+#define FAN_OPEN		0x00000020ULL	/* File was opened */
+#define FAN_MOVED_FROM		0x00000040ULL	/* File was moved from X */
+#define FAN_MOVED_TO		0x00000080ULL	/* File was moved to Y */
+#define FAN_CREATE		0x00000100ULL	/* Subfile was created */
+#define FAN_DELETE		0x00000200ULL	/* Subfile was deleted */
+#define FAN_DELETE_SELF		0x00000400ULL	/* Self was deleted */
+#define FAN_MOVE_SELF		0x00000800ULL	/* Self was moved */
+#define FAN_OPEN_EXEC		0x00001000ULL	/* File was opened for exec */
+
+#define FAN_Q_OVERFLOW		0x00004000ULL	/* Event queued overflowed */
+#define FAN_FS_ERROR		0x00008000ULL	/* Filesystem error */
+
+#define FAN_OPEN_PERM		0x00010000ULL	/* File open in perm check */
+#define FAN_ACCESS_PERM		0x00020000ULL	/* File accessed in perm check */
+#define FAN_OPEN_EXEC_PERM	0x00040000ULL	/* File open/exec in perm check */
+/* #define FAN_DIR_MODIFY	0x00080000ULL */	/* Deprecated (reserved) */
+
+#define FAN_PRE_ACCESS		0x00100000ULL	/* Pre-content access hook */
+#define FAN_MNT_ATTACH		0x01000000ULL	/* Mount was attached */
+#define FAN_MNT_DETACH		0x02000000ULL	/* Mount was detached */
+
+#define FAN_EVENT_ON_CHILD	0x08000000ULL	/* Interested in child events */
+
+#define FAN_RENAME		0x10000000ULL	/* File was renamed */
+
+#define FAN_ONDIR		0x40000000ULL	/* Event occurred against dir */
+
+/*
+ * Namespace lifecycle events use the upper 32 bits of the 64-bit mask
+ * to avoid confusion with the inode-level FAN_CREATE/FAN_DELETE events.
+ * They are only valid with FAN_MARK_USERNS and FAN_REPORT_NSID.
+ */
+#define FAN_NS_CREATE		(FAN_CREATE << 32)	/* Namespace became active */
+#define FAN_NS_DELETE		(FAN_DELETE << 32)	/* Namespace became inactive */
 
 /* helper events */
 #define FAN_CLOSE		(FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE) /* close */
-- 
2.53.0


  parent reply	other threads:[~2026-03-07 11:05 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-07 11:05 [RFC][PATCH 0/5] fanotify namespace monitoring Amir Goldstein
2026-03-07 11:05 ` [RFC][PATCH 1/5] fanotify: add support for watching the namespaces tree Amir Goldstein
2026-03-09 18:07   ` Amir Goldstein
2026-03-07 11:05 ` Amir Goldstein [this message]
2026-03-07 11:05 ` [RFC][PATCH 3/5] selftests/filesystems: create fanotify test dir Amir Goldstein
2026-03-07 11:05 ` [RFC][PATCH 4/5] filesystems/statmount: update mount.h in tools include dir Amir Goldstein
2026-03-07 11:05 ` [RFC][PATCH 5/5] selftests/filesystems: add fanotify namespace notifications test Amir Goldstein
2026-03-09 12:33 ` [RFC][PATCH 0/5] fanotify namespace monitoring Christian Brauner
2026-03-09 15:47   ` Amir Goldstein
2026-03-10 10:31     ` Christian Brauner
2026-03-10 11:14       ` Amir Goldstein
2026-03-16 10:05         ` Jan Kara

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=20260307110550.373762-3-amir73il@gmail.com \
    --to=amir73il@gmail.com \
    --cc=brauner@kernel.org \
    --cc=jack@suse.cz \
    --cc=lennart@poettering.net \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=tj@kernel.org \
    --cc=tjmercier@google.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox