[PATCH 03/10] Split do_linkat() out of sys_linkat

Matt Helsley matthltc at us.ibm.com
Mon Feb 28 20:05:09 PST 2011


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 |   77 +++++++++++++++++++++++++++++++++++++++---------------------
 1 files changed, 50 insertions(+), 27 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index b6b7359..52aa274 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2440,6 +2440,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
@@ -2452,7 +2497,6 @@ 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;
@@ -2465,37 +2509,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



More information about the Containers mailing list