summaryrefslogtreecommitdiffstats
path: root/fs/namei.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/namei.c')
-rw-r--r--fs/namei.c66
1 files changed, 48 insertions, 18 deletions
diff --git a/fs/namei.c b/fs/namei.c
index a3cd028e8a9b3..a09419379f5db 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -559,9 +559,10 @@ static int __nd_alloc_stack(struct nameidata *nd)
static bool path_connected(const struct path *path)
{
struct vfsmount *mnt = path->mnt;
+ struct super_block *sb = mnt->mnt_sb;
- /* Only bind mounts can have disconnected paths */
- if (mnt->mnt_root == mnt->mnt_sb->s_root)
+ /* Bind mounts and multi-root filesystems can have disconnected paths */
+ if (!(sb->s_iflags & SB_I_MULTIROOT) && (mnt->mnt_root == sb->s_root))
return true;
return is_subdir(path->dentry, mnt->mnt_root);
@@ -3721,8 +3722,8 @@ static int may_mknod(umode_t mode)
}
}
-SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode,
- unsigned, dev)
+long do_mknodat(int dfd, const char __user *filename, umode_t mode,
+ unsigned int dev)
{
struct dentry *dentry;
struct path path;
@@ -3765,9 +3766,15 @@ out:
return error;
}
+SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode,
+ unsigned int, dev)
+{
+ return do_mknodat(dfd, filename, mode, dev);
+}
+
SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, dev)
{
- return sys_mknodat(AT_FDCWD, filename, mode, dev);
+ return do_mknodat(AT_FDCWD, filename, mode, dev);
}
int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
@@ -3796,7 +3803,7 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
}
EXPORT_SYMBOL(vfs_mkdir);
-SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode)
+long do_mkdirat(int dfd, const char __user *pathname, umode_t mode)
{
struct dentry *dentry;
struct path path;
@@ -3821,9 +3828,14 @@ retry:
return error;
}
+SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode)
+{
+ return do_mkdirat(dfd, pathname, mode);
+}
+
SYSCALL_DEFINE2(mkdir, const char __user *, pathname, umode_t, mode)
{
- return sys_mkdirat(AT_FDCWD, pathname, mode);
+ return do_mkdirat(AT_FDCWD, pathname, mode);
}
int vfs_rmdir(struct inode *dir, struct dentry *dentry)
@@ -3865,7 +3877,7 @@ out:
}
EXPORT_SYMBOL(vfs_rmdir);
-static long do_rmdir(int dfd, const char __user *pathname)
+long do_rmdir(int dfd, const char __user *pathname)
{
int error = 0;
struct filename *name;
@@ -4101,8 +4113,8 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
}
EXPORT_SYMBOL(vfs_symlink);
-SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
- int, newdfd, const char __user *, newname)
+long do_symlinkat(const char __user *oldname, int newdfd,
+ const char __user *newname)
{
int error;
struct filename *from;
@@ -4132,9 +4144,15 @@ out_putname:
return error;
}
+SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
+ int, newdfd, const char __user *, newname)
+{
+ return do_symlinkat(oldname, newdfd, newname);
+}
+
SYSCALL_DEFINE2(symlink, const char __user *, oldname, const char __user *, newname)
{
- return sys_symlinkat(oldname, AT_FDCWD, newname);
+ return do_symlinkat(oldname, AT_FDCWD, newname);
}
/**
@@ -4226,8 +4244,8 @@ EXPORT_SYMBOL(vfs_link);
* with linux 2.0, and to avoid hard-linking to directories
* and other special files. --ADM
*/
-SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
- int, newdfd, const char __user *, newname, int, flags)
+int do_linkat(int olddfd, const char __user *oldname, int newdfd,
+ const char __user *newname, int flags)
{
struct dentry *new_dentry;
struct path old_path, new_path;
@@ -4291,9 +4309,15 @@ out:
return error;
}
+SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
+ int, newdfd, const char __user *, newname, int, flags)
+{
+ return do_linkat(olddfd, oldname, newdfd, newname, flags);
+}
+
SYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname)
{
- return sys_linkat(AT_FDCWD, oldname, AT_FDCWD, newname, 0);
+ return do_linkat(AT_FDCWD, oldname, AT_FDCWD, newname, 0);
}
/**
@@ -4471,8 +4495,8 @@ out:
}
EXPORT_SYMBOL(vfs_rename);
-SYSCALL_DEFINE5(renameat2, int, olddfd, const char __user *, oldname,
- int, newdfd, const char __user *, newname, unsigned int, flags)
+static int do_renameat2(int olddfd, const char __user *oldname, int newdfd,
+ const char __user *newname, unsigned int flags)
{
struct dentry *old_dentry, *new_dentry;
struct dentry *trap;
@@ -4614,15 +4638,21 @@ exit:
return error;
}
+SYSCALL_DEFINE5(renameat2, int, olddfd, const char __user *, oldname,
+ int, newdfd, const char __user *, newname, unsigned int, flags)
+{
+ return do_renameat2(olddfd, oldname, newdfd, newname, flags);
+}
+
SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
int, newdfd, const char __user *, newname)
{
- return sys_renameat2(olddfd, oldname, newdfd, newname, 0);
+ return do_renameat2(olddfd, oldname, newdfd, newname, 0);
}
SYSCALL_DEFINE2(rename, const char __user *, oldname, const char __user *, newname)
{
- return sys_renameat2(AT_FDCWD, oldname, AT_FDCWD, newname, 0);
+ return do_renameat2(AT_FDCWD, oldname, AT_FDCWD, newname, 0);
}
int vfs_whiteout(struct inode *dir, struct dentry *dentry)