fs: port vfs_*() helpers to struct mnt_idmap
[linux-2.6-block.git] / fs / namei.c
index 309ae6fc8c993b8057a560da88de4971fa004127..3e727efed860ef76f554a064732657f612dffdce 100644 (file)
@@ -3084,7 +3084,7 @@ static inline umode_t vfs_prepare_mode(struct user_namespace *mnt_userns,
 
 /**
  * vfs_create - create new file
- * @mnt_userns:        user namespace of the mount the inode was found from
+ * @idmap:     idmap of the mount the inode was found from
  * @dir:       inode of @dentry
  * @dentry:    pointer to dentry of the base directory
  * @mode:      mode of the new file
@@ -3092,16 +3092,19 @@ static inline umode_t vfs_prepare_mode(struct user_namespace *mnt_userns,
  *
  * Create a new file.
  *
- * If the inode has been found through an idmapped mount the user namespace of
- * the vfsmount must be passed through @mnt_userns. This function will then take
- * care to map the inode according to @mnt_userns before checking permissions.
+ * If the inode has been found through an idmapped mount the idmap of
+ * the vfsmount must be passed through @idmap. This function will then take
+ * care to map the inode according to @idmap before checking permissions.
  * On non-idmapped mounts or if permission checking is to be performed on the
- * raw inode simply passs init_user_ns.
+ * raw inode simply passs @nop_mnt_idmap.
  */
-int vfs_create(struct user_namespace *mnt_userns, struct inode *dir,
+int vfs_create(struct mnt_idmap *idmap, struct inode *dir,
               struct dentry *dentry, umode_t mode, bool want_excl)
 {
-       int error = may_create(mnt_userns, dir, dentry);
+       struct user_namespace *mnt_userns = mnt_idmap_owner(idmap);
+       int error;
+
+       error = may_create(mnt_userns, dir, dentry);
        if (error)
                return error;
 
@@ -3203,7 +3206,7 @@ static int may_open(struct user_namespace *mnt_userns, const struct path *path,
        return 0;
 }
 
-static int handle_truncate(struct user_namespace *mnt_userns, struct file *filp)
+static int handle_truncate(struct mnt_idmap *idmap, struct file *filp)
 {
        const struct path *path = &filp->f_path;
        struct inode *inode = path->dentry->d_inode;
@@ -3213,7 +3216,7 @@ static int handle_truncate(struct user_namespace *mnt_userns, struct file *filp)
 
        error = security_file_truncate(filp);
        if (!error) {
-               error = do_truncate(mnt_userns, path->dentry, 0,
+               error = do_truncate(idmap, path->dentry, 0,
                                    ATTR_MTIME|ATTR_CTIME|ATTR_OPEN,
                                    filp);
        }
@@ -3513,6 +3516,7 @@ finish_lookup:
 static int do_open(struct nameidata *nd,
                   struct file *file, const struct open_flags *op)
 {
+       struct mnt_idmap *idmap;
        struct user_namespace *mnt_userns;
        int open_flag = op->open_flag;
        bool do_truncate;
@@ -3526,7 +3530,8 @@ static int do_open(struct nameidata *nd,
        }
        if (!(file->f_mode & FMODE_CREATED))
                audit_inode(nd->name, nd->path.dentry, 0);
-       mnt_userns = mnt_user_ns(nd->path.mnt);
+       idmap = mnt_idmap(nd->path.mnt);
+       mnt_userns = mnt_idmap_owner(idmap);
        if (open_flag & O_CREAT) {
                if ((open_flag & O_EXCL) && !(file->f_mode & FMODE_CREATED))
                        return -EEXIST;
@@ -3558,7 +3563,7 @@ static int do_open(struct nameidata *nd,
        if (!error)
                error = ima_file_check(file, op->acc_mode);
        if (!error && do_truncate)
-               error = handle_truncate(mnt_userns, file);
+               error = handle_truncate(idmap, file);
        if (unlikely(error > 0)) {
                WARN_ON(1);
                error = -EINVAL;
@@ -3570,23 +3575,24 @@ static int do_open(struct nameidata *nd,
 
 /**
  * vfs_tmpfile - create tmpfile
- * @mnt_userns:        user namespace of the mount the inode was found from
+ * @idmap:     idmap of the mount the inode was found from
  * @dentry:    pointer to dentry of the base directory
  * @mode:      mode of the new tmpfile
  * @open_flag: flags
  *
  * Create a temporary file.
  *
- * If the inode has been found through an idmapped mount the user namespace of
- * the vfsmount must be passed through @mnt_userns. This function will then take
- * care to map the inode according to @mnt_userns before checking permissions.
+ * If the inode has been found through an idmapped mount the idmap of
+ * the vfsmount must be passed through @idmap. This function will then take
+ * care to map the inode according to @idmap before checking permissions.
  * On non-idmapped mounts or if permission checking is to be performed on the
- * raw inode simply passs init_user_ns.
+ * raw inode simply passs @nop_mnt_idmap.
  */
-static int vfs_tmpfile(struct user_namespace *mnt_userns,
+static int vfs_tmpfile(struct mnt_idmap *idmap,
                       const struct path *parentpath,
                       struct file *file, umode_t mode)
 {
+       struct user_namespace *mnt_userns = mnt_idmap_owner(idmap);
        struct dentry *child;
        struct inode *dir = d_inode(parentpath->dentry);
        struct inode *inode;
@@ -3625,7 +3631,7 @@ static int vfs_tmpfile(struct user_namespace *mnt_userns,
 
 /**
  * vfs_tmpfile_open - open a tmpfile for kernel internal use
- * @mnt_userns:        user namespace of the mount the inode was found from
+ * @idmap:     idmap of the mount the inode was found from
  * @parentpath:        path of the base directory
  * @mode:      mode of the new tmpfile
  * @open_flag: flags
@@ -3635,7 +3641,7 @@ static int vfs_tmpfile(struct user_namespace *mnt_userns,
  * hence this is only for kernel internal use, and must not be installed into
  * file tables or such.
  */
-struct file *vfs_tmpfile_open(struct user_namespace *mnt_userns,
+struct file *vfs_tmpfile_open(struct mnt_idmap *idmap,
                          const struct path *parentpath,
                          umode_t mode, int open_flag, const struct cred *cred)
 {
@@ -3644,7 +3650,7 @@ struct file *vfs_tmpfile_open(struct user_namespace *mnt_userns,
 
        file = alloc_empty_file_noaccount(open_flag, cred);
        if (!IS_ERR(file)) {
-               error = vfs_tmpfile(mnt_userns, parentpath, file, mode);
+               error = vfs_tmpfile(idmap, parentpath, file, mode);
                if (error) {
                        fput(file);
                        file = ERR_PTR(error);
@@ -3658,7 +3664,6 @@ static int do_tmpfile(struct nameidata *nd, unsigned flags,
                const struct open_flags *op,
                struct file *file)
 {
-       struct user_namespace *mnt_userns;
        struct path path;
        int error = path_lookupat(nd, flags | LOOKUP_DIRECTORY, &path);
 
@@ -3667,8 +3672,7 @@ static int do_tmpfile(struct nameidata *nd, unsigned flags,
        error = mnt_want_write(path.mnt);
        if (unlikely(error))
                goto out;
-       mnt_userns = mnt_user_ns(path.mnt);
-       error = vfs_tmpfile(mnt_userns, &path, file, op->mode);
+       error = vfs_tmpfile(mnt_idmap(path.mnt), &path, file, op->mode);
        if (error)
                goto out2;
        audit_inode(nd->name, file->f_path.dentry, 0);
@@ -3873,7 +3877,7 @@ EXPORT_SYMBOL(user_path_create);
 
 /**
  * vfs_mknod - create device node or file
- * @mnt_userns:        user namespace of the mount the inode was found from
+ * @idmap:     idmap of the mount the inode was found from
  * @dir:       inode of @dentry
  * @dentry:    pointer to dentry of the base directory
  * @mode:      mode of the new device node or file
@@ -3881,15 +3885,16 @@ EXPORT_SYMBOL(user_path_create);
  *
  * Create a device node or file.
  *
- * If the inode has been found through an idmapped mount the user namespace of
- * the vfsmount must be passed through @mnt_userns. This function will then take
- * care to map the inode according to @mnt_userns before checking permissions.
+ * If the inode has been found through an idmapped mount the idmap of
+ * the vfsmount must be passed through @idmap. This function will then take
+ * care to map the inode according to @idmap before checking permissions.
  * On non-idmapped mounts or if permission checking is to be performed on the
- * raw inode simply passs init_user_ns.
+ * raw inode simply passs @nop_mnt_idmap.
  */
-int vfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
+int vfs_mknod(struct mnt_idmap *idmap, struct inode *dir,
              struct dentry *dentry, umode_t mode, dev_t dev)
 {
+       struct user_namespace *mnt_userns = mnt_idmap_owner(idmap);
        bool is_whiteout = S_ISCHR(mode) && dev == WHITEOUT_DEV;
        int error = may_create(mnt_userns, dir, dentry);
 
@@ -3939,6 +3944,7 @@ static int may_mknod(umode_t mode)
 static int do_mknodat(int dfd, struct filename *name, umode_t mode,
                unsigned int dev)
 {
+       struct mnt_idmap *idmap;
        struct user_namespace *mnt_userns;
        struct dentry *dentry;
        struct path path;
@@ -3959,20 +3965,21 @@ retry:
        if (error)
                goto out2;
 
-       mnt_userns = mnt_user_ns(path.mnt);
+       idmap = mnt_idmap(path.mnt);
+       mnt_userns = mnt_idmap_owner(idmap);
        switch (mode & S_IFMT) {
                case 0: case S_IFREG:
-                       error = vfs_create(mnt_userns, path.dentry->d_inode,
+                       error = vfs_create(idmap, path.dentry->d_inode,
                                           dentry, mode, true);
                        if (!error)
                                ima_post_path_mknod(mnt_userns, dentry);
                        break;
                case S_IFCHR: case S_IFBLK:
-                       error = vfs_mknod(mnt_userns, path.dentry->d_inode,
+                       error = vfs_mknod(idmap, path.dentry->d_inode,
                                          dentry, mode, new_decode_dev(dev));
                        break;
                case S_IFIFO: case S_IFSOCK:
-                       error = vfs_mknod(mnt_userns, path.dentry->d_inode,
+                       error = vfs_mknod(idmap, path.dentry->d_inode,
                                          dentry, mode, 0);
                        break;
        }
@@ -4000,25 +4007,27 @@ SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, d
 
 /**
  * vfs_mkdir - create directory
- * @mnt_userns:        user namespace of the mount the inode was found from
+ * @idmap:     idmap of the mount the inode was found from
  * @dir:       inode of @dentry
  * @dentry:    pointer to dentry of the base directory
  * @mode:      mode of the new directory
  *
  * Create a directory.
  *
- * If the inode has been found through an idmapped mount the user namespace of
- * the vfsmount must be passed through @mnt_userns. This function will then take
- * care to map the inode according to @mnt_userns before checking permissions.
+ * If the inode has been found through an idmapped mount the idmap of
+ * the vfsmount must be passed through @idmap. This function will then take
+ * care to map the inode according to @idmap before checking permissions.
  * On non-idmapped mounts or if permission checking is to be performed on the
- * raw inode simply passs init_user_ns.
+ * raw inode simply passs @nop_mnt_idmap.
  */
-int vfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
+int vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
              struct dentry *dentry, umode_t mode)
 {
-       int error = may_create(mnt_userns, dir, dentry);
+       struct user_namespace *mnt_userns = mnt_idmap_owner(idmap);
+       int error;
        unsigned max_links = dir->i_sb->s_max_links;
 
+       error = may_create(mnt_userns, dir, dentry);
        if (error)
                return error;
 
@@ -4056,10 +4065,8 @@ retry:
        error = security_path_mkdir(&path, dentry,
                        mode_strip_umask(path.dentry->d_inode, mode));
        if (!error) {
-               struct user_namespace *mnt_userns;
-               mnt_userns = mnt_user_ns(path.mnt);
-               error = vfs_mkdir(mnt_userns, path.dentry->d_inode, dentry,
-                                 mode);
+               error = vfs_mkdir(mnt_idmap(path.mnt), path.dentry->d_inode,
+                                 dentry, mode);
        }
        done_path_create(&path, dentry);
        if (retry_estale(error, lookup_flags)) {
@@ -4083,21 +4090,22 @@ SYSCALL_DEFINE2(mkdir, const char __user *, pathname, umode_t, mode)
 
 /**
  * vfs_rmdir - remove directory
- * @mnt_userns:        user namespace of the mount the inode was found from
+ * @idmap:     idmap of the mount the inode was found from
  * @dir:       inode of @dentry
  * @dentry:    pointer to dentry of the base directory
  *
  * Remove a directory.
  *
- * If the inode has been found through an idmapped mount the user namespace of
- * the vfsmount must be passed through @mnt_userns. This function will then take
- * care to map the inode according to @mnt_userns before checking permissions.
+ * If the inode has been found through an idmapped mount the idmap of
+ * the vfsmount must be passed through @idmap. This function will then take
+ * care to map the inode according to @idmap before checking permissions.
  * On non-idmapped mounts or if permission checking is to be performed on the
- * raw inode simply passs init_user_ns.
+ * raw inode simply passs @nop_mnt_idmap.
  */
-int vfs_rmdir(struct user_namespace *mnt_userns, struct inode *dir,
+int vfs_rmdir(struct mnt_idmap *idmap, struct inode *dir,
                     struct dentry *dentry)
 {
+       struct user_namespace *mnt_userns = mnt_idmap_owner(idmap);
        int error = may_delete(mnt_userns, dir, dentry, 1);
 
        if (error)
@@ -4138,7 +4146,6 @@ EXPORT_SYMBOL(vfs_rmdir);
 
 int do_rmdir(int dfd, struct filename *name)
 {
-       struct user_namespace *mnt_userns;
        int error;
        struct dentry *dentry;
        struct path path;
@@ -4178,8 +4185,7 @@ retry:
        error = security_path_rmdir(&path, dentry);
        if (error)
                goto exit4;
-       mnt_userns = mnt_user_ns(path.mnt);
-       error = vfs_rmdir(mnt_userns, path.dentry->d_inode, dentry);
+       error = vfs_rmdir(mnt_idmap(path.mnt), path.dentry->d_inode, dentry);
 exit4:
        dput(dentry);
 exit3:
@@ -4203,7 +4209,7 @@ SYSCALL_DEFINE1(rmdir, const char __user *, pathname)
 
 /**
  * vfs_unlink - unlink a filesystem object
- * @mnt_userns:        user namespace of the mount the inode was found from
+ * @idmap:     idmap of the mount the inode was found from
  * @dir:       parent directory
  * @dentry:    victim
  * @delegated_inode: returns victim inode, if the inode is delegated.
@@ -4220,15 +4226,16 @@ SYSCALL_DEFINE1(rmdir, const char __user *, pathname)
  * be appropriate for callers that expect the underlying filesystem not
  * to be NFS exported.
  *
- * If the inode has been found through an idmapped mount the user namespace of
- * the vfsmount must be passed through @mnt_userns. This function will then take
- * care to map the inode according to @mnt_userns before checking permissions.
+ * If the inode has been found through an idmapped mount the idmap of
+ * the vfsmount must be passed through @idmap. This function will then take
+ * care to map the inode according to @idmap before checking permissions.
  * On non-idmapped mounts or if permission checking is to be performed on the
- * raw inode simply passs init_user_ns.
+ * raw inode simply passs @nop_mnt_idmap.
  */
-int vfs_unlink(struct user_namespace *mnt_userns, struct inode *dir,
+int vfs_unlink(struct mnt_idmap *idmap, struct inode *dir,
               struct dentry *dentry, struct inode **delegated_inode)
 {
+       struct user_namespace *mnt_userns = mnt_idmap_owner(idmap);
        struct inode *target = dentry->d_inode;
        int error = may_delete(mnt_userns, dir, dentry, 0);
 
@@ -4304,7 +4311,6 @@ retry_deleg:
        dentry = __lookup_hash(&last, path.dentry, lookup_flags);
        error = PTR_ERR(dentry);
        if (!IS_ERR(dentry)) {
-               struct user_namespace *mnt_userns;
 
                /* Why not before? Because we want correct error value */
                if (last.name[last.len])
@@ -4316,9 +4322,8 @@ retry_deleg:
                error = security_path_unlink(&path, dentry);
                if (error)
                        goto exit3;
-               mnt_userns = mnt_user_ns(path.mnt);
-               error = vfs_unlink(mnt_userns, path.dentry->d_inode, dentry,
-                                  &delegated_inode);
+               error = vfs_unlink(mnt_idmap(path.mnt), path.dentry->d_inode,
+                                  dentry, &delegated_inode);
 exit3:
                dput(dentry);
        }
@@ -4370,22 +4375,23 @@ SYSCALL_DEFINE1(unlink, const char __user *, pathname)
 
 /**
  * vfs_symlink - create symlink
- * @mnt_userns:        user namespace of the mount the inode was found from
+ * @idmap:     idmap of the mount the inode was found from
  * @dir:       inode of @dentry
  * @dentry:    pointer to dentry of the base directory
  * @oldname:   name of the file to link to
  *
  * Create a symlink.
  *
- * If the inode has been found through an idmapped mount the user namespace of
- * the vfsmount must be passed through @mnt_userns. This function will then take
- * care to map the inode according to @mnt_userns before checking permissions.
+ * If the inode has been found through an idmapped mount the idmap of
+ * the vfsmount must be passed through @idmap. This function will then take
+ * care to map the inode according to @idmap before checking permissions.
  * On non-idmapped mounts or if permission checking is to be performed on the
- * raw inode simply passs init_user_ns.
+ * raw inode simply passs @nop_mnt_idmap.
  */
-int vfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
+int vfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
                struct dentry *dentry, const char *oldname)
 {
+       struct user_namespace *mnt_userns = mnt_idmap_owner(idmap);
        int error = may_create(mnt_userns, dir, dentry);
 
        if (error)
@@ -4423,13 +4429,9 @@ retry:
                goto out_putnames;
 
        error = security_path_symlink(&path, dentry, from->name);
-       if (!error) {
-               struct user_namespace *mnt_userns;
-
-               mnt_userns = mnt_user_ns(path.mnt);
-               error = vfs_symlink(mnt_userns, path.dentry->d_inode, dentry,
-                                   from->name);
-       }
+       if (!error)
+               error = vfs_symlink(mnt_idmap(path.mnt), path.dentry->d_inode,
+                                   dentry, from->name);
        done_path_create(&path, dentry);
        if (retry_estale(error, lookup_flags)) {
                lookup_flags |= LOOKUP_REVAL;
@@ -4455,7 +4457,7 @@ SYSCALL_DEFINE2(symlink, const char __user *, oldname, const char __user *, newn
 /**
  * vfs_link - create a new link
  * @old_dentry:        object to be linked
- * @mnt_userns:        the user namespace of the mount
+ * @idmap:     idmap of the mount
  * @dir:       new parent
  * @new_dentry:        where to create the new link
  * @delegated_inode: returns inode needing a delegation break
@@ -4472,16 +4474,17 @@ SYSCALL_DEFINE2(symlink, const char __user *, oldname, const char __user *, newn
  * be appropriate for callers that expect the underlying filesystem not
  * to be NFS exported.
  *
- * If the inode has been found through an idmapped mount the user namespace of
- * the vfsmount must be passed through @mnt_userns. This function will then take
- * care to map the inode according to @mnt_userns before checking permissions.
+ * If the inode has been found through an idmapped mount the idmap of
+ * the vfsmount must be passed through @idmap. This function will then take
+ * care to map the inode according to @idmap before checking permissions.
  * On non-idmapped mounts or if permission checking is to be performed on the
- * raw inode simply passs init_user_ns.
+ * raw inode simply passs @nop_mnt_idmap.
  */
-int vfs_link(struct dentry *old_dentry, struct user_namespace *mnt_userns,
+int vfs_link(struct dentry *old_dentry, struct mnt_idmap *idmap,
             struct inode *dir, struct dentry *new_dentry,
             struct inode **delegated_inode)
 {
+       struct user_namespace *mnt_userns = mnt_idmap_owner(idmap);
        struct inode *inode = old_dentry->d_inode;
        unsigned max_links = dir->i_sb->s_max_links;
        int error;
@@ -4553,6 +4556,7 @@ EXPORT_SYMBOL(vfs_link);
 int do_linkat(int olddfd, struct filename *old, int newdfd,
              struct filename *new, int flags)
 {
+       struct mnt_idmap *idmap;
        struct user_namespace *mnt_userns;
        struct dentry *new_dentry;
        struct path old_path, new_path;
@@ -4590,14 +4594,15 @@ retry:
        error = -EXDEV;
        if (old_path.mnt != new_path.mnt)
                goto out_dput;
-       mnt_userns = mnt_user_ns(new_path.mnt);
+       idmap = mnt_idmap(new_path.mnt);
+       mnt_userns = mnt_idmap_owner(idmap);
        error = may_linkat(mnt_userns, &old_path);
        if (unlikely(error))
                goto out_dput;
        error = security_path_link(old_path.dentry, &new_path, new_dentry);
        if (error)
                goto out_dput;
-       error = vfs_link(old_path.dentry, mnt_userns, new_path.dentry->d_inode,
+       error = vfs_link(old_path.dentry, idmap, new_path.dentry->d_inode,
                         new_dentry, &delegated_inode);
 out_dput:
        done_path_create(&new_path, new_dentry);
@@ -4693,24 +4698,26 @@ int vfs_rename(struct renamedata *rd)
        bool new_is_dir = false;
        unsigned max_links = new_dir->i_sb->s_max_links;
        struct name_snapshot old_name;
+       struct user_namespace *old_mnt_userns = mnt_idmap_owner(rd->old_mnt_idmap),
+                             *new_mnt_userns = mnt_idmap_owner(rd->new_mnt_idmap);
 
        if (source == target)
                return 0;
 
-       error = may_delete(rd->old_mnt_userns, old_dir, old_dentry, is_dir);
+       error = may_delete(old_mnt_userns, old_dir, old_dentry, is_dir);
        if (error)
                return error;
 
        if (!target) {
-               error = may_create(rd->new_mnt_userns, new_dir, new_dentry);
+               error = may_create(new_mnt_userns, new_dir, new_dentry);
        } else {
                new_is_dir = d_is_dir(new_dentry);
 
                if (!(flags & RENAME_EXCHANGE))
-                       error = may_delete(rd->new_mnt_userns, new_dir,
+                       error = may_delete(new_mnt_userns, new_dir,
                                           new_dentry, is_dir);
                else
-                       error = may_delete(rd->new_mnt_userns, new_dir,
+                       error = may_delete(new_mnt_userns, new_dir,
                                           new_dentry, new_is_dir);
        }
        if (error)
@@ -4725,13 +4732,13 @@ int vfs_rename(struct renamedata *rd)
         */
        if (new_dir != old_dir) {
                if (is_dir) {
-                       error = inode_permission(rd->old_mnt_userns, source,
+                       error = inode_permission(old_mnt_userns, source,
                                                 MAY_WRITE);
                        if (error)
                                return error;
                }
                if ((flags & RENAME_EXCHANGE) && new_is_dir) {
-                       error = inode_permission(rd->new_mnt_userns, target,
+                       error = inode_permission(new_mnt_userns, target,
                                                 MAY_WRITE);
                        if (error)
                                return error;
@@ -4776,7 +4783,7 @@ int vfs_rename(struct renamedata *rd)
                if (error)
                        goto out;
        }
-       error = old_dir->i_op->rename(rd->new_mnt_userns, old_dir, old_dentry,
+       error = old_dir->i_op->rename(new_mnt_userns, old_dir, old_dentry,
                                      new_dir, new_dentry, flags);
        if (error)
                goto out;
@@ -4921,10 +4928,10 @@ retry_deleg:
 
        rd.old_dir         = old_path.dentry->d_inode;
        rd.old_dentry      = old_dentry;
-       rd.old_mnt_userns  = mnt_user_ns(old_path.mnt);
+       rd.old_mnt_idmap   = mnt_idmap(old_path.mnt);
        rd.new_dir         = new_path.dentry->d_inode;
        rd.new_dentry      = new_dentry;
-       rd.new_mnt_userns  = mnt_user_ns(new_path.mnt);
+       rd.new_mnt_idmap   = mnt_idmap(new_path.mnt);
        rd.delegated_inode = &delegated_inode;
        rd.flags           = flags;
        error = vfs_rename(&rd);