This patch introduces the concept of an "internal" mount which is a mount where a filesystem has create the mount itself. Both the mounted-on-dentry and the mount's root dentry must refer to the same superblock (they may be the same dentry), and the mounted-on dentry must be an automount. Signed-off-by: NeilBrown <neilb@xxxxxxx> --- fs/namespace.c | 29 +++++++++++++++++++++++++++++ include/linux/mount.h | 2 ++ 2 files changed, 31 insertions(+) diff --git a/fs/namespace.c b/fs/namespace.c index 73bbdb921e24..a14efbccfb03 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1273,6 +1273,35 @@ bool path_is_mountpoint(const struct path *path) } EXPORT_SYMBOL(path_is_mountpoint); +/** + * mount_is_internal() - Check if path is a mount internal to a single filesystem + * @mnt: vfsmount to check + * + * Some filesystems present multiple file-sets using a single + * superblock, such as btrfs with multiple subvolumes. Names within a + * parent filesystem which lead to a subordinate filesystem are + * implemented as automounts so that the structure is visible in the + * mount table. nfsd needs visibility into this arrangement so that it + * can determine if a mountpoint requires a new export, or is completely + * covered by an existing mount. + * + * An "internal" mount is one where the parent and child have the same + * superblock, and the mounted-on dentry is "managed" as an automount. A + * filehandle found for an inode in the child can be looked-up using either + * vfsmount. + */ +bool mount_is_internal(struct vfsmount *mnt) +{ + struct mount *m = real_mount(mnt); + + if (!mnt_has_parent(m)) + return false; + if (m->mnt_parent->mnt.mnt_sb != m->mnt.mnt_sb) + return false; + return m->mnt_mountpoint->d_flags & DCACHE_NEED_AUTOMOUNT; +} +EXPORT_SYMBOL(mount_is_internal); + struct vfsmount *mnt_clone_internal(const struct path *path) { struct mount *p; diff --git a/include/linux/mount.h b/include/linux/mount.h index 1d3daed88f83..ab58087728ba 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h @@ -118,6 +118,8 @@ extern unsigned int sysctl_mount_max; extern bool path_is_mountpoint(const struct path *path); +extern bool mount_is_internal(struct vfsmount *mnt); + extern struct vfsmount *lookup_mnt(const struct path *); extern void kern_unmount_array(struct vfsmount *mnt[], unsigned int num);