diff mbox

[v3,032/110] namei: introduce nameidata->link

Message ID 1431367690-5223-32-git-send-email-viro@ZenIV.linux.org.uk (mailing list archive)
State New, archived
Headers show

Commit Message

Al Viro May 11, 2015, 6:06 p.m. UTC
From: Al Viro <viro@zeniv.linux.org.uk>

shares space with nameidata->next, walk_component() et.al. store
the struct path of symlink instead of returning it into a variable
passed by caller.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/namei.c | 62 ++++++++++++++++++++++++++++++++++----------------------------
 1 file changed, 34 insertions(+), 28 deletions(-)
diff mbox

Patch

diff --git a/fs/namei.c b/fs/namei.c
index 2ffb4af..06c3e4a 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -494,7 +494,10 @@  EXPORT_SYMBOL(path_put);
 
 struct nameidata {
 	struct path	path;
-	struct qstr	last;
+	union {
+		struct qstr	last;
+		struct path	link;
+	};
 	struct path	root;
 	struct inode	*inode; /* path.dentry.d_inode */
 	unsigned int	flags;
@@ -1559,8 +1562,9 @@  static inline int should_follow_link(struct dentry *dentry, int follow)
 	return unlikely(d_is_symlink(dentry)) ? follow : 0;
 }
 
-static int walk_component(struct nameidata *nd, struct path *path, int follow)
+static int walk_component(struct nameidata *nd, int follow)
 {
+	struct path path;
 	struct inode *inode;
 	int err;
 	/*
@@ -1570,38 +1574,39 @@  static int walk_component(struct nameidata *nd, struct path *path, int follow)
 	 */
 	if (unlikely(nd->last_type != LAST_NORM))
 		return handle_dots(nd, nd->last_type);
-	err = lookup_fast(nd, path, &inode);
+	err = lookup_fast(nd, &path, &inode);
 	if (unlikely(err)) {
 		if (err < 0)
 			goto out_err;
 
-		err = lookup_slow(nd, path);
+		err = lookup_slow(nd, &path);
 		if (err < 0)
 			goto out_err;
 
-		inode = path->dentry->d_inode;
+		inode = path.dentry->d_inode;
 		err = -ENOENT;
-		if (d_is_negative(path->dentry))
+		if (d_is_negative(path.dentry))
 			goto out_path_put;
 	}
 
-	if (should_follow_link(path->dentry, follow)) {
+	if (should_follow_link(path.dentry, follow)) {
 		if (nd->flags & LOOKUP_RCU) {
-			if (unlikely(nd->path.mnt != path->mnt ||
-				     unlazy_walk(nd, path->dentry))) {
+			if (unlikely(nd->path.mnt != path.mnt ||
+				     unlazy_walk(nd, path.dentry))) {
 				err = -ECHILD;
 				goto out_err;
 			}
 		}
-		BUG_ON(inode != path->dentry->d_inode);
+		BUG_ON(inode != path.dentry->d_inode);
+		nd->link = path;
 		return 1;
 	}
-	path_to_nameidata(path, nd);
+	path_to_nameidata(&path, nd);
 	nd->inode = inode;
 	return 0;
 
 out_path_put:
-	path_to_nameidata(path, nd);
+	path_to_nameidata(&path, nd);
 out_err:
 	terminate_walk(nd);
 	return err;
@@ -1614,12 +1619,12 @@  out_err:
  * Without that kind of total limit, nasty chains of consecutive
  * symlinks can cause almost arbitrarily long lookups.
  */
-static inline int nested_symlink(struct path *path, struct nameidata *nd)
+static inline int nested_symlink(struct nameidata *nd)
 {
 	int res;
 
 	if (unlikely(current->link_count >= MAX_NESTED_LINKS)) {
-		path_put_conditional(path, nd);
+		path_put_conditional(&nd->link, nd);
 		path_put(&nd->path);
 		return -ELOOP;
 	}
@@ -1629,13 +1634,13 @@  static inline int nested_symlink(struct path *path, struct nameidata *nd)
 	current->link_count++;
 
 	do {
-		struct path link = *path;
+		struct path link = nd->link;
 		void *cookie;
 
 		res = follow_link(&link, nd, &cookie);
 		if (res)
 			break;
-		res = walk_component(nd, path, LOOKUP_FOLLOW);
+		res = walk_component(nd, LOOKUP_FOLLOW);
 		put_link(nd, &link, cookie);
 	} while (res > 0);
 
@@ -1770,7 +1775,6 @@  static inline u64 hash_name(const char *name)
  */
 static int link_path_walk(const char *name, struct nameidata *nd)
 {
-	struct path next;
 	int err;
 	
 	while (*name=='/')
@@ -1830,17 +1834,17 @@  static int link_path_walk(const char *name, struct nameidata *nd)
 		if (!*name)
 			return 0;
 
-		err = walk_component(nd, &next, LOOKUP_FOLLOW);
+		err = walk_component(nd, LOOKUP_FOLLOW);
 		if (err < 0)
 			return err;
 
 		if (err) {
-			err = nested_symlink(&next, nd);
+			err = nested_symlink(nd);
 			if (err)
 				return err;
 		}
 		if (!d_can_lookup(nd->path.dentry)) {
-			err = -ENOTDIR; 
+			err = -ENOTDIR;
 			break;
 		}
 	}
@@ -1960,20 +1964,19 @@  static void path_cleanup(struct nameidata *nd)
 		fput(nd->base);
 }
 
-static inline int lookup_last(struct nameidata *nd, struct path *path)
+static inline int lookup_last(struct nameidata *nd)
 {
 	if (nd->last_type == LAST_NORM && nd->last.name[nd->last.len])
 		nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
 
 	nd->flags &= ~LOOKUP_PARENT;
-	return walk_component(nd, path, nd->flags & LOOKUP_FOLLOW);
+	return walk_component(nd, nd->flags & LOOKUP_FOLLOW);
 }
 
 /* Returns 0 and nd will be valid on success; Retuns error, otherwise. */
 static int path_lookupat(int dfd, const struct filename *name,
 				unsigned int flags, struct nameidata *nd)
 {
-	struct path path;
 	int err;
 
 	/*
@@ -1992,10 +1995,10 @@  static int path_lookupat(int dfd, const struct filename *name,
 	 */
 	err = path_init(dfd, name, flags, nd);
 	if (!err && !(flags & LOOKUP_PARENT)) {
-		err = lookup_last(nd, &path);
+		err = lookup_last(nd);
 		while (err > 0) {
 			void *cookie;
-			struct path link = path;
+			struct path link = nd->link;
 			err = may_follow_link(&link, nd);
 			if (unlikely(err))
 				break;
@@ -2003,7 +2006,7 @@  static int path_lookupat(int dfd, const struct filename *name,
 			err = follow_link(&link, nd, &cookie);
 			if (err)
 				break;
-			err = lookup_last(nd, &path);
+			err = lookup_last(nd);
 			put_link(nd, &link, cookie);
 		}
 	}
@@ -2312,8 +2315,10 @@  done:
 	}
 	path->dentry = dentry;
 	path->mnt = nd->path.mnt;
-	if (should_follow_link(dentry, nd->flags & LOOKUP_FOLLOW))
+	if (should_follow_link(dentry, nd->flags & LOOKUP_FOLLOW)) {
+		nd->link = *path;
 		return 1;
+	}
 	mntget(path->mnt);
 	follow_mount(path);
 	error = 0;
@@ -3040,6 +3045,7 @@  finish_lookup:
 			}
 		}
 		BUG_ON(inode != path->dentry->d_inode);
+		nd->link = *path;
 		return 1;
 	}
 
@@ -3228,7 +3234,7 @@  static struct file *path_openat(int dfd, struct filename *pathname,
 
 	error = do_last(nd, &path, file, op, &opened, pathname);
 	while (unlikely(error > 0)) { /* trailing symlink */
-		struct path link = path;
+		struct path link = nd->link;
 		void *cookie;
 		error = may_follow_link(&link, nd);
 		if (unlikely(error))