Like ksys_umount, but takes a kernel pointer for the destination path.
Switch over the umount in the init code to it, which just happens to work
due to the implicit set_fs(KERNEL_DS) during early init right now.

Signed-off-by: Christoph Hellwig <h...@lst.de>
---
 fs/namespace.c           | 53 ++++++++++++++++++++++++----------------
 include/linux/fs.h       |  1 +
 include/linux/syscalls.h |  1 -
 init/do_mounts_initrd.c  |  2 +-
 4 files changed, 34 insertions(+), 23 deletions(-)

diff --git a/fs/namespace.c b/fs/namespace.c
index d208a389aac3c0..cfcee6a1bd5dd2 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1706,36 +1706,26 @@ static inline bool may_mandlock(void)
 }
 #endif
 
-/*
- * Now umount can handle mount points as well as block devices.
- * This is important for filesystems which use unnamed block devices.
- *
- * We now support a flag for forced unmount like the other 'big iron'
- * unixes. Our API is identical to OSF/1 to avoid making a mess of AMD
- */
+static int umount_lookup_flags(int flags)
+{
+       if (flags & UMOUNT_NOFOLLOW)
+               return LOOKUP_MOUNTPOINT;
+       return LOOKUP_MOUNTPOINT | LOOKUP_FOLLOW;
+}
 
-int ksys_umount(char __user *name, int flags)
+static int path_umount(struct path *path, int flags)
 {
-       struct path path;
        struct mount *mnt;
        int retval;
-       int lookup_flags = LOOKUP_MOUNTPOINT;
 
        if (flags & ~(MNT_FORCE | MNT_DETACH | MNT_EXPIRE | UMOUNT_NOFOLLOW))
                return -EINVAL;
-
        if (!may_mount())
                return -EPERM;
 
-       if (!(flags & UMOUNT_NOFOLLOW))
-               lookup_flags |= LOOKUP_FOLLOW;
-
-       retval = user_path_at(AT_FDCWD, name, lookup_flags, &path);
-       if (retval)
-               goto out;
-       mnt = real_mount(path.mnt);
+       mnt = real_mount(path->mnt);
        retval = -EINVAL;
-       if (path.dentry != path.mnt->mnt_root)
+       if (path->dentry != path->mnt->mnt_root)
                goto dput_and_out;
        if (!check_mnt(mnt))
                goto dput_and_out;
@@ -1748,12 +1738,33 @@ int ksys_umount(char __user *name, int flags)
        retval = do_umount(mnt, flags);
 dput_and_out:
        /* we mustn't call path_put() as that would clear mnt_expiry_mark */
-       dput(path.dentry);
+       dput(path->dentry);
        mntput_no_expire(mnt);
-out:
        return retval;
 }
 
+static int ksys_umount(char __user *name, int flags)
+{
+       struct path path;
+       int ret;
+
+       ret = user_path_at(AT_FDCWD, name, umount_lookup_flags(flags), &path);
+       if (ret)
+               return ret;
+       return path_umount(&path, flags);
+}
+
+int __init kern_umount(char *name, int flags)
+{
+       struct path path;
+       int ret;
+
+       ret = kern_path(name, umount_lookup_flags(flags), &path);
+       if (ret)
+               return ret;
+       return path_umount(&path, flags);
+}
+
 SYSCALL_DEFINE2(umount, char __user *, name, int, flags)
 {
        return ksys_umount(name, flags);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 8f628f9868711d..fbeadaa1a185fb 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2339,6 +2339,7 @@ extern long do_mount(const char *, const char __user *,
                     const char *, unsigned long, void *);
 int do_kern_mount(const char *dev_name, const char *dir_name,
                const char *type_page, unsigned long flags, void *data_page);
+int __init kern_umount(char *name, int flags);
 extern struct vfsmount *collect_mounts(const struct path *);
 extern void drop_collected_mounts(struct vfsmount *);
 extern int iterate_mounts(int (*)(struct vfsmount *, void *), void *,
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 5b0f1fca4cfb9d..3b1b8ebcda1d8c 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -1236,7 +1236,6 @@ asmlinkage long sys_ni_syscall(void);
  * the ksys_xyzyyz() functions prototyped below.
  */
 
-int ksys_umount(char __user *name, int flags);
 int ksys_chroot(const char __user *filename);
 ssize_t ksys_write(unsigned int fd, const char __user *buf, size_t count);
 int ksys_chdir(const char __user *filename);
diff --git a/init/do_mounts_initrd.c b/init/do_mounts_initrd.c
index 604ce78af9acfa..d3858620707893 100644
--- a/init/do_mounts_initrd.c
+++ b/init/do_mounts_initrd.c
@@ -122,7 +122,7 @@ static void __init handle_initrd(void)
                else
                        printk("failed\n");
                printk(KERN_NOTICE "Unmounting old root\n");
-               ksys_umount("/old", MNT_DETACH);
+               kern_umount("/old", MNT_DETACH);
        }
 }
 
-- 
2.27.0

Reply via email to