diff options
author | Ian Kent <ikent@redhat.com> | 2016-11-23 16:03:41 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2016-12-03 20:51:47 -0500 |
commit | 01619491a5f0766014fe863c5ae480665436e7a2 (patch) | |
tree | e9f8f4fcf30337b805c76f8fcc83baa517779359 /fs/dcache.c | |
parent | c6609c0a1c34fc097152b28b496236625673924f (diff) |
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 <raven@themaw.net>
Cc: Al Viro <viro@ZenIV.linux.org.uk>
Cc: Eric W. Biederman <ebiederm@xmission.com>
Cc: Omar Sandoval <osandov@osandov.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/dcache.c')
-rw-r--r-- | fs/dcache.c | 39 |
1 files changed, 39 insertions, 0 deletions
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) | |||
1306 | } | 1306 | } |
1307 | EXPORT_SYMBOL(have_submounts); | 1307 | EXPORT_SYMBOL(have_submounts); |
1308 | 1308 | ||
1309 | struct check_mount { | ||
1310 | struct vfsmount *mnt; | ||
1311 | unsigned int mounted; | ||
1312 | }; | ||
1313 | |||
1314 | static enum d_walk_ret path_check_mount(void *data, struct dentry *dentry) | ||
1315 | { | ||
1316 | struct check_mount *info = data; | ||
1317 | struct path path = { .mnt = info->mnt, .dentry = dentry }; | ||
1318 | |||
1319 | if (likely(!d_mountpoint(dentry))) | ||
1320 | return D_WALK_CONTINUE; | ||
1321 | if (__path_is_mountpoint(&path)) { | ||
1322 | info->mounted = 1; | ||
1323 | return D_WALK_QUIT; | ||
1324 | } | ||
1325 | return D_WALK_CONTINUE; | ||
1326 | } | ||
1327 | |||
1328 | /** | ||
1329 | * path_has_submounts - check for mounts over a dentry in the | ||
1330 | * current namespace. | ||
1331 | * @parent: path to check. | ||
1332 | * | ||
1333 | * Return true if the parent or its subdirectories contain | ||
1334 | * a mount point in the current namespace. | ||
1335 | */ | ||
1336 | int path_has_submounts(const struct path *parent) | ||
1337 | { | ||
1338 | struct check_mount data = { .mnt = parent->mnt, .mounted = 0 }; | ||
1339 | |||
1340 | read_seqlock_excl(&mount_lock); | ||
1341 | d_walk(parent->dentry, &data, path_check_mount, NULL); | ||
1342 | read_sequnlock_excl(&mount_lock); | ||
1343 | |||
1344 | return data.mounted; | ||
1345 | } | ||
1346 | EXPORT_SYMBOL(path_has_submounts); | ||
1347 | |||
1309 | /* | 1348 | /* |
1310 | * Called by mount code to set a mountpoint and check if the mountpoint is | 1349 | * Called by mount code to set a mountpoint and check if the mountpoint is |
1311 | * reachable (e.g. NFS can unhash a directory dentry and then the complete | 1350 | * reachable (e.g. NFS can unhash a directory dentry and then the complete |