aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namespace.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2025-08-22 12:59:10 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2025-09-02 19:35:59 -0400
commit9bf5d488529b9efa01bd292633482acd10277b90 (patch)
treeaa945a59dfda9975b82f11be735088bf54b1db82 /fs/namespace.c
parent6bbbc4a04a10ebdb633501dc87aac5b0d6b80ec8 (diff)
downloadrandom-9bf5d488529b9efa01bd292633482acd10277b90.tar.gz
finish_automount(): take the lock_mount() analogue into a helper
finish_automount() can't use lock_mount() - it treats finding something already mounted as "quitely drop our mount and return 0", not as "mount on top of whatever mounted there". It's been open-coded; let's take it into a helper similar to lock_mount(). "something's already mounted" => -EBUSY, finish_automount() needs to distinguish it from the normal case and it can't happen in other failure cases. Reviewed-by: Christian Brauner <brauner@kernel.org> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namespace.c')
-rw-r--r--fs/namespace.c42
1 files changed, 25 insertions, 17 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index 90b62ee882da06..6251ee15f5f65a 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -3781,9 +3781,29 @@ static int do_new_mount(struct path *path, const char *fstype, int sb_flags,
return err;
}
-int finish_automount(struct vfsmount *m, const struct path *path)
+static int lock_mount_exact(const struct path *path,
+ struct pinned_mountpoint *mp)
{
struct dentry *dentry = path->dentry;
+ int err;
+
+ inode_lock(dentry->d_inode);
+ namespace_lock();
+ if (unlikely(cant_mount(dentry)))
+ err = -ENOENT;
+ else if (path_overmounted(path))
+ err = -EBUSY;
+ else
+ err = get_mountpoint(dentry, mp);
+ if (unlikely(err)) {
+ namespace_unlock();
+ inode_unlock(dentry->d_inode);
+ }
+ return err;
+}
+
+int finish_automount(struct vfsmount *m, const struct path *path)
+{
struct pinned_mountpoint mp = {};
struct mount *mnt;
int err;
@@ -3805,20 +3825,11 @@ int finish_automount(struct vfsmount *m, const struct path *path)
* that overmounts our mountpoint to be means "quitely drop what we've
* got", not "try to mount it on top".
*/
- inode_lock(dentry->d_inode);
- namespace_lock();
- if (unlikely(cant_mount(dentry))) {
- err = -ENOENT;
- goto discard_locked;
- }
- if (path_overmounted(path)) {
- err = 0;
- goto discard_locked;
+ err = lock_mount_exact(path, &mp);
+ if (unlikely(err)) {
+ mntput(m);
+ return err == -EBUSY ? 0 : err;
}
- err = get_mountpoint(dentry, &mp);
- if (err)
- goto discard_locked;
-
err = do_add_mount(mnt, mp.mp, path,
path->mnt->mnt_flags | MNT_SHRINKABLE);
unlock_mount(&mp);
@@ -3826,9 +3837,6 @@ int finish_automount(struct vfsmount *m, const struct path *path)
goto discard;
return 0;
-discard_locked:
- namespace_unlock();
- inode_unlock(dentry->d_inode);
discard:
mntput(m);
return err;