mirror of https://github.com/OpenIPC/firmware.git
580 lines
19 KiB
Diff
580 lines
19 KiB
Diff
diff -drupN a/fs/namei.c b/fs/namei.c
|
|
--- a/fs/namei.c 2018-08-06 17:23:04.000000000 +0300
|
|
+++ b/fs/namei.c 2022-06-12 05:28:14.000000000 +0300
|
|
@@ -39,6 +39,8 @@
|
|
#include <linux/init_task.h>
|
|
#include <asm/uaccess.h>
|
|
|
|
+#include <linux/fivm.h>
|
|
+
|
|
#include "internal.h"
|
|
#include "mount.h"
|
|
|
|
@@ -51,8 +53,8 @@
|
|
* The new code replaces the old recursive symlink resolution with
|
|
* an iterative one (in case of non-nested symlink chains). It does
|
|
* this with calls to <fs>_follow_link().
|
|
- * As a side effect, dir_namei(), _namei() and follow_link() are now
|
|
- * replaced with a single function lookup_dentry() that can handle all
|
|
+ * As a side effect, dir_namei(), _namei() and follow_link() are now
|
|
+ * replaced with a single function lookup_dentry() that can handle all
|
|
* the special cases of the former code.
|
|
*
|
|
* With the new dcache, the pathname is stored at each inode, at least as
|
|
@@ -376,9 +378,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);
|
|
|
|
@@ -402,7 +406,7 @@ static inline int do_inode_permission(st
|
|
* 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;
|
|
|
|
@@ -422,7 +426,7 @@ int __inode_permission(struct inode *ino
|
|
return -EACCES;
|
|
}
|
|
|
|
- retval = do_inode_permission(inode, mask);
|
|
+ retval = do_inode_permission(mnt, inode, mask);
|
|
if (retval)
|
|
return retval;
|
|
|
|
@@ -430,7 +434,14 @@ int __inode_permission(struct inode *ino
|
|
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);
|
|
|
|
@@ -466,14 +477,20 @@ static int sb_permission(struct super_bl
|
|
*
|
|
* 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);
|
|
|
|
@@ -1665,13 +1682,13 @@ out:
|
|
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)
|
|
@@ -2145,11 +2162,12 @@ static const char *path_init(struct name
|
|
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);
|
|
}
|
|
@@ -2414,6 +2432,7 @@ 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
|
|
*
|
|
@@ -2422,7 +2441,7 @@ EXPORT_SYMBOL(vfs_path_lookup);
|
|
*
|
|
* The caller must hold base->i_mutex.
|
|
*/
|
|
-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;
|
|
@@ -2456,12 +2475,18 @@ struct dentry *lookup_one_len(const char
|
|
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);
|
|
|
|
/**
|
|
@@ -2764,7 +2789,7 @@ EXPORT_SYMBOL(__check_sticky);
|
|
* 11. 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;
|
|
@@ -2776,7 +2801,7 @@ static int may_delete(struct inode *dir,
|
|
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))
|
|
@@ -2808,7 +2833,7 @@ static int may_delete(struct inode *dir,
|
|
* 4. We should have write and exec permissions on dir
|
|
* 5. 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)
|
|
{
|
|
struct user_namespace *s_user_ns;
|
|
audit_inode_child(dir, child, AUDIT_TYPE_CHILD_CREATE);
|
|
@@ -2820,7 +2845,7 @@ static inline int may_create(struct inod
|
|
if (!kuid_has_mapping(s_user_ns, current_fsuid()) ||
|
|
!kgid_has_mapping(s_user_ns, current_fsgid()))
|
|
return -EOVERFLOW;
|
|
- return inode_permission(dir, MAY_WRITE | MAY_EXEC);
|
|
+ return inode_permission2(mnt, dir, MAY_WRITE | MAY_EXEC);
|
|
}
|
|
|
|
/*
|
|
@@ -2867,10 +2892,10 @@ void unlock_rename(struct dentry *p1, st
|
|
}
|
|
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;
|
|
|
|
@@ -2886,6 +2911,13 @@ int vfs_create(struct inode *dir, struct
|
|
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);
|
|
|
|
bool may_open_dev(const struct path *path)
|
|
@@ -2897,6 +2929,7 @@ bool may_open_dev(const struct path *pat
|
|
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;
|
|
|
|
@@ -2921,7 +2954,7 @@ static int may_open(struct path *path, i
|
|
break;
|
|
}
|
|
|
|
- error = inode_permission(inode, MAY_OPEN | acc_mode);
|
|
+ error = inode_permission2(mnt, inode, MAY_OPEN | acc_mode);
|
|
if (error)
|
|
return error;
|
|
|
|
@@ -2956,7 +2989,7 @@ static int handle_truncate(struct file *
|
|
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);
|
|
}
|
|
@@ -2983,7 +3016,7 @@ static int may_o_create(const struct pat
|
|
!kgid_has_mapping(s_user_ns, current_fsgid()))
|
|
return -EOVERFLOW;
|
|
|
|
- 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;
|
|
|
|
@@ -3384,6 +3417,11 @@ opened:
|
|
error = open_check_o_direct(file);
|
|
if (!error)
|
|
error = ima_file_check(file, op->acc_mode, *opened);
|
|
+#ifdef CONFIG_FILE_INTEGRITY
|
|
+ error = fivm_open_verify(file, nd->name->name, op->acc_mode);
|
|
+ if (error)
|
|
+ goto out;
|
|
+#endif
|
|
if (!error && will_truncate)
|
|
error = handle_truncate(file);
|
|
out:
|
|
@@ -3414,7 +3452,7 @@ static int do_tmpfile(struct nameidata *
|
|
goto out;
|
|
dir = path.dentry->d_inode;
|
|
/* we want directory to be writable */
|
|
- error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
|
|
+ error = inode_permission2(nd->path.mnt, dir, MAY_WRITE | MAY_EXEC);
|
|
if (error)
|
|
goto out2;
|
|
if (!dir->i_op->tmpfile) {
|
|
@@ -3667,9 +3705,9 @@ inline struct dentry *user_path_create(i
|
|
}
|
|
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;
|
|
@@ -3693,6 +3731,12 @@ int vfs_mknod(struct inode *dir, struct
|
|
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)
|
|
@@ -3735,12 +3779,12 @@ 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);
|
|
if (!error)
|
|
ima_post_path_mknod(dentry);
|
|
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:
|
|
@@ -3761,9 +3805,9 @@ SYSCALL_DEFINE3(mknod, const char __user
|
|
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)
|
|
@@ -3785,6 +3829,12 @@ int vfs_mkdir(struct inode *dir, struct
|
|
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)
|
|
@@ -3803,7 +3853,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;
|
|
@@ -3817,9 +3867,9 @@ SYSCALL_DEFINE2(mkdir, const char __user
|
|
return sys_mkdirat(AT_FDCWD, pathname, mode);
|
|
}
|
|
|
|
-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;
|
|
@@ -3854,6 +3904,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)
|
|
@@ -3899,7 +3955,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:
|
|
@@ -3938,10 +3994,10 @@ SYSCALL_DEFINE1(rmdir, const char __user
|
|
* 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;
|
|
@@ -3976,6 +4032,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);
|
|
|
|
/*
|
|
@@ -4023,7 +4085,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);
|
|
}
|
|
@@ -4073,9 +4135,9 @@ SYSCALL_DEFINE1(unlink, const char __use
|
|
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;
|
|
@@ -4092,6 +4154,12 @@ int vfs_symlink(struct inode *dir, struc
|
|
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,
|
|
@@ -4114,7 +4182,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;
|
|
@@ -4149,7 +4217,7 @@ SYSCALL_DEFINE2(symlink, const char __us
|
|
* 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;
|
|
@@ -4158,7 +4226,7 @@ int vfs_link(struct dentry *old_dentry,
|
|
if (!inode)
|
|
return -ENOENT;
|
|
|
|
- error = may_create(dir, new_dentry);
|
|
+ error = may_create(mnt, dir, new_dentry);
|
|
if (error)
|
|
return error;
|
|
|
|
@@ -4208,6 +4276,12 @@ int vfs_link(struct dentry *old_dentry,
|
|
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);
|
|
|
|
/*
|
|
@@ -4263,7 +4337,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) {
|
|
@@ -4338,7 +4412,8 @@ SYSCALL_DEFINE2(link, const char __user
|
|
* ->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)
|
|
{
|
|
@@ -4357,19 +4432,19 @@ int vfs_rename(struct inode *old_dir, st
|
|
if (d_real_inode(old_dentry) == d_real_inode(new_dentry))
|
|
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;
|
|
@@ -4383,12 +4458,12 @@ int vfs_rename(struct inode *old_dir, st
|
|
*/
|
|
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;
|
|
}
|
|
@@ -4465,6 +4540,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,
|
|
@@ -4578,7 +4661,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:
|
|
@@ -4623,7 +4706,7 @@ SYSCALL_DEFINE2(rename, const char __use
|
|
|
|
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;
|
|
|