Skip to content

Commit b944249

Browse files
Miklos Szeredibrauner
authored andcommitted
fsnotify: add mount notification infrastructure
This is just the plumbing between the event source (fs/namespace.c) and the event consumer (fanotify). In itself it does nothing. Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> Link: https://lore.kernel.org/r/20250129165803.72138-2-mszeredi@redhat.com Signed-off-by: Christian Brauner <brauner@kernel.org>
1 parent 2014c95 commit b944249

6 files changed

Lines changed: 128 additions & 10 deletions

File tree

fs/mount.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ struct mnt_namespace {
2121
struct rcu_head mnt_ns_rcu;
2222
};
2323
u64 event;
24+
#ifdef CONFIG_FSNOTIFY
25+
__u32 n_fsnotify_mask;
26+
struct fsnotify_mark_connector __rcu *n_fsnotify_marks;
27+
#endif
2428
unsigned int nr_mounts; /* # of mounts in the namespace */
2529
unsigned int pending_mounts;
2630
struct rb_node mnt_ns_tree_node; /* node in the mnt_ns_tree */

fs/notify/fsnotify.c

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ void __fsnotify_vfsmount_delete(struct vfsmount *mnt)
2828
fsnotify_clear_marks_by_mount(mnt);
2929
}
3030

31+
void __fsnotify_mntns_delete(struct mnt_namespace *mntns)
32+
{
33+
fsnotify_clear_marks_by_mntns(mntns);
34+
}
35+
3136
/**
3237
* fsnotify_unmount_inodes - an sb is unmounting. handle any watched inodes.
3338
* @sb: superblock being unmounted.
@@ -420,7 +425,7 @@ static int send_to_group(__u32 mask, const void *data, int data_type,
420425
file_name, cookie, iter_info);
421426
}
422427

423-
static struct fsnotify_mark *fsnotify_first_mark(struct fsnotify_mark_connector **connp)
428+
static struct fsnotify_mark *fsnotify_first_mark(struct fsnotify_mark_connector *const *connp)
424429
{
425430
struct fsnotify_mark_connector *conn;
426431
struct hlist_node *node = NULL;
@@ -538,14 +543,15 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir,
538543
{
539544
const struct path *path = fsnotify_data_path(data, data_type);
540545
struct super_block *sb = fsnotify_data_sb(data, data_type);
541-
struct fsnotify_sb_info *sbinfo = fsnotify_sb_info(sb);
546+
const struct fsnotify_mnt *mnt_data = fsnotify_data_mnt(data, data_type);
547+
struct fsnotify_sb_info *sbinfo = sb ? fsnotify_sb_info(sb) : NULL;
542548
struct fsnotify_iter_info iter_info = {};
543549
struct mount *mnt = NULL;
544550
struct inode *inode2 = NULL;
545551
struct dentry *moved;
546552
int inode2_type;
547553
int ret = 0;
548-
__u32 test_mask, marks_mask;
554+
__u32 test_mask, marks_mask = 0;
549555

550556
if (path)
551557
mnt = real_mount(path->mnt);
@@ -578,17 +584,20 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir,
578584
if ((!sbinfo || !sbinfo->sb_marks) &&
579585
(!mnt || !mnt->mnt_fsnotify_marks) &&
580586
(!inode || !inode->i_fsnotify_marks) &&
581-
(!inode2 || !inode2->i_fsnotify_marks))
587+
(!inode2 || !inode2->i_fsnotify_marks) &&
588+
(!mnt_data || !mnt_data->ns->n_fsnotify_marks))
582589
return 0;
583590

584-
marks_mask = READ_ONCE(sb->s_fsnotify_mask);
591+
if (sb)
592+
marks_mask |= READ_ONCE(sb->s_fsnotify_mask);
585593
if (mnt)
586594
marks_mask |= READ_ONCE(mnt->mnt_fsnotify_mask);
587595
if (inode)
588596
marks_mask |= READ_ONCE(inode->i_fsnotify_mask);
589597
if (inode2)
590598
marks_mask |= READ_ONCE(inode2->i_fsnotify_mask);
591-
599+
if (mnt_data)
600+
marks_mask |= READ_ONCE(mnt_data->ns->n_fsnotify_mask);
592601

593602
/*
594603
* If this is a modify event we may need to clear some ignore masks.
@@ -618,6 +627,10 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir,
618627
iter_info.marks[inode2_type] =
619628
fsnotify_first_mark(&inode2->i_fsnotify_marks);
620629
}
630+
if (mnt_data) {
631+
iter_info.marks[FSNOTIFY_ITER_TYPE_MNTNS] =
632+
fsnotify_first_mark(&mnt_data->ns->n_fsnotify_marks);
633+
}
621634

622635
/*
623636
* We need to merge inode/vfsmount/sb mark lists so that e.g. inode mark
@@ -702,11 +715,31 @@ void file_set_fsnotify_mode(struct file *file)
702715
}
703716
#endif
704717

718+
void fsnotify_mnt(__u32 mask, struct mnt_namespace *ns, struct vfsmount *mnt)
719+
{
720+
struct fsnotify_mnt data = {
721+
.ns = ns,
722+
.mnt_id = real_mount(mnt)->mnt_id_unique,
723+
};
724+
725+
if (WARN_ON_ONCE(!ns))
726+
return;
727+
728+
/*
729+
* This is an optimization as well as making sure fsnotify_init() has
730+
* been called.
731+
*/
732+
if (!ns->n_fsnotify_marks)
733+
return;
734+
735+
fsnotify(mask, &data, FSNOTIFY_EVENT_MNT, NULL, NULL, NULL, 0);
736+
}
737+
705738
static __init int fsnotify_init(void)
706739
{
707740
int ret;
708741

709-
BUILD_BUG_ON(HWEIGHT32(ALL_FSNOTIFY_BITS) != 24);
742+
BUILD_BUG_ON(HWEIGHT32(ALL_FSNOTIFY_BITS) != 26);
710743

711744
ret = init_srcu_struct(&fsnotify_mark_srcu);
712745
if (ret)

fs/notify/fsnotify.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ static inline struct super_block *fsnotify_conn_sb(
3333
return conn->obj;
3434
}
3535

36+
static inline struct mnt_namespace *fsnotify_conn_mntns(
37+
struct fsnotify_mark_connector *conn)
38+
{
39+
return conn->obj;
40+
}
41+
3642
static inline struct super_block *fsnotify_object_sb(void *obj,
3743
enum fsnotify_obj_type obj_type)
3844
{
@@ -89,6 +95,11 @@ static inline void fsnotify_clear_marks_by_sb(struct super_block *sb)
8995
fsnotify_destroy_marks(fsnotify_sb_marks(sb));
9096
}
9197

98+
static inline void fsnotify_clear_marks_by_mntns(struct mnt_namespace *mntns)
99+
{
100+
fsnotify_destroy_marks(&mntns->n_fsnotify_marks);
101+
}
102+
92103
/*
93104
* update the dentry->d_flags of all of inode's children to indicate if inode cares
94105
* about events that happen to its children.

fs/notify/mark.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ static fsnotify_connp_t *fsnotify_object_connp(void *obj,
107107
return &real_mount(obj)->mnt_fsnotify_marks;
108108
case FSNOTIFY_OBJ_TYPE_SB:
109109
return fsnotify_sb_marks(obj);
110+
case FSNOTIFY_OBJ_TYPE_MNTNS:
111+
return &((struct mnt_namespace *)obj)->n_fsnotify_marks;
110112
default:
111113
return NULL;
112114
}
@@ -120,6 +122,8 @@ static __u32 *fsnotify_conn_mask_p(struct fsnotify_mark_connector *conn)
120122
return &fsnotify_conn_mount(conn)->mnt_fsnotify_mask;
121123
else if (conn->type == FSNOTIFY_OBJ_TYPE_SB)
122124
return &fsnotify_conn_sb(conn)->s_fsnotify_mask;
125+
else if (conn->type == FSNOTIFY_OBJ_TYPE_MNTNS)
126+
return &fsnotify_conn_mntns(conn)->n_fsnotify_mask;
123127
return NULL;
124128
}
125129

@@ -346,12 +350,15 @@ static void *fsnotify_detach_connector_from_object(
346350
fsnotify_conn_mount(conn)->mnt_fsnotify_mask = 0;
347351
} else if (conn->type == FSNOTIFY_OBJ_TYPE_SB) {
348352
fsnotify_conn_sb(conn)->s_fsnotify_mask = 0;
353+
} else if (conn->type == FSNOTIFY_OBJ_TYPE_MNTNS) {
354+
fsnotify_conn_mntns(conn)->n_fsnotify_mask = 0;
349355
}
350356

351357
rcu_assign_pointer(*connp, NULL);
352358
conn->obj = NULL;
353359
conn->type = FSNOTIFY_OBJ_TYPE_DETACHED;
354-
fsnotify_update_sb_watchers(sb, conn);
360+
if (sb)
361+
fsnotify_update_sb_watchers(sb, conn);
355362

356363
return inode;
357364
}
@@ -724,7 +731,7 @@ static int fsnotify_add_mark_list(struct fsnotify_mark *mark, void *obj,
724731
* Attach the sb info before attaching a connector to any object on sb.
725732
* The sb info will remain attached as long as sb lives.
726733
*/
727-
if (!fsnotify_sb_info(sb)) {
734+
if (sb && !fsnotify_sb_info(sb)) {
728735
err = fsnotify_attach_info_to_sb(sb);
729736
if (err)
730737
return err;
@@ -770,7 +777,8 @@ static int fsnotify_add_mark_list(struct fsnotify_mark *mark, void *obj,
770777
/* mark should be the last entry. last is the current last entry */
771778
hlist_add_behind_rcu(&mark->obj_list, &last->obj_list);
772779
added:
773-
fsnotify_update_sb_watchers(sb, conn);
780+
if (sb)
781+
fsnotify_update_sb_watchers(sb, conn);
774782
/*
775783
* Since connector is attached to object using cmpxchg() we are
776784
* guaranteed that connector initialization is fully visible by anyone

include/linux/fsnotify.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,11 @@ static inline void fsnotify_vfsmount_delete(struct vfsmount *mnt)
299299
__fsnotify_vfsmount_delete(mnt);
300300
}
301301

302+
static inline void fsnotify_mntns_delete(struct mnt_namespace *mntns)
303+
{
304+
__fsnotify_mntns_delete(mntns);
305+
}
306+
302307
/*
303308
* fsnotify_inoderemove - an inode is going away
304309
*/
@@ -507,4 +512,19 @@ static inline int fsnotify_sb_error(struct super_block *sb, struct inode *inode,
507512
NULL, NULL, NULL, 0);
508513
}
509514

515+
static inline void fsnotify_mnt_attach(struct mnt_namespace *ns, struct vfsmount *mnt)
516+
{
517+
fsnotify_mnt(FS_MNT_ATTACH, ns, mnt);
518+
}
519+
520+
static inline void fsnotify_mnt_detach(struct mnt_namespace *ns, struct vfsmount *mnt)
521+
{
522+
fsnotify_mnt(FS_MNT_DETACH, ns, mnt);
523+
}
524+
525+
static inline void fsnotify_mnt_move(struct mnt_namespace *ns, struct vfsmount *mnt)
526+
{
527+
fsnotify_mnt(FS_MNT_MOVE, ns, mnt);
528+
}
529+
510530
#endif /* _LINUX_FS_NOTIFY_H */

include/linux/fsnotify_backend.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@
5959

6060
#define FS_PRE_ACCESS 0x00100000 /* Pre-content access hook */
6161

62+
#define FS_MNT_ATTACH 0x01000000 /* Mount was attached */
63+
#define FS_MNT_DETACH 0x02000000 /* Mount was detached */
64+
#define FS_MNT_MOVE (FS_MNT_ATTACH | FS_MNT_DETACH)
65+
6266
/*
6367
* Set on inode mark that cares about things that happen to its children.
6468
* Always set for dnotify and inotify.
@@ -80,6 +84,9 @@
8084
*/
8185
#define ALL_FSNOTIFY_DIRENT_EVENTS (FS_CREATE | FS_DELETE | FS_MOVE | FS_RENAME)
8286

87+
/* Mount namespace events */
88+
#define FSNOTIFY_MNT_EVENTS (FS_MNT_ATTACH | FS_MNT_DETACH)
89+
8390
/* Content events can be used to inspect file content */
8491
#define FSNOTIFY_CONTENT_PERM_EVENTS (FS_OPEN_PERM | FS_OPEN_EXEC_PERM | \
8592
FS_ACCESS_PERM)
@@ -108,6 +115,7 @@
108115

109116
/* Events that can be reported to backends */
110117
#define ALL_FSNOTIFY_EVENTS (ALL_FSNOTIFY_DIRENT_EVENTS | \
118+
FSNOTIFY_MNT_EVENTS | \
111119
FS_EVENTS_POSS_ON_CHILD | \
112120
FS_DELETE_SELF | FS_MOVE_SELF | \
113121
FS_UNMOUNT | FS_Q_OVERFLOW | FS_IN_IGNORED | \
@@ -298,6 +306,7 @@ enum fsnotify_data_type {
298306
FSNOTIFY_EVENT_PATH,
299307
FSNOTIFY_EVENT_INODE,
300308
FSNOTIFY_EVENT_DENTRY,
309+
FSNOTIFY_EVENT_MNT,
301310
FSNOTIFY_EVENT_ERROR,
302311
};
303312

@@ -318,6 +327,11 @@ static inline const struct path *file_range_path(const struct file_range *range)
318327
return range->path;
319328
}
320329

330+
struct fsnotify_mnt {
331+
const struct mnt_namespace *ns;
332+
u64 mnt_id;
333+
};
334+
321335
static inline struct inode *fsnotify_data_inode(const void *data, int data_type)
322336
{
323337
switch (data_type) {
@@ -383,6 +397,24 @@ static inline struct super_block *fsnotify_data_sb(const void *data,
383397
}
384398
}
385399

400+
static inline const struct fsnotify_mnt *fsnotify_data_mnt(const void *data,
401+
int data_type)
402+
{
403+
switch (data_type) {
404+
case FSNOTIFY_EVENT_MNT:
405+
return data;
406+
default:
407+
return NULL;
408+
}
409+
}
410+
411+
static inline u64 fsnotify_data_mnt_id(const void *data, int data_type)
412+
{
413+
const struct fsnotify_mnt *mnt_data = fsnotify_data_mnt(data, data_type);
414+
415+
return mnt_data ? mnt_data->mnt_id : 0;
416+
}
417+
386418
static inline struct fs_error_report *fsnotify_data_error_report(
387419
const void *data,
388420
int data_type)
@@ -420,6 +452,7 @@ enum fsnotify_iter_type {
420452
FSNOTIFY_ITER_TYPE_SB,
421453
FSNOTIFY_ITER_TYPE_PARENT,
422454
FSNOTIFY_ITER_TYPE_INODE2,
455+
FSNOTIFY_ITER_TYPE_MNTNS,
423456
FSNOTIFY_ITER_TYPE_COUNT
424457
};
425458

@@ -429,6 +462,7 @@ enum fsnotify_obj_type {
429462
FSNOTIFY_OBJ_TYPE_INODE,
430463
FSNOTIFY_OBJ_TYPE_VFSMOUNT,
431464
FSNOTIFY_OBJ_TYPE_SB,
465+
FSNOTIFY_OBJ_TYPE_MNTNS,
432466
FSNOTIFY_OBJ_TYPE_COUNT,
433467
FSNOTIFY_OBJ_TYPE_DETACHED = FSNOTIFY_OBJ_TYPE_COUNT
434468
};
@@ -613,8 +647,10 @@ extern int __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data
613647
extern void __fsnotify_inode_delete(struct inode *inode);
614648
extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt);
615649
extern void fsnotify_sb_delete(struct super_block *sb);
650+
extern void __fsnotify_mntns_delete(struct mnt_namespace *mntns);
616651
extern void fsnotify_sb_free(struct super_block *sb);
617652
extern u32 fsnotify_get_cookie(void);
653+
extern void fsnotify_mnt(__u32 mask, struct mnt_namespace *ns, struct vfsmount *mnt);
618654

619655
static inline __u32 fsnotify_parent_needed_mask(__u32 mask)
620656
{
@@ -928,6 +964,9 @@ static inline void __fsnotify_vfsmount_delete(struct vfsmount *mnt)
928964
static inline void fsnotify_sb_delete(struct super_block *sb)
929965
{}
930966

967+
static inline void __fsnotify_mntns_delete(struct mnt_namespace *mntns)
968+
{}
969+
931970
static inline void fsnotify_sb_free(struct super_block *sb)
932971
{}
933972

@@ -942,6 +981,9 @@ static inline u32 fsnotify_get_cookie(void)
942981
static inline void fsnotify_unmount_inodes(struct super_block *sb)
943982
{}
944983

984+
static inline void fsnotify_mnt(__u32 mask, struct mnt_namespace *ns, struct vfsmount *mnt)
985+
{}
986+
945987
#endif /* CONFIG_FSNOTIFY */
946988

947989
#endif /* __KERNEL __ */

0 commit comments

Comments
 (0)