From fb5f51c7425ebc808d91329257cbc963e2421368 Mon Sep 17 00:00:00 2001 From: Ian Kent Date: Thu, 24 Nov 2016 08:03:41 +1100 Subject: vfs: change d_manage() to take a struct path For the autofs module to be able to reliably check if a dentry is a mountpoint in a multiple namespace environment the ->d_manage() dentry operation will need to take a path argument instead of a dentry. Link: http://lkml.kernel.org/r/20161011053352.27645.83962.stgit@pluto.themaw.net Signed-off-by: Ian Kent Cc: Al Viro Cc: Eric W. Biederman Cc: Omar Sandoval Signed-off-by: Andrew Morton Signed-off-by: Al Viro --- include/linux/dcache.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux/dcache.h') diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 5beed7b30561..bc529ce88ed0 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -139,7 +139,7 @@ struct dentry_operations { void (*d_iput)(struct dentry *, struct inode *); char *(*d_dname)(struct dentry *, char *, int); struct vfsmount *(*d_automount)(struct path *); - int (*d_manage)(struct dentry *, bool); + int (*d_manage)(const struct path *, bool); struct dentry *(*d_real)(struct dentry *, const struct inode *, unsigned int); } ____cacheline_aligned; -- cgit v1.2.3-55-g7522 From 01619491a5f0766014fe863c5ae480665436e7a2 Mon Sep 17 00:00:00 2001 From: Ian Kent Date: Thu, 24 Nov 2016 08:03:41 +1100 Subject: vfs: add path_has_submounts() d_mountpoint() can only be used reliably to establish if a dentry is not mounted in any namespace. It isn't aware of the possibility there may be multiple mounts using the given dentry, possibly in a different namespace. Add function, path_has_submounts(), that checks is a struct path contains mounts (or is a mountpoint itself) to handle this case. Link: http://lkml.kernel.org/r/20161011053403.27645.55242.stgit@pluto.themaw.net Signed-off-by: Ian Kent Cc: Al Viro Cc: Eric W. Biederman Cc: Omar Sandoval Signed-off-by: Andrew Morton Signed-off-by: Al Viro --- fs/dcache.c | 39 +++++++++++++++++++++++++++++++++++++++ include/linux/dcache.h | 1 + 2 files changed, 40 insertions(+) (limited to 'include/linux/dcache.h') diff --git a/fs/dcache.c b/fs/dcache.c index 5c7cc953ac81..8515875854b6 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1306,6 +1306,45 @@ int have_submounts(struct dentry *parent) } EXPORT_SYMBOL(have_submounts); +struct check_mount { + struct vfsmount *mnt; + unsigned int mounted; +}; + +static enum d_walk_ret path_check_mount(void *data, struct dentry *dentry) +{ + struct check_mount *info = data; + struct path path = { .mnt = info->mnt, .dentry = dentry }; + + if (likely(!d_mountpoint(dentry))) + return D_WALK_CONTINUE; + if (__path_is_mountpoint(&path)) { + info->mounted = 1; + return D_WALK_QUIT; + } + return D_WALK_CONTINUE; +} + +/** + * path_has_submounts - check for mounts over a dentry in the + * current namespace. + * @parent: path to check. + * + * Return true if the parent or its subdirectories contain + * a mount point in the current namespace. + */ +int path_has_submounts(const struct path *parent) +{ + struct check_mount data = { .mnt = parent->mnt, .mounted = 0 }; + + read_seqlock_excl(&mount_lock); + d_walk(parent->dentry, &data, path_check_mount, NULL); + read_sequnlock_excl(&mount_lock); + + return data.mounted; +} +EXPORT_SYMBOL(path_has_submounts); + /* * Called by mount code to set a mountpoint and check if the mountpoint is * reachable (e.g. NFS can unhash a directory dentry and then the complete diff --git a/include/linux/dcache.h b/include/linux/dcache.h index bc529ce88ed0..0ffaf7aef9ae 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -255,6 +255,7 @@ extern void d_prune_aliases(struct inode *); /* test whether we have any submounts in a subdir tree */ extern int have_submounts(struct dentry *); +extern int path_has_submounts(const struct path *); /* * This adds the entry to the hash queues. -- cgit v1.2.3-55-g7522 From f74e7b33c37e5a7bae33bb73858c2766cb256626 Mon Sep 17 00:00:00 2001 From: Ian Kent Date: Thu, 24 Nov 2016 08:03:42 +1100 Subject: vfs: remove unused have_submounts() function Now that path_has_submounts() has been added have_submounts() is no longer used so remove it. Link: http://lkml.kernel.org/r/20161011053428.27645.12310.stgit@pluto.themaw.net Signed-off-by: Ian Kent Cc: Al Viro Cc: Eric W. Biederman Cc: Omar Sandoval Signed-off-by: Andrew Morton Signed-off-by: Al Viro --- fs/dcache.c | 33 --------------------------------- include/linux/dcache.h | 1 - 2 files changed, 34 deletions(-) (limited to 'include/linux/dcache.h') diff --git a/fs/dcache.c b/fs/dcache.c index 8515875854b6..252378359a8f 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1273,39 +1273,6 @@ rename_retry: goto again; } -/* - * Search for at least 1 mount point in the dentry's subdirs. - * We descend to the next level whenever the d_subdirs - * list is non-empty and continue searching. - */ - -static enum d_walk_ret check_mount(void *data, struct dentry *dentry) -{ - int *ret = data; - if (d_mountpoint(dentry)) { - *ret = 1; - return D_WALK_QUIT; - } - return D_WALK_CONTINUE; -} - -/** - * have_submounts - check for mounts over a dentry - * @parent: dentry to check. - * - * Return true if the parent or its subdirectories contain - * a mount point - */ -int have_submounts(struct dentry *parent) -{ - int ret = 0; - - d_walk(parent, &ret, check_mount, NULL); - - return ret; -} -EXPORT_SYMBOL(have_submounts); - struct check_mount { struct vfsmount *mnt; unsigned int mounted; diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 0ffaf7aef9ae..c965e4469499 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -254,7 +254,6 @@ extern struct dentry *d_find_alias(struct inode *); extern void d_prune_aliases(struct inode *); /* test whether we have any submounts in a subdir tree */ -extern int have_submounts(struct dentry *); extern int path_has_submounts(const struct path *); /* -- cgit v1.2.3-55-g7522