On Wed 29-01-25 17:58:01, Miklos Szeredi wrote: > Add notifications for attaching and detaching mounts to fs/namespace.c > > 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 | 20 +++++++++++++ > fs/namespace.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++- > fs/pnode.c | 4 ++- > 3 files changed, 101 insertions(+), 2 deletions(-) > > diff --git a/fs/mount.h b/fs/mount.h > index 5324a931b403..946dc8b792d7 100644 > --- a/fs/mount.h > +++ b/fs/mount.h > @@ -5,6 +5,8 @@ > #include <linux/ns_common.h> > #include <linux/fs_pin.h> > > +extern struct list_head notify_list; > + > struct mnt_namespace { > struct ns_common ns; > struct mount * root; > @@ -80,6 +82,8 @@ struct mount { > #ifdef CONFIG_FSNOTIFY > struct fsnotify_mark_connector __rcu *mnt_fsnotify_marks; > __u32 mnt_fsnotify_mask; > + struct list_head to_notify; /* need to queue notification */ > + struct mnt_namespace *prev_ns; /* previous namespace (NULL if none) */ > #endif > int mnt_id; /* mount identifier, reused */ > u64 mnt_id_unique; /* mount ID unique until reboot */ > @@ -182,4 +186,20 @@ static inline struct mnt_namespace *to_mnt_ns(struct ns_common *ns) > return container_of(ns, struct mnt_namespace, ns); > } > > +#ifdef CONFIG_FSNOTIFY > +static inline void mnt_notify_add(struct mount *m) > +{ > + /* Optimize the case where there are no watches */ > + if ((m->mnt_ns && m->mnt_ns->n_fsnotify_marks) || > + (m->prev_ns && m->prev_ns->n_fsnotify_marks)) > + list_add_tail(&m->to_notify, ¬ify_list); > + else > + m->prev_ns = m->mnt_ns; > +} > +#else > +static inline void mnt_notify_add(struct mount *m) > +{ > +} > +#endif > + > struct mnt_namespace *mnt_ns_from_dentry(struct dentry *dentry); > diff --git a/fs/namespace.c b/fs/namespace.c > index d8d70da56e7b..1e964b646509 100644 > --- a/fs/namespace.c > +++ b/fs/namespace.c > @@ -81,6 +81,9 @@ static HLIST_HEAD(unmounted); /* protected by namespace_sem */ > static LIST_HEAD(ex_mountpoints); /* protected by namespace_sem */ > static DEFINE_SEQLOCK(mnt_ns_tree_lock); > > +#ifdef CONFIG_FSNOTIFY > +LIST_HEAD(notify_list); /* protected by namespace_sem */ > +#endif > static struct rb_root mnt_ns_tree = RB_ROOT; /* protected by mnt_ns_tree_lock */ > static LIST_HEAD(mnt_ns_list); /* protected by mnt_ns_tree_lock */ > > @@ -163,6 +166,7 @@ static void mnt_ns_release(struct mnt_namespace *ns) > { > /* keep alive for {list,stat}mount() */ > if (refcount_dec_and_test(&ns->passive)) { > + fsnotify_mntns_delete(ns); > put_user_ns(ns->user_ns); > kfree(ns); > } > @@ -1176,6 +1180,8 @@ static void mnt_add_to_ns(struct mnt_namespace *ns, struct mount *mnt) > ns->mnt_first_node = &mnt->mnt_node; > rb_link_node(&mnt->mnt_node, parent, link); > rb_insert_color(&mnt->mnt_node, &ns->mounts); > + > + mnt_notify_add(mnt); > } > > /* > @@ -1723,6 +1729,50 @@ int may_umount(struct vfsmount *mnt) > > EXPORT_SYMBOL(may_umount); > > +#ifdef CONFIG_FSNOTIFY > +static void mnt_notify(struct mount *p) > +{ > + if (!p->prev_ns && p->mnt_ns) { > + fsnotify_mnt_attach(p->mnt_ns, &p->mnt); > + } else if (p->prev_ns && !p->mnt_ns) { > + fsnotify_mnt_detach(p->prev_ns, &p->mnt); > + } else if (p->prev_ns == p->mnt_ns) { > + fsnotify_mnt_move(p->mnt_ns, &p->mnt); > + } else { > + fsnotify_mnt_detach(p->prev_ns, &p->mnt); > + fsnotify_mnt_attach(p->mnt_ns, &p->mnt); > + } > + p->prev_ns = p->mnt_ns; > +} > + > +static void notify_mnt_list(void) > +{ > + struct mount *m, *tmp; > + /* > + * Notify about mounts that were added/reparented/detached/remain > + * connected after unmount. > + */ > + list_for_each_entry_safe(m, tmp, ¬ify_list, to_notify) { > + mnt_notify(m); > + list_del_init(&m->to_notify); > + } > +} > + > +static bool need_notify_mnt_list(void) > +{ > + return !list_empty(¬ify_list); > +} > +#else > +static void notify_mnt_list(void) > +{ > +} > + > +static bool need_notify_mnt_list(void) > +{ > + return false; > +} > +#endif > + > static void namespace_unlock(void) > { > struct hlist_head head; > @@ -1733,7 +1783,18 @@ static void namespace_unlock(void) > hlist_move_list(&unmounted, &head); > list_splice_init(&ex_mountpoints, &list); > > - up_write(&namespace_sem); > + if (need_notify_mnt_list()) { > + /* > + * No point blocking out concurrent readers while notifications > + * are sent. This will also allow statmount()/listmount() to run > + * concurrently. > + */ > + downgrade_write(&namespace_sem); > + notify_mnt_list(); > + up_read(&namespace_sem); > + } else { > + up_write(&namespace_sem); > + } > > shrink_dentry_list(&list); > > @@ -1846,6 +1907,19 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how) > change_mnt_propagation(p, MS_PRIVATE); > if (disconnect) > hlist_add_head(&p->mnt_umount, &unmounted); > + > + /* > + * At this point p->mnt_ns is NULL, notification will be queued > + * only if > + * > + * - p->prev_ns is non-NULL *and* > + * - p->prev_ns->n_fsnotify_marks is non-NULL > + * > + * This will preclude queuing the mount if this is a cleanup > + * after a failed copy_tree() or destruction of an anonymous > + * namespace, etc. > + */ > + mnt_notify_add(p); > } > } > > @@ -2555,6 +2629,7 @@ static int attach_recursive_mnt(struct mount *source_mnt, > dest_mp = smp; > unhash_mnt(source_mnt); > attach_mnt(source_mnt, top_mnt, dest_mp, beneath); > + mnt_notify_add(source_mnt); > touch_mnt_namespace(source_mnt->mnt_ns); > } else { > if (source_mnt->mnt_ns) { > @@ -4476,6 +4551,8 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, > list_del_init(&new_mnt->mnt_expire); > put_mountpoint(root_mp); > unlock_mount_hash(); > + mnt_notify_add(root_mnt); > + mnt_notify_add(new_mnt); > chroot_fs_refs(&root, &new); > error = 0; > out4: > diff --git a/fs/pnode.c b/fs/pnode.c > index ef048f008bdd..82d809c785ec 100644 > --- a/fs/pnode.c > +++ b/fs/pnode.c > @@ -549,8 +549,10 @@ static void restore_mounts(struct list_head *to_restore) > mp = parent->mnt_mp; > parent = parent->mnt_parent; > } > - if (parent != mnt->mnt_parent) > + if (parent != mnt->mnt_parent) { > mnt_change_mountpoint(parent, mp, mnt); > + mnt_notify_add(mnt); > + } > } > } > > -- > 2.48.1 > -- Jan Kara <jack@xxxxxxxx> SUSE Labs, CR