On Wed 29-01-25 17:57:59, Miklos Szeredi wrote: > 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@xxxxxxxxxx> Looks good to me. Feel free to add: Reviewed-by: Jan Kara <jack@xxxxxxx> Honza > --- > fs/mount.h | 4 +++ > fs/notify/fsnotify.c | 47 +++++++++++++++++++++++++++----- > fs/notify/fsnotify.h | 11 ++++++++ > fs/notify/mark.c | 14 ++++++++-- > include/linux/fsnotify.h | 20 ++++++++++++++ > include/linux/fsnotify_backend.h | 42 ++++++++++++++++++++++++++++ > 6 files changed, 128 insertions(+), 10 deletions(-) > > diff --git a/fs/mount.h b/fs/mount.h > index ffb613cdfeee..82aa3bad7cf5 100644 > --- a/fs/mount.h > +++ b/fs/mount.h > @@ -21,6 +21,10 @@ struct mnt_namespace { > struct rcu_head mnt_ns_rcu; > }; > u64 event; > +#ifdef CONFIG_FSNOTIFY > + __u32 n_fsnotify_mask; > + struct fsnotify_mark_connector __rcu *n_fsnotify_marks; > +#endif > unsigned int nr_mounts; /* # of mounts in the namespace */ > unsigned int pending_mounts; > struct rb_node mnt_ns_tree_node; /* node in the mnt_ns_tree */ > diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c > index 8ee495a58d0a..c64b95cf50c7 100644 > --- a/fs/notify/fsnotify.c > +++ b/fs/notify/fsnotify.c > @@ -28,6 +28,11 @@ void __fsnotify_vfsmount_delete(struct vfsmount *mnt) > fsnotify_clear_marks_by_mount(mnt); > } > > +void __fsnotify_mntns_delete(struct mnt_namespace *mntns) > +{ > + fsnotify_clear_marks_by_mntns(mntns); > +} > + > /** > * fsnotify_unmount_inodes - an sb is unmounting. handle any watched inodes. > * @sb: superblock being unmounted. > @@ -420,7 +425,7 @@ static int send_to_group(__u32 mask, const void *data, int data_type, > file_name, cookie, iter_info); > } > > -static struct fsnotify_mark *fsnotify_first_mark(struct fsnotify_mark_connector **connp) > +static struct fsnotify_mark *fsnotify_first_mark(struct fsnotify_mark_connector *const *connp) > { > struct fsnotify_mark_connector *conn; > struct hlist_node *node = NULL; > @@ -538,14 +543,15 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir, > { > const struct path *path = fsnotify_data_path(data, data_type); > struct super_block *sb = fsnotify_data_sb(data, data_type); > - struct fsnotify_sb_info *sbinfo = fsnotify_sb_info(sb); > + const struct fsnotify_mnt *mnt_data = fsnotify_data_mnt(data, data_type); > + struct fsnotify_sb_info *sbinfo = sb ? fsnotify_sb_info(sb) : NULL; > struct fsnotify_iter_info iter_info = {}; > struct mount *mnt = NULL; > struct inode *inode2 = NULL; > struct dentry *moved; > int inode2_type; > int ret = 0; > - __u32 test_mask, marks_mask; > + __u32 test_mask, marks_mask = 0; > > if (path) > mnt = real_mount(path->mnt); > @@ -578,17 +584,20 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir, > if ((!sbinfo || !sbinfo->sb_marks) && > (!mnt || !mnt->mnt_fsnotify_marks) && > (!inode || !inode->i_fsnotify_marks) && > - (!inode2 || !inode2->i_fsnotify_marks)) > + (!inode2 || !inode2->i_fsnotify_marks) && > + (!mnt_data || !mnt_data->ns->n_fsnotify_marks)) > return 0; > > - marks_mask = READ_ONCE(sb->s_fsnotify_mask); > + if (sb) > + marks_mask |= READ_ONCE(sb->s_fsnotify_mask); > if (mnt) > marks_mask |= READ_ONCE(mnt->mnt_fsnotify_mask); > if (inode) > marks_mask |= READ_ONCE(inode->i_fsnotify_mask); > if (inode2) > marks_mask |= READ_ONCE(inode2->i_fsnotify_mask); > - > + if (mnt_data) > + marks_mask |= READ_ONCE(mnt_data->ns->n_fsnotify_mask); > > /* > * 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, > iter_info.marks[inode2_type] = > fsnotify_first_mark(&inode2->i_fsnotify_marks); > } > + if (mnt_data) { > + iter_info.marks[FSNOTIFY_ITER_TYPE_MNTNS] = > + fsnotify_first_mark(&mnt_data->ns->n_fsnotify_marks); > + } > > /* > * 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) > } > #endif > > +void fsnotify_mnt(__u32 mask, struct mnt_namespace *ns, struct vfsmount *mnt) > +{ > + struct fsnotify_mnt data = { > + .ns = ns, > + .mnt_id = real_mount(mnt)->mnt_id_unique, > + }; > + > + if (WARN_ON_ONCE(!ns)) > + return; > + > + /* > + * This is an optimization as well as making sure fsnotify_init() has > + * been called. > + */ > + if (!ns->n_fsnotify_marks) > + return; > + > + fsnotify(mask, &data, FSNOTIFY_EVENT_MNT, NULL, NULL, NULL, 0); > +} > + > static __init int fsnotify_init(void) > { > int ret; > > - BUILD_BUG_ON(HWEIGHT32(ALL_FSNOTIFY_BITS) != 24); > + BUILD_BUG_ON(HWEIGHT32(ALL_FSNOTIFY_BITS) != 26); > > ret = init_srcu_struct(&fsnotify_mark_srcu); > if (ret) > diff --git a/fs/notify/fsnotify.h b/fs/notify/fsnotify.h > index 663759ed6fbc..5950c7a67f41 100644 > --- a/fs/notify/fsnotify.h > +++ b/fs/notify/fsnotify.h > @@ -33,6 +33,12 @@ static inline struct super_block *fsnotify_conn_sb( > return conn->obj; > } > > +static inline struct mnt_namespace *fsnotify_conn_mntns( > + struct fsnotify_mark_connector *conn) > +{ > + return conn->obj; > +} > + > static inline struct super_block *fsnotify_object_sb(void *obj, > enum fsnotify_obj_type obj_type) > { > @@ -89,6 +95,11 @@ static inline void fsnotify_clear_marks_by_sb(struct super_block *sb) > fsnotify_destroy_marks(fsnotify_sb_marks(sb)); > } > > +static inline void fsnotify_clear_marks_by_mntns(struct mnt_namespace *mntns) > +{ > + fsnotify_destroy_marks(&mntns->n_fsnotify_marks); > +} > + > /* > * update the dentry->d_flags of all of inode's children to indicate if inode cares > * about events that happen to its children. > diff --git a/fs/notify/mark.c b/fs/notify/mark.c > index 4981439e6209..798340db69d7 100644 > --- a/fs/notify/mark.c > +++ b/fs/notify/mark.c > @@ -107,6 +107,8 @@ static fsnotify_connp_t *fsnotify_object_connp(void *obj, > return &real_mount(obj)->mnt_fsnotify_marks; > case FSNOTIFY_OBJ_TYPE_SB: > return fsnotify_sb_marks(obj); > + case FSNOTIFY_OBJ_TYPE_MNTNS: > + return &((struct mnt_namespace *)obj)->n_fsnotify_marks; > default: > return NULL; > } > @@ -120,6 +122,8 @@ static __u32 *fsnotify_conn_mask_p(struct fsnotify_mark_connector *conn) > return &fsnotify_conn_mount(conn)->mnt_fsnotify_mask; > else if (conn->type == FSNOTIFY_OBJ_TYPE_SB) > return &fsnotify_conn_sb(conn)->s_fsnotify_mask; > + else if (conn->type == FSNOTIFY_OBJ_TYPE_MNTNS) > + return &fsnotify_conn_mntns(conn)->n_fsnotify_mask; > return NULL; > } > > @@ -346,12 +350,15 @@ static void *fsnotify_detach_connector_from_object( > fsnotify_conn_mount(conn)->mnt_fsnotify_mask = 0; > } else if (conn->type == FSNOTIFY_OBJ_TYPE_SB) { > fsnotify_conn_sb(conn)->s_fsnotify_mask = 0; > + } else if (conn->type == FSNOTIFY_OBJ_TYPE_MNTNS) { > + fsnotify_conn_mntns(conn)->n_fsnotify_mask = 0; > } > > rcu_assign_pointer(*connp, NULL); > conn->obj = NULL; > conn->type = FSNOTIFY_OBJ_TYPE_DETACHED; > - fsnotify_update_sb_watchers(sb, conn); > + if (sb) > + fsnotify_update_sb_watchers(sb, conn); > > return inode; > } > @@ -724,7 +731,7 @@ static int fsnotify_add_mark_list(struct fsnotify_mark *mark, void *obj, > * Attach the sb info before attaching a connector to any object on sb. > * The sb info will remain attached as long as sb lives. > */ > - if (!fsnotify_sb_info(sb)) { > + if (sb && !fsnotify_sb_info(sb)) { > err = fsnotify_attach_info_to_sb(sb); > if (err) > return err; > @@ -770,7 +777,8 @@ static int fsnotify_add_mark_list(struct fsnotify_mark *mark, void *obj, > /* mark should be the last entry. last is the current last entry */ > hlist_add_behind_rcu(&mark->obj_list, &last->obj_list); > added: > - fsnotify_update_sb_watchers(sb, conn); > + if (sb) > + fsnotify_update_sb_watchers(sb, conn); > /* > * Since connector is attached to object using cmpxchg() we are > * guaranteed that connector initialization is fully visible by anyone > diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h > index 1a9ef8f6784d..589e274adc7d 100644 > --- a/include/linux/fsnotify.h > +++ b/include/linux/fsnotify.h > @@ -299,6 +299,11 @@ static inline void fsnotify_vfsmount_delete(struct vfsmount *mnt) > __fsnotify_vfsmount_delete(mnt); > } > > +static inline void fsnotify_mntns_delete(struct mnt_namespace *mntns) > +{ > + __fsnotify_mntns_delete(mntns); > +} > + > /* > * fsnotify_inoderemove - an inode is going away > */ > @@ -507,4 +512,19 @@ static inline int fsnotify_sb_error(struct super_block *sb, struct inode *inode, > NULL, NULL, NULL, 0); > } > > +static inline void fsnotify_mnt_attach(struct mnt_namespace *ns, struct vfsmount *mnt) > +{ > + fsnotify_mnt(FS_MNT_ATTACH, ns, mnt); > +} > + > +static inline void fsnotify_mnt_detach(struct mnt_namespace *ns, struct vfsmount *mnt) > +{ > + fsnotify_mnt(FS_MNT_DETACH, ns, mnt); > +} > + > +static inline void fsnotify_mnt_move(struct mnt_namespace *ns, struct vfsmount *mnt) > +{ > + fsnotify_mnt(FS_MNT_MOVE, ns, mnt); > +} > + > #endif /* _LINUX_FS_NOTIFY_H */ > diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h > index 0d24a21a8e60..6cd8d1d28b8b 100644 > --- a/include/linux/fsnotify_backend.h > +++ b/include/linux/fsnotify_backend.h > @@ -59,6 +59,10 @@ > > #define FS_PRE_ACCESS 0x00100000 /* Pre-content access hook */ > > +#define FS_MNT_ATTACH 0x01000000 /* Mount was attached */ > +#define FS_MNT_DETACH 0x02000000 /* Mount was detached */ > +#define FS_MNT_MOVE (FS_MNT_ATTACH | FS_MNT_DETACH) > + > /* > * Set on inode mark that cares about things that happen to its children. > * Always set for dnotify and inotify. > @@ -80,6 +84,9 @@ > */ > #define ALL_FSNOTIFY_DIRENT_EVENTS (FS_CREATE | FS_DELETE | FS_MOVE | FS_RENAME) > > +/* Mount namespace events */ > +#define FSNOTIFY_MNT_EVENTS (FS_MNT_ATTACH | FS_MNT_DETACH) > + > /* Content events can be used to inspect file content */ > #define FSNOTIFY_CONTENT_PERM_EVENTS (FS_OPEN_PERM | FS_OPEN_EXEC_PERM | \ > FS_ACCESS_PERM) > @@ -108,6 +115,7 @@ > > /* Events that can be reported to backends */ > #define ALL_FSNOTIFY_EVENTS (ALL_FSNOTIFY_DIRENT_EVENTS | \ > + FSNOTIFY_MNT_EVENTS | \ > FS_EVENTS_POSS_ON_CHILD | \ > FS_DELETE_SELF | FS_MOVE_SELF | \ > FS_UNMOUNT | FS_Q_OVERFLOW | FS_IN_IGNORED | \ > @@ -298,6 +306,7 @@ enum fsnotify_data_type { > FSNOTIFY_EVENT_PATH, > FSNOTIFY_EVENT_INODE, > FSNOTIFY_EVENT_DENTRY, > + FSNOTIFY_EVENT_MNT, > FSNOTIFY_EVENT_ERROR, > }; > > @@ -318,6 +327,11 @@ static inline const struct path *file_range_path(const struct file_range *range) > return range->path; > } > > +struct fsnotify_mnt { > + const struct mnt_namespace *ns; > + u64 mnt_id; > +}; > + > static inline struct inode *fsnotify_data_inode(const void *data, int data_type) > { > switch (data_type) { > @@ -383,6 +397,24 @@ static inline struct super_block *fsnotify_data_sb(const void *data, > } > } > > +static inline const struct fsnotify_mnt *fsnotify_data_mnt(const void *data, > + int data_type) > +{ > + switch (data_type) { > + case FSNOTIFY_EVENT_MNT: > + return data; > + default: > + return NULL; > + } > +} > + > +static inline u64 fsnotify_data_mnt_id(const void *data, int data_type) > +{ > + const struct fsnotify_mnt *mnt_data = fsnotify_data_mnt(data, data_type); > + > + return mnt_data ? mnt_data->mnt_id : 0; > +} > + > static inline struct fs_error_report *fsnotify_data_error_report( > const void *data, > int data_type) > @@ -420,6 +452,7 @@ enum fsnotify_iter_type { > FSNOTIFY_ITER_TYPE_SB, > FSNOTIFY_ITER_TYPE_PARENT, > FSNOTIFY_ITER_TYPE_INODE2, > + FSNOTIFY_ITER_TYPE_MNTNS, > FSNOTIFY_ITER_TYPE_COUNT > }; > > @@ -429,6 +462,7 @@ enum fsnotify_obj_type { > FSNOTIFY_OBJ_TYPE_INODE, > FSNOTIFY_OBJ_TYPE_VFSMOUNT, > FSNOTIFY_OBJ_TYPE_SB, > + FSNOTIFY_OBJ_TYPE_MNTNS, > FSNOTIFY_OBJ_TYPE_COUNT, > FSNOTIFY_OBJ_TYPE_DETACHED = FSNOTIFY_OBJ_TYPE_COUNT > }; > @@ -613,8 +647,10 @@ extern int __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data > extern void __fsnotify_inode_delete(struct inode *inode); > extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt); > extern void fsnotify_sb_delete(struct super_block *sb); > +extern void __fsnotify_mntns_delete(struct mnt_namespace *mntns); > extern void fsnotify_sb_free(struct super_block *sb); > extern u32 fsnotify_get_cookie(void); > +extern void fsnotify_mnt(__u32 mask, struct mnt_namespace *ns, struct vfsmount *mnt); > > static inline __u32 fsnotify_parent_needed_mask(__u32 mask) > { > @@ -928,6 +964,9 @@ static inline void __fsnotify_vfsmount_delete(struct vfsmount *mnt) > static inline void fsnotify_sb_delete(struct super_block *sb) > {} > > +static inline void __fsnotify_mntns_delete(struct mnt_namespace *mntns) > +{} > + > static inline void fsnotify_sb_free(struct super_block *sb) > {} > > @@ -942,6 +981,9 @@ static inline u32 fsnotify_get_cookie(void) > static inline void fsnotify_unmount_inodes(struct super_block *sb) > {} > > +static inline void fsnotify_mnt(__u32 mask, struct mnt_namespace *ns, struct vfsmount *mnt) > +{} > + > #endif /* CONFIG_FSNOTIFY */ > > #endif /* __KERNEL __ */ > -- > 2.48.1 > -- Jan Kara <jack@xxxxxxxx> SUSE Labs, CR