[Devel] [PATCH 4/6] [RFC] Split do_linkat() out of sys_linkat
Matt Helsley
matthltc at us.ibm.com
Thu Sep 23 14:53:30 PDT 2010
Separate the __user pathname handling from the bulk of the syscall.
Since we're doing this to enable relinking of unlinked files by
sys_checkpoint and not sys_linkat we're not using a sys-wrapper.
Signed-off-by: Matt Helsley <matthltc at us.ibm.com>
Cc: containers at lists.linux-foundation.org
Cc: Oren Laadan <orenl at cs.columbia.edu>
Cc: Amir Goldstein <amir73il at users.sf.net>
Cc: linux-fsdevel at vger.kernel.org
Cc: Al Viro <viro at zeniv.linux.org.uk>
Cc: Christoph Hellwig <hch at infradead.org>
Cc: Jamie Lokier <jamie at shareable.org>
---
fs/namei.c | 79 ++++++++++++++++++++++++++++++++++++++---------------------
1 files changed, 51 insertions(+), 28 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index eb279e3..8c9663d 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2456,6 +2456,51 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
return error;
}
+/* If the file has been unlinked then old_dentry doesn't match old_path */
+static int do_linkat(struct path *old_path, struct dentry *old_dentry,
+ struct nameidata *nd, int flags)
+{
+ struct dentry *new_dentry;
+ int error = -EXDEV;
+
+ if (old_path->mnt != nd->path.mnt)
+ goto out;
+ new_dentry = lookup_create(nd, 0);
+ error = PTR_ERR(new_dentry);
+ if (IS_ERR(new_dentry))
+ goto out_unlock;
+ error = mnt_want_write(nd->path.mnt);
+ if (error)
+ goto out_dput;
+ error = security_path_link(old_dentry, &nd->path, new_dentry);
+ if (error)
+ goto out_drop_write;
+ error = vfs_link(old_dentry, nd->path.dentry->d_inode, new_dentry);
+out_drop_write:
+ mnt_drop_write(nd->path.mnt);
+out_dput:
+ dput(new_dentry);
+out_unlock:
+ mutex_unlock(&nd->path.dentry->d_inode->i_mutex);
+out:
+ return error;
+}
+
+static int do_kern_linkat(struct path *old_path, struct dentry *old_dentry,
+ int newdfd, const char * newname, int flags)
+{
+ struct nameidata nd;
+ int error;
+
+ error = do_path_lookup(newdfd, newname, LOOKUP_PARENT, &nd);
+ if (error)
+ goto out;
+ error = do_linkat(old_path, old_dentry, &nd, flags);
+ path_put(&nd.path);
+out:
+ return error;
+}
+
/*
* Hardlinks are often used in delicate situations. We avoid
* security-related surprises by not following symlinks on the
@@ -2468,11 +2513,10 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
int, newdfd, const char __user *, newname, int, flags)
{
- struct dentry *new_dentry;
struct nameidata nd;
struct path old_path;
- int error;
char *to;
+ int error;
if ((flags & ~AT_SYMLINK_FOLLOW) != 0)
return -EINVAL;
@@ -2481,37 +2525,16 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
flags & AT_SYMLINK_FOLLOW ? LOOKUP_FOLLOW : 0,
&old_path);
if (error)
- return error;
-
- error = user_path_parent(newdfd, newname, &nd, &to);
- if (error)
goto out;
- error = -EXDEV;
- if (old_path.mnt != nd.path.mnt)
- goto out_release;
- new_dentry = lookup_create(&nd, 0);
- error = PTR_ERR(new_dentry);
- if (IS_ERR(new_dentry))
- goto out_unlock;
- error = mnt_want_write(nd.path.mnt);
- if (error)
- goto out_dput;
- error = security_path_link(old_path.dentry, &nd.path, new_dentry);
+ error = user_path_parent(newdfd, newname, &nd, &to);
if (error)
- goto out_drop_write;
- error = vfs_link(old_path.dentry, nd.path.dentry->d_inode, new_dentry);
-out_drop_write:
- mnt_drop_write(nd.path.mnt);
-out_dput:
- dput(new_dentry);
-out_unlock:
- mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
-out_release:
+ goto out_put_old_path;
+ error = do_linkat(&old_path, old_path.dentry, &nd, flags);
path_put(&nd.path);
putname(to);
-out:
+out_put_old_path:
path_put(&old_path);
-
+out:
return error;
}
--
1.6.3.3
_______________________________________________
Containers mailing list
Containers at lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/containers
More information about the Devel
mailing list