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
next prev 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