OSDN Git Service

Merge tag 'v4.4.214' into 10
[sagit-ice-cold/kernel_xiaomi_msm8998.git] / fs / namei.c
index 9f1aae5..e221fed 100644 (file)
@@ -40,6 +40,9 @@
 #include "internal.h"
 #include "mount.h"
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/namei.h>
+
 /* [Feb-1997 T. Schoebel-Theuer]
  * Fundamental changes in the pathname lookup mechanisms (namei)
  * were necessary because of omirr.  The reason is that omirr needs
@@ -374,9 +377,11 @@ EXPORT_SYMBOL(generic_permission);
  * flag in inode->i_opflags, that says "this has not special
  * permission function, use the fast case".
  */
-static inline int do_inode_permission(struct inode *inode, int mask)
+static inline int do_inode_permission(struct vfsmount *mnt, struct inode *inode, int mask)
 {
        if (unlikely(!(inode->i_opflags & IOP_FASTPERM))) {
+               if (likely(mnt && inode->i_op->permission2))
+                       return inode->i_op->permission2(mnt, inode, mask);
                if (likely(inode->i_op->permission))
                        return inode->i_op->permission(inode, mask);
 
@@ -400,7 +405,7 @@ static inline int do_inode_permission(struct inode *inode, int mask)
  * This does not check for a read-only file system.  You probably want
  * inode_permission().
  */
-int __inode_permission(struct inode *inode, int mask)
+int __inode_permission2(struct vfsmount *mnt, struct inode *inode, int mask)
 {
        int retval;
 
@@ -412,7 +417,7 @@ int __inode_permission(struct inode *inode, int mask)
                        return -EACCES;
        }
 
-       retval = do_inode_permission(inode, mask);
+       retval = do_inode_permission(mnt, inode, mask);
        if (retval)
                return retval;
 
@@ -420,7 +425,14 @@ int __inode_permission(struct inode *inode, int mask)
        if (retval)
                return retval;
 
-       return security_inode_permission(inode, mask);
+       retval = security_inode_permission(inode, mask);
+       return retval;
+}
+EXPORT_SYMBOL(__inode_permission2);
+
+int __inode_permission(struct inode *inode, int mask)
+{
+       return __inode_permission2(NULL, inode, mask);
 }
 EXPORT_SYMBOL(__inode_permission);
 
@@ -456,14 +468,20 @@ static int sb_permission(struct super_block *sb, struct inode *inode, int mask)
  *
  * When checking for MAY_APPEND, MAY_WRITE must also be set in @mask.
  */
-int inode_permission(struct inode *inode, int mask)
+int inode_permission2(struct vfsmount *mnt, struct inode *inode, int mask)
 {
        int retval;
 
        retval = sb_permission(inode->i_sb, inode, mask);
        if (retval)
                return retval;
-       return __inode_permission(inode, mask);
+       return __inode_permission2(mnt, inode, mask);
+}
+EXPORT_SYMBOL(inode_permission2);
+
+int inode_permission(struct inode *inode, int mask)
+{
+       return inode_permission2(NULL, inode, mask);
 }
 EXPORT_SYMBOL(inode_permission);
 
@@ -769,6 +787,81 @@ static inline int d_revalidate(struct dentry *dentry, unsigned int flags)
        return dentry->d_op->d_revalidate(dentry, flags);
 }
 
+#define INIT_PATH_SIZE 64
+
+static void success_walk_trace(struct nameidata *nd)
+{
+       struct path *pt = &nd->path;
+       struct inode *i = nd->inode;
+       char buf[INIT_PATH_SIZE], *try_buf;
+       int cur_path_size;
+       char *p;
+
+       /* When eBPF/ tracepoint is disabled, keep overhead low. */
+       if (!trace_inodepath_enabled())
+               return;
+
+       /* First try stack allocated buffer. */
+       try_buf = buf;
+       cur_path_size = INIT_PATH_SIZE;
+
+       while (cur_path_size <= PATH_MAX) {
+               /* Free previous heap allocation if we are now trying
+                * a second or later heap allocation.
+                */
+               if (try_buf != buf)
+                       kfree(try_buf);
+
+               /* All but the first alloc are on the heap. */
+               if (cur_path_size != INIT_PATH_SIZE) {
+                       try_buf = kmalloc(cur_path_size, GFP_KERNEL);
+                       if (!try_buf) {
+                               try_buf = buf;
+                               sprintf(try_buf, "error:buf_alloc_failed");
+                               break;
+                       }
+               }
+
+               p = d_path(pt, try_buf, cur_path_size);
+
+               if (!IS_ERR(p)) {
+                       char *end = mangle_path(try_buf, p, "\n");
+
+                       if (end) {
+                               try_buf[end - try_buf] = 0;
+                               break;
+                       } else {
+                               /* On mangle errors, double path size
+                                * till PATH_MAX.
+                                */
+                               cur_path_size = cur_path_size << 1;
+                               continue;
+                       }
+               }
+
+               if (PTR_ERR(p) == -ENAMETOOLONG) {
+                       /* If d_path complains that name is too long,
+                        * then double path size till PATH_MAX.
+                        */
+                       cur_path_size = cur_path_size << 1;
+                       continue;
+               }
+
+               sprintf(try_buf, "error:d_path_failed_%lu",
+                       -1 * PTR_ERR(p));
+               break;
+       }
+
+       if (cur_path_size > PATH_MAX)
+               sprintf(try_buf, "error:d_path_name_too_long");
+
+       trace_inodepath(i, try_buf);
+
+       if (try_buf != buf)
+               kfree(try_buf);
+       return;
+}
+
 /**
  * complete_walk - successful completion of path walk
  * @nd:  pointer nameidata
@@ -791,15 +884,21 @@ static int complete_walk(struct nameidata *nd)
                        return -ECHILD;
        }
 
-       if (likely(!(nd->flags & LOOKUP_JUMPED)))
+       if (likely(!(nd->flags & LOOKUP_JUMPED))) {
+               success_walk_trace(nd);
                return 0;
+       }
 
-       if (likely(!(dentry->d_flags & DCACHE_OP_WEAK_REVALIDATE)))
+       if (likely(!(dentry->d_flags & DCACHE_OP_WEAK_REVALIDATE))) {
+               success_walk_trace(nd);
                return 0;
+       }
 
        status = dentry->d_op->d_weak_revalidate(dentry, nd->flags);
-       if (status > 0)
+       if (status > 0) {
+               success_walk_trace(nd);
                return 0;
+       }
 
        if (!status)
                status = -ESTALE;
@@ -1689,13 +1788,13 @@ static int lookup_slow(struct nameidata *nd, struct path *path)
 static inline int may_lookup(struct nameidata *nd)
 {
        if (nd->flags & LOOKUP_RCU) {
-               int err = inode_permission(nd->inode, MAY_EXEC|MAY_NOT_BLOCK);
+               int err = inode_permission2(nd->path.mnt, nd->inode, MAY_EXEC|MAY_NOT_BLOCK);
                if (err != -ECHILD)
                        return err;
                if (unlazy_walk(nd, NULL, 0))
                        return -ECHILD;
        }
-       return inode_permission(nd->inode, MAY_EXEC);
+       return inode_permission2(nd->path.mnt, nd->inode, MAY_EXEC);
 }
 
 static inline int handle_dots(struct nameidata *nd, int type)
@@ -2052,11 +2151,12 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
        nd->depth = 0;
        if (flags & LOOKUP_ROOT) {
                struct dentry *root = nd->root.dentry;
+               struct vfsmount *mnt = nd->root.mnt;
                struct inode *inode = root->d_inode;
                if (*s) {
                        if (!d_can_lookup(root))
                                return ERR_PTR(-ENOTDIR);
-                       retval = inode_permission(inode, MAY_EXEC);
+                       retval = inode_permission2(mnt, inode, MAY_EXEC);
                        if (retval)
                                return ERR_PTR(retval);
                }
@@ -2190,6 +2290,7 @@ static int path_lookupat(struct nameidata *nd, unsigned flags, struct path *path
        if (!err && nd->flags & LOOKUP_DIRECTORY)
                if (!d_can_lookup(nd->path.dentry))
                        err = -ENOTDIR;
+
        if (!err) {
                *path = nd->path;
                nd->path.mnt = NULL;
@@ -2327,13 +2428,14 @@ EXPORT_SYMBOL(vfs_path_lookup);
 /**
  * lookup_one_len - filesystem helper to lookup single pathname component
  * @name:      pathname component to lookup
+ * @mnt:       mount we are looking up on
  * @base:      base directory to lookup from
  * @len:       maximum length @len should be interpreted to
  *
  * Note that this routine is purely a helper for filesystem usage and should
  * not be called by generic code.
  */
-struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
+struct dentry *lookup_one_len2(const char *name, struct vfsmount *mnt, struct dentry *base, int len)
 {
        struct qstr this;
        unsigned int c;
@@ -2367,12 +2469,18 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
                        return ERR_PTR(err);
        }
 
-       err = inode_permission(base->d_inode, MAY_EXEC);
+       err = inode_permission2(mnt, base->d_inode, MAY_EXEC);
        if (err)
                return ERR_PTR(err);
 
        return __lookup_hash(&this, base, 0);
 }
+EXPORT_SYMBOL(lookup_one_len2);
+
+struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
+{
+       return lookup_one_len2(name, NULL, base, len);
+}
 EXPORT_SYMBOL(lookup_one_len);
 
 int user_path_at_empty(int dfd, const char __user *name, unsigned flags,
@@ -2599,7 +2707,7 @@ EXPORT_SYMBOL(__check_sticky);
  * 10. We don't allow removal of NFS sillyrenamed files; it's handled by
  *     nfs_async_unlink().
  */
-static int may_delete(struct inode *dir, struct dentry *victim, bool isdir)
+static int may_delete(struct vfsmount *mnt, struct inode *dir, struct dentry *victim, bool isdir)
 {
        struct inode *inode = d_backing_inode(victim);
        int error;
@@ -2611,7 +2719,7 @@ static int may_delete(struct inode *dir, struct dentry *victim, bool isdir)
        BUG_ON(victim->d_parent->d_inode != dir);
        audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE);
 
-       error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
+       error = inode_permission2(mnt, dir, MAY_WRITE | MAY_EXEC);
        if (error)
                return error;
        if (IS_APPEND(dir))
@@ -2642,14 +2750,14 @@ static int may_delete(struct inode *dir, struct dentry *victim, bool isdir)
  *  3. We should have write and exec permissions on dir
  *  4. We can't do it if dir is immutable (done in permission())
  */
-static inline int may_create(struct inode *dir, struct dentry *child)
+static inline int may_create(struct vfsmount *mnt, struct inode *dir, struct dentry *child)
 {
        audit_inode_child(dir, child, AUDIT_TYPE_CHILD_CREATE);
        if (child->d_inode)
                return -EEXIST;
        if (IS_DEADDIR(dir))
                return -ENOENT;
-       return inode_permission(dir, MAY_WRITE | MAY_EXEC);
+       return inode_permission2(mnt, dir, MAY_WRITE | MAY_EXEC);
 }
 
 /*
@@ -2696,10 +2804,10 @@ void unlock_rename(struct dentry *p1, struct dentry *p2)
 }
 EXPORT_SYMBOL(unlock_rename);
 
-int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-               bool want_excl)
+int vfs_create2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry,
+               umode_t mode, bool want_excl)
 {
-       int error = may_create(dir, dentry);
+       int error = may_create(mnt, dir, dentry);
        if (error)
                return error;
 
@@ -2711,15 +2819,29 @@ int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
        if (error)
                return error;
        error = dir->i_op->create(dir, dentry, mode, want_excl);
+       if (error)
+               return error;
+       error = security_inode_post_create(dir, dentry, mode);
+       if (error)
+               return error;
        if (!error)
                fsnotify_create(dir, dentry);
+
        return error;
 }
+EXPORT_SYMBOL(vfs_create2);
+
+int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
+               bool want_excl)
+{
+       return vfs_create2(NULL, dir, dentry, mode, want_excl);
+}
 EXPORT_SYMBOL(vfs_create);
 
 static int may_open(struct path *path, int acc_mode, int flag)
 {
        struct dentry *dentry = path->dentry;
+       struct vfsmount *mnt = path->mnt;
        struct inode *inode = dentry->d_inode;
        int error;
 
@@ -2748,7 +2870,7 @@ static int may_open(struct path *path, int acc_mode, int flag)
                break;
        }
 
-       error = inode_permission(inode, acc_mode);
+       error = inode_permission2(mnt, inode, acc_mode);
        if (error)
                return error;
 
@@ -2783,7 +2905,7 @@ static int handle_truncate(struct file *filp)
        if (!error)
                error = security_path_truncate(path);
        if (!error) {
-               error = do_truncate(path->dentry, 0,
+               error = do_truncate2(path->mnt, path->dentry, 0,
                                    ATTR_MTIME|ATTR_CTIME|ATTR_OPEN,
                                    filp);
        }
@@ -2804,7 +2926,7 @@ static int may_o_create(struct path *dir, struct dentry *dentry, umode_t mode)
        if (error)
                return error;
 
-       error = inode_permission(dir->dentry->d_inode, MAY_WRITE | MAY_EXEC);
+       error = inode_permission2(dir->mnt, dir->dentry->d_inode, MAY_WRITE | MAY_EXEC);
        if (error)
                return error;
 
@@ -2990,6 +3112,7 @@ static int lookup_open(struct nameidata *nd, struct path *path,
                        bool got_write, int *opened)
 {
        struct dentry *dir = nd->path.dentry;
+       struct vfsmount *mnt = nd->path.mnt;
        struct inode *dir_inode = dir->d_inode;
        struct dentry *dentry;
        int error;
@@ -3037,7 +3160,7 @@ static int lookup_open(struct nameidata *nd, struct path *path,
                error = security_path_mknod(&nd->path, dentry, mode, 0);
                if (error)
                        goto out_dput;
-               error = vfs_create(dir->d_inode, dentry, mode,
+               error = vfs_create2(mnt, dir->d_inode, dentry, mode,
                                   nd->flags & LOOKUP_EXCL);
                if (error)
                        goto out_dput;
@@ -3307,7 +3430,7 @@ static int do_tmpfile(struct nameidata *nd, unsigned flags,
                goto out;
        dir = path.dentry->d_inode;
        /* we want directory to be writable */
-       error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
+       error = inode_permission2(path.mnt, dir, MAY_WRITE | MAY_EXEC);
        if (error)
                goto out2;
        if (!dir->i_op->tmpfile) {
@@ -3396,6 +3519,8 @@ out2:
                                error = -ESTALE;
                }
                file = ERR_PTR(error);
+       } else {
+               global_filetable_add(file);
        }
        return file;
 }
@@ -3541,9 +3666,9 @@ inline struct dentry *user_path_create(int dfd, const char __user *pathname,
 }
 EXPORT_SYMBOL(user_path_create);
 
-int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
+int vfs_mknod2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
 {
-       int error = may_create(dir, dentry);
+       int error = may_create(mnt, dir, dentry);
 
        if (error)
                return error;
@@ -3563,10 +3688,24 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
                return error;
 
        error = dir->i_op->mknod(dir, dentry, mode, dev);
+       if (error)
+               return error;
+
+       error = security_inode_post_create(dir, dentry, mode);
+       if (error)
+               return error;
+
        if (!error)
                fsnotify_create(dir, dentry);
+
        return error;
 }
+EXPORT_SYMBOL(vfs_mknod2);
+
+int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
+{
+       return vfs_mknod2(NULL, dir, dentry, mode, dev);
+}
 EXPORT_SYMBOL(vfs_mknod);
 
 static int may_mknod(umode_t mode)
@@ -3609,10 +3748,10 @@ retry:
                goto out;
        switch (mode & S_IFMT) {
                case 0: case S_IFREG:
-                       error = vfs_create(path.dentry->d_inode,dentry,mode,true);
+                       error = vfs_create2(path.mnt, path.dentry->d_inode,dentry,mode,true);
                        break;
                case S_IFCHR: case S_IFBLK:
-                       error = vfs_mknod(path.dentry->d_inode,dentry,mode,
+                       error = vfs_mknod2(path.mnt, path.dentry->d_inode,dentry,mode,
                                        new_decode_dev(dev));
                        break;
                case S_IFIFO: case S_IFSOCK:
@@ -3633,9 +3772,9 @@ SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, d
        return sys_mknodat(AT_FDCWD, filename, mode, dev);
 }
 
-int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
+int vfs_mkdir2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, umode_t mode)
 {
-       int error = may_create(dir, dentry);
+       int error = may_create(mnt, dir, dentry);
        unsigned max_links = dir->i_sb->s_max_links;
 
        if (error)
@@ -3657,6 +3796,12 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
                fsnotify_mkdir(dir, dentry);
        return error;
 }
+EXPORT_SYMBOL(vfs_mkdir2);
+
+int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
+{
+       return vfs_mkdir2(NULL, dir, dentry, mode);
+}
 EXPORT_SYMBOL(vfs_mkdir);
 
 SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode)
@@ -3675,7 +3820,7 @@ retry:
                mode &= ~current_umask();
        error = security_path_mkdir(&path, dentry, mode);
        if (!error)
-               error = vfs_mkdir(path.dentry->d_inode, dentry, mode);
+               error = vfs_mkdir2(path.mnt, path.dentry->d_inode, dentry, mode);
        done_path_create(&path, dentry);
        if (retry_estale(error, lookup_flags)) {
                lookup_flags |= LOOKUP_REVAL;
@@ -3714,9 +3859,9 @@ void dentry_unhash(struct dentry *dentry)
 }
 EXPORT_SYMBOL(dentry_unhash);
 
-int vfs_rmdir(struct inode *dir, struct dentry *dentry)
+int vfs_rmdir2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry)
 {
-       int error = may_delete(dir, dentry, 1);
+       int error = may_delete(mnt, dir, dentry, 1);
 
        if (error)
                return error;
@@ -3751,6 +3896,12 @@ out:
                d_delete(dentry);
        return error;
 }
+EXPORT_SYMBOL(vfs_rmdir2);
+
+int vfs_rmdir(struct inode *dir, struct dentry *dentry)
+{
+       return vfs_rmdir2(NULL, dir, dentry);
+}
 EXPORT_SYMBOL(vfs_rmdir);
 
 static long do_rmdir(int dfd, const char __user *pathname)
@@ -3796,7 +3947,7 @@ retry:
        error = security_path_rmdir(&path, dentry);
        if (error)
                goto exit3;
-       error = vfs_rmdir(path.dentry->d_inode, dentry);
+       error = vfs_rmdir2(path.mnt, path.dentry->d_inode, dentry);
 exit3:
        dput(dentry);
 exit2:
@@ -3835,10 +3986,10 @@ SYSCALL_DEFINE1(rmdir, const char __user *, pathname)
  * be appropriate for callers that expect the underlying filesystem not
  * to be NFS exported.
  */
-int vfs_unlink(struct inode *dir, struct dentry *dentry, struct inode **delegated_inode)
+int vfs_unlink2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, struct inode **delegated_inode)
 {
        struct inode *target = dentry->d_inode;
-       int error = may_delete(dir, dentry, 0);
+       int error = may_delete(mnt, dir, dentry, 0);
 
        if (error)
                return error;
@@ -3873,6 +4024,12 @@ out:
 
        return error;
 }
+EXPORT_SYMBOL(vfs_unlink2);
+
+int vfs_unlink(struct inode *dir, struct dentry *dentry, struct inode **delegated_inode)
+{
+       return vfs_unlink2(NULL, dir, dentry, delegated_inode);
+}
 EXPORT_SYMBOL(vfs_unlink);
 
 /*
@@ -3920,7 +4077,7 @@ retry_deleg:
                error = security_path_unlink(&path, dentry);
                if (error)
                        goto exit2;
-               error = vfs_unlink(path.dentry->d_inode, dentry, &delegated_inode);
+               error = vfs_unlink2(path.mnt, path.dentry->d_inode, dentry, &delegated_inode);
 exit2:
                dput(dentry);
        }
@@ -3970,9 +4127,9 @@ SYSCALL_DEFINE1(unlink, const char __user *, pathname)
        return do_unlinkat(AT_FDCWD, pathname);
 }
 
-int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
+int vfs_symlink2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, const char *oldname)
 {
-       int error = may_create(dir, dentry);
+       int error = may_create(mnt, dir, dentry);
 
        if (error)
                return error;
@@ -3989,6 +4146,12 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
                fsnotify_create(dir, dentry);
        return error;
 }
+EXPORT_SYMBOL(vfs_symlink2);
+
+int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
+{
+       return vfs_symlink2(NULL, dir, dentry, oldname);
+}
 EXPORT_SYMBOL(vfs_symlink);
 
 SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
@@ -4011,7 +4174,7 @@ retry:
 
        error = security_path_symlink(&path, dentry, from->name);
        if (!error)
-               error = vfs_symlink(path.dentry->d_inode, dentry, from->name);
+               error = vfs_symlink2(path.mnt, path.dentry->d_inode, dentry, from->name);
        done_path_create(&path, dentry);
        if (retry_estale(error, lookup_flags)) {
                lookup_flags |= LOOKUP_REVAL;
@@ -4046,7 +4209,7 @@ 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.
  */
-int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry, struct inode **delegated_inode)
+int vfs_link2(struct vfsmount *mnt, struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry, struct inode **delegated_inode)
 {
        struct inode *inode = old_dentry->d_inode;
        unsigned max_links = dir->i_sb->s_max_links;
@@ -4055,7 +4218,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
        if (!inode)
                return -ENOENT;
 
-       error = may_create(dir, new_dentry);
+       error = may_create(mnt, dir, new_dentry);
        if (error)
                return error;
 
@@ -4098,6 +4261,12 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
                fsnotify_link(dir, inode, new_dentry);
        return error;
 }
+EXPORT_SYMBOL(vfs_link2);
+
+int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry, struct inode **delegated_inode)
+{
+       return vfs_link2(NULL, old_dentry, dir, new_dentry, delegated_inode);
+}
 EXPORT_SYMBOL(vfs_link);
 
 /*
@@ -4153,7 +4322,7 @@ retry:
        error = security_path_link(old_path.dentry, &new_path, new_dentry);
        if (error)
                goto out_dput;
-       error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry, &delegated_inode);
+       error = vfs_link2(old_path.mnt, old_path.dentry, new_path.dentry->d_inode, new_dentry, &delegated_inode);
 out_dput:
        done_path_create(&new_path, new_dentry);
        if (delegated_inode) {
@@ -4228,7 +4397,8 @@ SYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname
  *        ->i_mutex on parents, which works but leads to some truly excessive
  *        locking].
  */
-int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+int vfs_rename2(struct vfsmount *mnt,
+              struct inode *old_dir, struct dentry *old_dentry,
               struct inode *new_dir, struct dentry *new_dentry,
               struct inode **delegated_inode, unsigned int flags)
 {
@@ -4247,19 +4417,19 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (vfs_select_inode(old_dentry, 0) == vfs_select_inode(new_dentry, 0))
                return 0;
 
-       error = may_delete(old_dir, old_dentry, is_dir);
+       error = may_delete(mnt, old_dir, old_dentry, is_dir);
        if (error)
                return error;
 
        if (!target) {
-               error = may_create(new_dir, new_dentry);
+               error = may_create(mnt, new_dir, new_dentry);
        } else {
                new_is_dir = d_is_dir(new_dentry);
 
                if (!(flags & RENAME_EXCHANGE))
-                       error = may_delete(new_dir, new_dentry, is_dir);
+                       error = may_delete(mnt, new_dir, new_dentry, is_dir);
                else
-                       error = may_delete(new_dir, new_dentry, new_is_dir);
+                       error = may_delete(mnt, new_dir, new_dentry, new_is_dir);
        }
        if (error)
                return error;
@@ -4276,12 +4446,12 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
         */
        if (new_dir != old_dir) {
                if (is_dir) {
-                       error = inode_permission(source, MAY_WRITE);
+                       error = inode_permission2(mnt, source, MAY_WRITE);
                        if (error)
                                return error;
                }
                if ((flags & RENAME_EXCHANGE) && new_is_dir) {
-                       error = inode_permission(target, MAY_WRITE);
+                       error = inode_permission2(mnt, target, MAY_WRITE);
                        if (error)
                                return error;
                }
@@ -4364,6 +4534,14 @@ out:
 
        return error;
 }
+EXPORT_SYMBOL(vfs_rename2);
+
+int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+              struct inode *new_dir, struct dentry *new_dentry,
+              struct inode **delegated_inode, unsigned int flags)
+{
+       return vfs_rename2(NULL, old_dir, old_dentry, new_dir, new_dentry, delegated_inode, flags);
+}
 EXPORT_SYMBOL(vfs_rename);
 
 SYSCALL_DEFINE5(renameat2, int, olddfd, const char __user *, oldname,
@@ -4477,7 +4655,7 @@ retry_deleg:
                                     &new_path, new_dentry, flags);
        if (error)
                goto exit5;
-       error = vfs_rename(old_path.dentry->d_inode, old_dentry,
+       error = vfs_rename2(old_path.mnt, old_path.dentry->d_inode, old_dentry,
                           new_path.dentry->d_inode, new_dentry,
                           &delegated_inode, flags);
 exit5:
@@ -4522,7 +4700,7 @@ SYSCALL_DEFINE2(rename, const char __user *, oldname, const char __user *, newna
 
 int vfs_whiteout(struct inode *dir, struct dentry *dentry)
 {
-       int error = may_create(dir, dentry);
+       int error = may_create(NULL, dir, dentry);
        if (error)
                return error;