Re: [PATCH v5 3/3] vfs: add notifications for mount attach and detach

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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, &notify_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, &notify_list, to_notify) {
> +		mnt_notify(m);
> +		list_del_init(&m->to_notify);
> +	}
> +}
> +
> +static bool need_notify_mnt_list(void)
> +{
> +	return !list_empty(&notify_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




[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [NTFS 3]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [NTFS 3]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux