diff options
| author | Al Viro <viro@zeniv.linux.org.uk> | 2025-08-22 12:59:10 -0400 |
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2025-09-02 19:35:59 -0400 |
| commit | 9bf5d488529b9efa01bd292633482acd10277b90 (patch) | |
| tree | aa945a59dfda9975b82f11be735088bf54b1db82 /fs/namespace.c | |
| parent | 6bbbc4a04a10ebdb633501dc87aac5b0d6b80ec8 (diff) | |
| download | random-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.c | 42 |
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; |
