Module Name:    src
Committed By:   dholland
Date:           Sun Aug  9 07:27:54 UTC 2009

Modified Files:
        src/sys/kern: vfs_lookup.c

Log Message:
Begin splitting lookup() into more tractable pieces too.


To generate a diff of this commit:
cvs rdiff -u -r1.117 -r1.118 src/sys/kern/vfs_lookup.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/kern/vfs_lookup.c
diff -u src/sys/kern/vfs_lookup.c:1.117 src/sys/kern/vfs_lookup.c:1.118
--- src/sys/kern/vfs_lookup.c:1.117	Sun Aug  9 03:28:35 2009
+++ src/sys/kern/vfs_lookup.c	Sun Aug  9 07:27:54 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: vfs_lookup.c,v 1.117 2009/08/09 03:28:35 dholland Exp $	*/
+/*	$NetBSD: vfs_lookup.c,v 1.118 2009/08/09 07:27:54 dholland Exp $	*/
 
 /*
  * Copyright (c) 1982, 1986, 1989, 1993
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.117 2009/08/09 03:28:35 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.118 2009/08/09 07:27:54 dholland Exp $");
 
 #include "opt_magiclinks.h"
 
@@ -224,9 +224,22 @@
 	struct nameidata *ndp;
 	struct componentname *cnp;
 
+	/* used by the pieces of namei */
+	struct vnode *namei_startdir; /* The directory namei() starts from. */
+
+	/* used by the pieces of lookup */
+	int lookup_alldone;
+
+	int docache;			/* == 0 do not cache last component */
+	int rdonly;			/* lookup read-only flag bit */
 	struct vnode *dp;		/* the directory we are searching */
+	int slashes;
 };
 
+/* XXX reorder things to make this decl unnecessary */
+static int do_lookup(struct namei_state *state);
+
+
 /*
  * Initialize the namei working state.
  */
@@ -236,7 +249,14 @@
 	state->ndp = ndp;
 	state->cnp = &ndp->ni_cnd;
 
+	state->namei_startdir = NULL;
+
+	state->lookup_alldone = 0;
+
+	state->docache = 0;
+	state->rdonly = 0;
 	state->dp = NULL;
+	state->slashes = 0;
 }
 
 /*
@@ -248,7 +268,7 @@
 {
 	KASSERT(state->cnp == &state->ndp->ni_cnd);
 
-	//KASSERT(state->dp == NULL); 	// not yet
+	//KASSERT(state->namei_startdir == NULL); 	// not yet
 
 	/* nothing for now */
 	(void)state;
@@ -321,10 +341,10 @@
 	 */
 	cwdi = self->l_proc->p_cwdi;
 	rw_enter(&cwdi->cwdi_lock, RW_READER);
-	state->dp = cwdi->cwdi_rdir;
-	if (state->dp == NULL)
-		state->dp = rootvnode;
-	ndp->ni_rootdir = state->dp;
+	state->namei_startdir = cwdi->cwdi_rdir;
+	if (state->namei_startdir == NULL)
+		state->namei_startdir = rootvnode;
+	ndp->ni_rootdir = state->namei_startdir;
 
 	/*
 	 * Check if starting from root directory or current directory.
@@ -333,7 +353,7 @@
 		if (cnp->cn_flags & TRYEMULROOT) {
 			if (cnp->cn_flags & EMULROOTSET) {
 				/* Called from (eg) emul_find_interp() */
-				state->dp = ndp->ni_erootdir;
+				state->namei_startdir = ndp->ni_erootdir;
 			} else {
 				if (cwdi->cwdi_edir == NULL
 				    || (cnp->cn_pnbuf[1] == '.' 
@@ -341,20 +361,20 @@
 					   && cnp->cn_pnbuf[3] == '/')) {
 					ndp->ni_erootdir = NULL;
 				} else {
-					state->dp = cwdi->cwdi_edir;
-					ndp->ni_erootdir = state->dp;
+					state->namei_startdir = cwdi->cwdi_edir;
+					ndp->ni_erootdir = state->namei_startdir;
 				}
 			}
 		} else {
 			ndp->ni_erootdir = NULL;
 			if (cnp->cn_flags & NOCHROOT)
-				state->dp = ndp->ni_rootdir = rootvnode;
+				state->namei_startdir = ndp->ni_rootdir = rootvnode;
 		}
 	} else {
-		state->dp = cwdi->cwdi_cdir;
+		state->namei_startdir = cwdi->cwdi_cdir;
 		ndp->ni_erootdir = NULL;
 	}
-	VREF(state->dp);
+	VREF(state->namei_startdir);
 	rw_exit(&cwdi->cwdi_lock);
 
 	/*
@@ -381,7 +401,7 @@
 			ktrnamei(cnp->cn_pnbuf, ndp->ni_pathlen);
 	}
 
-	vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY);
+	vn_lock(state->namei_startdir, LK_EXCLUSIVE | LK_RETRY);
 
 	return 0;
 }
@@ -393,7 +413,7 @@
 static void
 namei_end(struct namei_state *state)
 {
-	vput(state->dp);
+	vput(state->namei_startdir);
 	PNBUF_PUT(state->cnp->cn_pnbuf);
 	//state->cnp->cn_pnbuf = NULL; // not yet (just in case) (XXX)
 }
@@ -474,23 +494,23 @@
 		cnp->cn_pnbuf[linklen] = '\0';
 	ndp->ni_pathlen += linklen;
 	vput(ndp->ni_vp);
-	state->dp = ndp->ni_dvp;
+	state->namei_startdir = ndp->ni_dvp;
 
 	/*
 	 * Check if root directory should replace current directory.
 	 */
 	if (cnp->cn_pnbuf[0] == '/') {
-		vput(state->dp);
+		vput(state->namei_startdir);
 		/* Keep absolute symbolic links inside emulation root */
-		state->dp = ndp->ni_erootdir;
-		if (state->dp == NULL || (cnp->cn_pnbuf[1] == '.' 
+		state->namei_startdir = ndp->ni_erootdir;
+		if (state->namei_startdir == NULL || (cnp->cn_pnbuf[1] == '.' 
 					  && cnp->cn_pnbuf[2] == '.'
 					  && cnp->cn_pnbuf[3] == '/')) {
 			ndp->ni_erootdir = NULL;
-			state->dp = ndp->ni_rootdir;
+			state->namei_startdir = ndp->ni_rootdir;
 		}
-		VREF(state->dp);
-		vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY);
+		VREF(state->namei_startdir);
+		vn_lock(state->namei_startdir, LK_EXCLUSIVE | LK_RETRY);
 	}
 
 	return 0;
@@ -519,13 +539,13 @@
 
 	/* Loop through symbolic links */
 	for (;;) {
-		if (!state->dp->v_mount) {
+		if (state->namei_startdir->v_mount == NULL) {
 			/* Give up if the directory is no longer mounted */
 			namei_end(state);
 			return (ENOENT);
 		}
 		cnp->cn_nameptr = cnp->cn_pnbuf;
-		ndp->ni_startdir = state->dp;
+		ndp->ni_startdir = state->namei_startdir;
 		error = lookup(ndp);
 		if (error != 0) {
 			/* XXX this should use namei_end() */
@@ -660,30 +680,33 @@
  *	return the answer in ni_vp, locked if LOCKLEAF set
  *	    if LOCKPARENT set, return locked parent in ni_dvp
  */
-int
-lookup(struct nameidata *ndp)
+
+/*
+ * Begin lookup().
+ */
+static int
+lookup_start(struct namei_state *state)
 {
 	const char *cp;			/* pointer into pathname argument */
-	struct vnode *dp = 0;		/* the directory we are searching */
-	struct vnode *tdp;		/* saved dp */
-	struct mount *mp;		/* mount table entry */
-	int docache;			/* == 0 do not cache last component */
-	int rdonly;			/* lookup read-only flag bit */
-	int error = 0;
-	int slashes;
-	struct componentname *cnp = &ndp->ni_cnd;
-	struct lwp *l = curlwp;
+
+	struct componentname *cnp = state->cnp;
+	struct nameidata *ndp = state->ndp;
+
+	KASSERT(cnp == &ndp->ni_cnd);
+
+	state->lookup_alldone = 0;
+	state->dp = NULL;
 
 	/*
 	 * Setup: break out flag bits into variables.
 	 */
-	docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
+	state->docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
 	if (cnp->cn_nameiop == DELETE)
-		docache = 0;
-	rdonly = cnp->cn_flags & RDONLY;
+		state->docache = 0;
+	state->rdonly = cnp->cn_flags & RDONLY;
 	ndp->ni_dvp = NULL;
 	cnp->cn_flags &= ~ISSYMLINK;
-	dp = ndp->ni_startdir;
+	state->dp = ndp->ni_startdir;
 	ndp->ni_startdir = NULLVP;
 
 	/*
@@ -698,10 +721,9 @@
 		ndp->ni_pathlen -= cp - cnp->cn_nameptr;
 		cnp->cn_nameptr = cp;
 
-		if (dp->v_type != VDIR) {
-			error = ENOTDIR;
-			vput(dp);
-			goto bad;
+		if (state->dp->v_type != VDIR) {
+			vput(state->dp);
+			return ENOTDIR;
 		}
 
 		/*
@@ -709,13 +731,28 @@
 		 * current node.
 		 */
 		if (cnp->cn_nameptr[0] == '\0') {
-			ndp->ni_vp = dp;
+			ndp->ni_vp = state->dp;
 			cnp->cn_flags |= ISLASTCN;
-			goto terminal;
+
+			/* bleh */
+			state->lookup_alldone = 1;
+			return 0;
 		}
 	}
 
-dirloop:
+	return 0;
+}
+
+static int
+lookup_parsepath(struct namei_state *state)
+{
+	const char *cp;			/* pointer into pathname argument */
+
+	struct componentname *cnp = state->cnp;
+	struct nameidata *ndp = state->ndp;
+
+	KASSERT(cnp == &ndp->ni_cnd);
+
 	/*
 	 * Search a new directory.
 	 *
@@ -732,10 +769,9 @@
 	cnp->cn_hash = namei_hash(cnp->cn_nameptr, &cp);
 	cnp->cn_namelen = cp - cnp->cn_nameptr;
 	if (cnp->cn_namelen > NAME_MAX) {
-		vput(dp);
-		error = ENAMETOOLONG;
+		vput(state->dp);
 		ndp->ni_dvp = NULL;
-		goto bad;
+		return ENAMETOOLONG;
 	}
 #ifdef NAMEI_DIAGNOSTIC
 	{ char c = *cp;
@@ -754,12 +790,12 @@
 		do {
 			cp++;
 		} while (*cp == '/');
-		slashes = cp - ndp->ni_next;
-		ndp->ni_pathlen -= slashes;
+		state->slashes = cp - ndp->ni_next;
+		ndp->ni_pathlen -= state->slashes;
 		ndp->ni_next = cp;
 		cnp->cn_flags |= REQUIREDIR;
 	} else {
-		slashes = 0;
+		state->slashes = 0;
 		cnp->cn_flags &= ~REQUIREDIR;
 	}
 	/*
@@ -767,7 +803,7 @@
 	 * a directory.  Cache all intervening lookups, but not the final one.
 	 */
 	if (*cp == '\0') {
-		if (docache)
+		if (state->docache)
 			cnp->cn_flags |= MAKEENTRY;
 		else
 			cnp->cn_flags &= ~MAKEENTRY;
@@ -782,6 +818,22 @@
 	else
 		cnp->cn_flags &= ~ISDOTDOT;
 
+	return 0;
+}
+
+static int
+lookup_once(struct namei_state *state)
+{
+	struct vnode *tdp;		/* saved dp */
+	struct mount *mp;		/* mount table entry */
+	struct lwp *l = curlwp;
+	int error;
+
+	struct componentname *cnp = state->cnp;
+	struct nameidata *ndp = state->ndp;
+
+	KASSERT(cnp == &ndp->ni_cnd);
+
 	/*
 	 * Handle "..": two special cases.
 	 * 1. If at root directory (e.g. after chroot)
@@ -800,18 +852,18 @@
 		struct proc *p = l->l_proc;
 
 		for (;;) {
-			if (dp == ndp->ni_rootdir || dp == rootvnode) {
-				ndp->ni_dvp = dp;
-				ndp->ni_vp = dp;
-				VREF(dp);
-				goto nextname;
+			if (state->dp == ndp->ni_rootdir || state->dp == rootvnode) {
+				ndp->ni_dvp = state->dp;
+				ndp->ni_vp = state->dp;
+				VREF(state->dp);
+				return 0;
 			}
 			if (ndp->ni_rootdir != rootvnode) {
 				int retval;
 
-				VOP_UNLOCK(dp, 0);
-				retval = vn_isunder(dp, ndp->ni_rootdir, l);
-				vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
+				VOP_UNLOCK(state->dp, 0);
+				retval = vn_isunder(state->dp, ndp->ni_rootdir, l);
+				vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY);
 				if (!retval) {
 				    /* Oops! We got out of jail! */
 				    log(LOG_WARNING,
@@ -820,24 +872,24 @@
 					p->p_pid, kauth_cred_geteuid(l->l_cred),
 					p->p_comm);
 				    /* Put us at the jail root. */
-				    vput(dp);
-				    dp = ndp->ni_rootdir;
-				    ndp->ni_dvp = dp;
-				    ndp->ni_vp = dp;
-				    VREF(dp);
-				    VREF(dp);
-				    vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
-				    goto nextname;
+				    vput(state->dp);
+				    state->dp = ndp->ni_rootdir;
+				    ndp->ni_dvp = state->dp;
+				    ndp->ni_vp = state->dp;
+				    VREF(state->dp);
+				    VREF(state->dp);
+				    vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY);
+				    return 0;
 				}
 			}
-			if ((dp->v_vflag & VV_ROOT) == 0 ||
+			if ((state->dp->v_vflag & VV_ROOT) == 0 ||
 			    (cnp->cn_flags & NOCROSSMOUNT))
 				break;
-			tdp = dp;
-			dp = dp->v_mount->mnt_vnodecovered;
+			tdp = state->dp;
+			state->dp = state->dp->v_mount->mnt_vnodecovered;
 			vput(tdp);
-			VREF(dp);
-			vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
+			VREF(state->dp);
+			vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY);
 		}
 	}
 
@@ -846,9 +898,9 @@
 	 * Again, our only vnode state is that "dp" is held and locked.
 	 */
 unionlookup:
-	ndp->ni_dvp = dp;
+	ndp->ni_dvp = state->dp;
 	ndp->ni_vp = NULL;
-	error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp);
+	error = VOP_LOOKUP(state->dp, &ndp->ni_vp, cnp);
 	if (error != 0) {
 #ifdef DIAGNOSTIC
 		if (ndp->ni_vp != NULL)
@@ -858,18 +910,18 @@
 		printf("not found\n");
 #endif /* NAMEI_DIAGNOSTIC */
 		if ((error == ENOENT) &&
-		    (dp->v_vflag & VV_ROOT) &&
-		    (dp->v_mount->mnt_flag & MNT_UNION)) {
-			tdp = dp;
-			dp = dp->v_mount->mnt_vnodecovered;
+		    (state->dp->v_vflag & VV_ROOT) &&
+		    (state->dp->v_mount->mnt_flag & MNT_UNION)) {
+			tdp = state->dp;
+			state->dp = state->dp->v_mount->mnt_vnodecovered;
 			vput(tdp);
-			VREF(dp);
-			vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
+			VREF(state->dp);
+			vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY);
 			goto unionlookup;
 		}
 
 		if (error != EJUSTRETURN)
-			goto bad;
+			return error;
 
 		/*
 		 * If this was not the last component, or there were trailing
@@ -877,17 +929,15 @@
 		 * then the name must exist.
 		 */
 		if ((cnp->cn_flags & (REQUIREDIR | CREATEDIR)) == REQUIREDIR) {
-			error = ENOENT;
-			goto bad;
+			return ENOENT;
 		}
 
 		/*
 		 * If creating and at end of pathname, then can consider
 		 * allowing file to be created.
 		 */
-		if (rdonly) {
-			error = EROFS;
-			goto bad;
+		if (state->rdonly) {
+			return EROFS;
 		}
 
 		/*
@@ -899,6 +949,7 @@
 			ndp->ni_startdir = ndp->ni_dvp;
 			VREF(ndp->ni_startdir);
 		}
+		state->lookup_alldone = 1;
 		return (0);
 	}
 #ifdef NAMEI_DIAGNOSTIC
@@ -911,17 +962,17 @@
 	 * the last component consumed.
 	 */
 	if (cnp->cn_consume > 0) {
-		ndp->ni_pathlen -= cnp->cn_consume - slashes;
-		ndp->ni_next += cnp->cn_consume - slashes;
+		ndp->ni_pathlen -= cnp->cn_consume - state->slashes;
+		ndp->ni_next += cnp->cn_consume - state->slashes;
 		cnp->cn_consume = 0;
 		if (ndp->ni_next[0] == '\0')
 			cnp->cn_flags |= ISLASTCN;
 	}
 
-	dp = ndp->ni_vp;
+	state->dp = ndp->ni_vp;
 
 	/*
-	 * "dp" and "ndp->ni_dvp" are both locked and held,
+	 * "state->dp" and "ndp->ni_dvp" are both locked and held,
 	 * and may be the same vnode.
 	 */
 
@@ -929,35 +980,74 @@
 	 * Check to see if the vnode has been mounted on;
 	 * if so find the root of the mounted file system.
 	 */
-	while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
+	while (state->dp->v_type == VDIR && (mp = state->dp->v_mountedhere) &&
 	       (cnp->cn_flags & NOCROSSMOUNT) == 0) {
 		error = vfs_busy(mp, NULL);
 		if (error != 0) {
-			vput(dp);
-			goto bad;
+			vput(state->dp);
+			return error;
 		}
-		KASSERT(ndp->ni_dvp != dp);
+		KASSERT(ndp->ni_dvp != state->dp);
 		VOP_UNLOCK(ndp->ni_dvp, 0);
-		vput(dp);
+		vput(state->dp);
 		error = VFS_ROOT(mp, &tdp);
 		vfs_unbusy(mp, false, NULL);
 		if (error) {
 			vn_lock(ndp->ni_dvp, LK_EXCLUSIVE | LK_RETRY);
-			goto bad;
+			return error;
 		}
 		VOP_UNLOCK(tdp, 0);
-		ndp->ni_vp = dp = tdp;
+		ndp->ni_vp = state->dp = tdp;
 		vn_lock(ndp->ni_dvp, LK_EXCLUSIVE | LK_RETRY);
 		vn_lock(ndp->ni_vp, LK_EXCLUSIVE | LK_RETRY);
 	}
 
+	return 0;
+}
+
+static int
+do_lookup(struct namei_state *state)
+{
+	int error = 0;
+
+	struct componentname *cnp = state->cnp;
+	struct nameidata *ndp = state->ndp;
+
+	KASSERT(cnp == &ndp->ni_cnd);
+
+	error = lookup_start(state);
+	if (error) {
+		goto bad;
+	}
+	// XXX: this case should not be necessary given proper handling
+	// of slashes elsewhere.
+	if (state->lookup_alldone) {
+		goto terminal;
+	}
+
+dirloop:
+	error = lookup_parsepath(state);
+	if (error) {
+		goto bad;
+	}
+
+	error = lookup_once(state);
+	if (error) {
+		goto bad;
+	}
+	// XXX ought to be able to avoid this case too
+	if (state->lookup_alldone) {
+		/* this should NOT be "goto terminal;" */
+		return 0;
+	}
+
 	/*
 	 * Check for symbolic link.  Back up over any slashes that we skipped,
 	 * as we will need them again.
 	 */
-	if ((dp->v_type == VLNK) && (cnp->cn_flags & (FOLLOW|REQUIREDIR))) {
-		ndp->ni_pathlen += slashes;
-		ndp->ni_next -= slashes;
+	if ((state->dp->v_type == VLNK) && (cnp->cn_flags & (FOLLOW|REQUIREDIR))) {
+		ndp->ni_pathlen += state->slashes;
+		ndp->ni_next -= state->slashes;
 		cnp->cn_flags |= ISSYMLINK;
 		return (0);
 	}
@@ -966,22 +1056,20 @@
 	 * Check for directory, if the component was followed by a series of
 	 * slashes.
 	 */
-	if ((dp->v_type != VDIR) && (cnp->cn_flags & REQUIREDIR)) {
+	if ((state->dp->v_type != VDIR) && (cnp->cn_flags & REQUIREDIR)) {
 		error = ENOTDIR;
-		KASSERT(dp != ndp->ni_dvp);
-		vput(dp);
+		KASSERT(state->dp != ndp->ni_dvp);
+		vput(state->dp);
 		goto bad;
 	}
 
-nextname:
-
 	/*
 	 * Not a symbolic link.  If this was not the last component, then
 	 * continue at the next component, else return.
 	 */
 	if (!(cnp->cn_flags & ISLASTCN)) {
 		cnp->cn_nameptr = ndp->ni_next;
-		if (ndp->ni_dvp == dp) {
+		if (ndp->ni_dvp == state->dp) {
 			vrele(ndp->ni_dvp);
 		} else {
 			vput(ndp->ni_dvp);
@@ -990,7 +1078,7 @@
 	}
 
 terminal:
-	if (dp == ndp->ni_erootdir) {
+	if (state->dp == ndp->ni_erootdir) {
 		/*
 		 * We are about to return the emulation root.
 		 * This isn't a good idea because code might repeatedly
@@ -998,17 +1086,17 @@
 		 * for "/" and loop forever.
 		 * So convert it to the real root.
 		 */
-		if (ndp->ni_dvp == dp)
-			vrele(dp);
+		if (ndp->ni_dvp == state->dp)
+			vrele(state->dp);
 		else
 			if (ndp->ni_dvp != NULL)
 				vput(ndp->ni_dvp);
 		ndp->ni_dvp = NULL;
-		vput(dp);
-		dp = ndp->ni_rootdir;
-		VREF(dp);
-		vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
-		ndp->ni_vp = dp;
+		vput(state->dp);
+		state->dp = ndp->ni_rootdir;
+		VREF(state->dp);
+		vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY);
+		ndp->ni_vp = state->dp;
 	}
 
 	/*
@@ -1028,7 +1116,7 @@
 		default:
 			KASSERT(0);
 		}
-		vput(dp);
+		vput(state->dp);
 		goto bad;
 	}
 
@@ -1036,11 +1124,11 @@
 	 * Disallow directory write attempts on read-only lookups.
 	 * Prefers EEXIST over EROFS for the CREATE case.
 	 */
-	if (rdonly &&
+	if (state->rdonly &&
 	    (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
 		error = EROFS;
-		if (dp != ndp->ni_dvp) {
-			vput(dp);
+		if (state->dp != ndp->ni_dvp) {
+			vput(state->dp);
 		}
 		goto bad;
 	}
@@ -1051,7 +1139,7 @@
 		}
 	}
 	if ((cnp->cn_flags & LOCKLEAF) == 0) {
-		VOP_UNLOCK(dp, 0);
+		VOP_UNLOCK(state->dp, 0);
 	}
 	return (0);
 
@@ -1061,6 +1149,23 @@
 }
 
 /*
+ * Externally visible interface used by nfsd (bletch, yuk, XXX)
+ */
+int
+lookup(struct nameidata *ndp)
+{
+	struct namei_state state;
+	int error;
+
+	/* For now at least we don't have to frob the state */
+	namei_init(&state, ndp);
+	error = do_lookup(&state);
+	namei_cleanup(&state);
+
+	return error;
+}
+
+/*
  * Reacquire a path name component.
  * dvp is locked on entry and exit.
  * *vpp is locked on exit unless it's NULL.

Reply via email to