public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Maneesh Soni <maneesh@in.ibm.com>
To: Paul Menage <pmenage@ensim.com>
Cc: linux-kernel@vger.kernel.org, viro@math.psu.edu
Subject: Re: [RFC] link_path_walk cleanup
Date: Mon, 29 Apr 2002 10:49:33 +0530	[thread overview]
Message-ID: <20020429104933.O31039@in.ibm.com> (raw)
In-Reply-To: <E171DGU-0003m7-00@pmenage-dt.ensim.com>

On Fri, Apr 26, 2002 at 02:28:26PM -0700, Paul Menage wrote:
> 
> Hi Maneesh,
> 
> The handling of '/' in path_walk() and vfs_follow_link() is broken - if
> the pathname consists entirely of  '/' characters, then lookup_parent
> returns the base immediately without setting nd->last. If there's more
> than one '/', then the check for looking up '/' won't be triggered, and
> walk_one() will be called with an undefined nd->last.
> [..]

Hi Paul,

Thanks for pointing it. The corrected patch is appended. 

Regards,
Maneesh

-- 
Maneesh Soni
IBM Linux Technology Center, 
IBM India Software Lab, Bangalore.
Phone: +91-80-5044999 email: maneesh@in.ibm.com
http://lse.sourceforge.net/locking/rcupdate.html


diff -urN linux-2.5.10/fs/namei.c linux-2.5.10-lpw/fs/namei.c
--- linux-2.5.10/fs/namei.c	Wed Apr 24 12:45:16 2002
+++ linux-2.5.10-lpw/fs/namei.c	Mon Apr 29 08:42:05 2002
@@ -442,6 +442,95 @@
 		;
 }
 
+	
+/* Big routine.. not supposed to be inlined but stack usage has to be limited
+ * no other choice
+ */
+static inline int walk_one(struct nameidata *nd)
+{
+	int err = 0;
+	struct dentry * dentry;
+	struct inode * inode;
+	
+	/*
+	 * "." and ".." are special - ".." especially so because it has
+	 * to be able to know about the current root directory and
+	 * parent relationships.
+	 */
+	if (nd->last.name[0] == '.') switch (nd->last.len) {
+		default:
+			break;
+		case 2:	
+			if (nd->last.name[1] != '.')
+				break;
+			follow_dotdot(nd);
+			inode = nd->dentry->d_inode;
+			/* fallthrough */
+		case 1:
+			return 0;
+	}
+	/*
+	 * See if the low-level filesystem might want
+	 * to use its own hash..
+	 */
+	if (nd->dentry->d_op && nd->dentry->d_op->d_hash) {
+		err = nd->dentry->d_op->d_hash(nd->dentry, &nd->last);
+		if (err < 0) 
+			goto out_path_release;
+	}
+
+	/* This does the actual lookups.. */
+	dentry = cached_lookup(nd->dentry, &nd->last, 
+			(nd->flags & LOOKUP_LAST) ? 0 : LOOKUP_CONTINUE);
+	if (!dentry) {
+		dentry = real_lookup(nd->dentry, &nd->last, 
+			    (nd->flags & LOOKUP_LAST) ? 0 : LOOKUP_CONTINUE);
+		err = PTR_ERR(dentry);
+		if (IS_ERR(dentry)) 
+			goto out_path_release;
+	}
+	/* Check mountpoints.. */
+	while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry))
+		;
+
+	inode = dentry->d_inode;
+	if ((nd->flags & LOOKUP_LAST) && !(nd->flags & LOOKUP_FOLLOW)) {
+		dput(nd->dentry);
+		nd->dentry = dentry;
+		goto do_not_follow;
+	}
+
+	if (inode && inode->i_op && inode->i_op->follow_link) {
+		err = do_follow_link(dentry, nd);
+		dput(dentry);
+		if (err)
+			return err;
+		inode = nd->dentry->d_inode;
+	} else {
+		dput(nd->dentry);
+		nd->dentry = dentry;
+	}
+
+do_not_follow:
+	err = -ENOENT;
+	if (!inode) 
+		goto out_path_release;
+
+	if ((nd->flags & LOOKUP_LAST) && !(nd->flags & LOOKUP_DIRECTORY))
+			return 0;
+
+	err = -ENOTDIR; 
+	if (!inode->i_op || !inode->i_op->lookup) 
+		goto out_path_release;
+
+	return 0;
+
+out_path_release:
+	path_release(nd);
+
+	return err;
+}
+
 /*
  * Name resolution.
  *
@@ -450,21 +539,22 @@
  *
  * We expect 'base' to be positive and a directory.
  */
-int link_path_walk(const char * name, struct nameidata *nd)
+int lookup_parent(const char * name, struct nameidata *nd)
 {
 	struct dentry *dentry;
 	struct inode *inode;
-	int err;
-	unsigned int lookup_flags = nd->flags;
+	int err = 0;
 
 	while (*name=='/')
 		name++;
-	if (!*name)
+	if (!*name) {
+		nd->last = (struct qstr) { name : ".", len : 1, hash : 0 };
 		goto return_base;
+	}
 
 	inode = nd->dentry->d_inode;
 	if (current->link_count)
-		lookup_flags = LOOKUP_FOLLOW;
+		nd->flags = LOOKUP_FOLLOW;
 
 	/* At this point we know we have a real path component. */
 	for(;;) {
@@ -488,7 +578,8 @@
 		} while (c && (c != '/'));
 		this.len = name - (const char *) this.name;
 		this.hash = end_name_hash(hash);
-
+		
+		nd->last = this;
 		/* remove trailing slashes? */
 		if (!c)
 			goto last_component;
@@ -496,150 +587,49 @@
 		if (!*name)
 			goto last_with_slashes;
 
-		/*
-		 * "." and ".." are special - ".." especially so because it has
-		 * to be able to know about the current root directory and
-		 * parent relationships.
-		 */
-		if (this.name[0] == '.') switch (this.len) {
-			default:
-				break;
-			case 2:	
-				if (this.name[1] != '.')
-					break;
-				follow_dotdot(nd);
-				inode = nd->dentry->d_inode;
-				/* fallthrough */
-			case 1:
-				continue;
-		}
-		/*
-		 * See if the low-level filesystem might want
-		 * to use its own hash..
-		 */
-		if (nd->dentry->d_op && nd->dentry->d_op->d_hash) {
-			err = nd->dentry->d_op->d_hash(nd->dentry, &this);
-			if (err < 0)
-				break;
-		}
-		/* This does the actual lookups.. */
-		dentry = cached_lookup(nd->dentry, &this, LOOKUP_CONTINUE);
-		if (!dentry) {
-			dentry = real_lookup(nd->dentry, &this, LOOKUP_CONTINUE);
-			err = PTR_ERR(dentry);
-			if (IS_ERR(dentry))
-				break;
-		}
-		/* Check mountpoints.. */
-		while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry))
-			;
-
-		err = -ENOENT;
-		inode = dentry->d_inode;
-		if (!inode)
-			goto out_dput;
-		err = -ENOTDIR; 
-		if (!inode->i_op)
-			goto out_dput;
+		if ((err = walk_one(nd)) < 0)
+			return err;
 
-		if (inode->i_op->follow_link) {
-			err = do_follow_link(dentry, nd);
-			dput(dentry);
-			if (err)
-				goto return_err;
-			err = -ENOENT;
-			inode = nd->dentry->d_inode;
-			if (!inode)
-				break;
-			err = -ENOTDIR; 
-			if (!inode->i_op)
-				break;
-		} else {
-			dput(nd->dentry);
-			nd->dentry = dentry;
-		}
-		err = -ENOTDIR; 
-		if (!inode->i_op->lookup)
-			break;
-		continue;
+		inode = nd->dentry->d_inode;
+
+		continue; 
 		/* here ends the main loop */
 
 last_with_slashes:
-		lookup_flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
+		nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
 last_component:
-		if (lookup_flags & LOOKUP_PARENT)
-			goto lookup_parent;
-		if (this.name[0] == '.') switch (this.len) {
-			default:
-				break;
-			case 2:	
-				if (this.name[1] != '.')
-					break;
-				follow_dotdot(nd);
-				inode = nd->dentry->d_inode;
-				/* fallthrough */
-			case 1:
+		nd->flags |= LOOKUP_LAST;
+		
+		if (nd->flags & LOOKUP_PARENT) {
+		
+			/* stop at parent of the last component */
+			nd->last_type = LAST_NORM;
+			if (this.name[0] != '.')
 				goto return_base;
+			if (this.len == 1)
+				nd->last_type = LAST_DOT;
+			else if (this.len == 2 && this.name[1] == '.')
+				nd->last_type = LAST_DOTDOT;
 		}
-		if (nd->dentry->d_op && nd->dentry->d_op->d_hash) {
-			err = nd->dentry->d_op->d_hash(nd->dentry, &this);
-			if (err < 0)
-				break;
-		}
-		dentry = cached_lookup(nd->dentry, &this, 0);
-		if (!dentry) {
-			dentry = real_lookup(nd->dentry, &this, 0);
-			err = PTR_ERR(dentry);
-			if (IS_ERR(dentry))
-				break;
-		}
-		while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry))
-			;
-		inode = dentry->d_inode;
-		if ((lookup_flags & LOOKUP_FOLLOW)
-		    && inode && inode->i_op && inode->i_op->follow_link) {
-			err = do_follow_link(dentry, nd);
-			dput(dentry);
-			if (err)
-				goto return_err;
-			inode = nd->dentry->d_inode;
-		} else {
-			dput(nd->dentry);
-			nd->dentry = dentry;
-		}
-		err = -ENOENT;
-		if (!inode)
-			break;
-		if (lookup_flags & LOOKUP_DIRECTORY) {
-			err = -ENOTDIR; 
-			if (!inode->i_op || !inode->i_op->lookup)
-				break;
-		}
-		goto return_base;
-lookup_parent:
-		nd->last = this;
-		nd->last_type = LAST_NORM;
-		if (this.name[0] != '.')
-			goto return_base;
-		if (this.len == 1)
-			nd->last_type = LAST_DOT;
-		else if (this.len == 2 && this.name[1] == '.')
-			nd->last_type = LAST_DOTDOT;
 return_base:
 		return 0;
-out_dput:
-		dput(dentry);
-		break;
 	}
 	path_release(nd);
-return_err:
 	return err;
 }
 
 int path_walk(const char * name, struct nameidata *nd)
 {
+	int err;
+	
 	current->total_link_count = 0;
-	return link_path_walk(name, nd);
+	err = lookup_parent(name, nd);
+
+	/* handle last component if needed */
+	if (!err && !(nd->flags & LOOKUP_PARENT)) 
+		err = walk_one(nd); 
+
+	return err;
 }
 
 /* SMP-safe */
@@ -1922,7 +1912,13 @@
 			/* weird __emul_prefix() stuff did it */
 			goto out;
 	}
-	res = link_path_walk(link, nd);
+
+	res = lookup_parent(link, nd);
+
+	/* handle last component if needed */
+	if (!res && !(nd->flags & LOOKUP_PARENT))
+		res = walk_one(nd);
+
 out:
 	if (current->link_count || res || nd->last_type!=LAST_NORM)
 		return res;
diff -urN linux-2.5.10/include/linux/fs.h linux-2.5.10-lpw/include/linux/fs.h
--- linux-2.5.10/include/linux/fs.h	Fri Apr 26 17:12:19 2002
+++ linux-2.5.10-lpw/include/linux/fs.h	Fri Apr 26 16:48:48 2002
@@ -1392,6 +1392,7 @@
 #define LOOKUP_CONTINUE		(4)
 #define LOOKUP_PARENT		(16)
 #define LOOKUP_NOALT		(32)
+#define LOOKUP_LAST		(64)
 /*
  * Type of the last component on LOOKUP_PARENT
  */

  reply	other threads:[~2002-04-29  5:16 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-04-26 21:28 [RFC] link_path_walk cleanup Paul Menage
2002-04-29  5:19 ` Maneesh Soni [this message]
  -- strict thread matches above, loose matches on Subject: below --
2002-04-26 13:51 Maneesh Soni
2002-04-26 16:40 ` Andrew Morton
2002-04-26 17:26   ` Alexander Viro
2002-04-27  1:45     ` Denis Vlasenko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20020429104933.O31039@in.ibm.com \
    --to=maneesh@in.ibm.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=pmenage@ensim.com \
    --cc=viro@math.psu.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox