Module Name:    src
Committed By:   dholland
Date:           Sun Aug  9 03:28:35 UTC 2009

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

Log Message:
Begin splitting up namei into smaller pieces.


To generate a diff of this commit:
cvs rdiff -u -r1.116 -r1.117 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.116 src/sys/kern/vfs_lookup.c:1.117
--- src/sys/kern/vfs_lookup.c:1.116	Mon Jun 29 05:00:14 2009
+++ src/sys/kern/vfs_lookup.c	Sun Aug  9 03:28:35 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: vfs_lookup.c,v 1.116 2009/06/29 05:00:14 dholland Exp $	*/
+/*	$NetBSD: vfs_lookup.c,v 1.117 2009/08/09 03:28:35 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.116 2009/06/29 05:00:14 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.117 2009/08/09 03:28:35 dholland Exp $");
 
 #include "opt_magiclinks.h"
 
@@ -216,25 +216,61 @@
  *		if symbolic link, massage name in buffer and continue
  *	}
  */
-int
-namei(struct nameidata *ndp)
-{
-	struct cwdinfo *cwdi;		/* pointer to cwd state */
-	char *cp;			/* pointer into pathname argument */
+
+/*
+ * Internal state for a namei operation.
+ */
+struct namei_state {
+	struct nameidata *ndp;
+	struct componentname *cnp;
+
 	struct vnode *dp;		/* the directory we are searching */
-	struct iovec aiov;		/* uio for reading symbolic links */
-	struct lwp *l = curlwp;		/* thread doing namei() */
-	struct uio auio;
-	int error;
-	size_t linklen;
-	struct componentname *cnp = &ndp->ni_cnd;
+};
+
+/*
+ * Initialize the namei working state.
+ */
+static void
+namei_init(struct namei_state *state, struct nameidata *ndp)
+{
+	state->ndp = ndp;
+	state->cnp = &ndp->ni_cnd;
+
+	state->dp = NULL;
+}
+
+/*
+ * Clean up the working namei state, leaving things ready for return
+ * from namei.
+ */
+static void
+namei_cleanup(struct namei_state *state)
+{
+	KASSERT(state->cnp == &state->ndp->ni_cnd);
+
+	//KASSERT(state->dp == NULL); 	// not yet
+
+	/* nothing for now */
+	(void)state;
+}
+
+//////////////////////////////
+
+/*
+ * Start up namei. Early portion.
+ *
+ * This is divided from namei_start2 by the emul_retry: point.
+ */
+static void
+namei_start1(struct namei_state *state)
+{
 
 #ifdef DIAGNOSTIC
-	if (!cnp->cn_cred)
+	if (!state->cnp->cn_cred)
 		panic("namei: bad cred/proc");
-	if (cnp->cn_nameiop & (~OPMASK))
+	if (state->cnp->cn_nameiop & (~OPMASK))
 		panic("namei: nameiop contaminated with flags");
-	if (cnp->cn_flags & OPMASK)
+	if (state->cnp->cn_flags & OPMASK)
 		panic("namei: flags contaminated with nameiops");
 #endif
 
@@ -242,9 +278,24 @@
 	 * Get a buffer for the name to be translated, and copy the
 	 * name into the buffer.
 	 */
-	if ((cnp->cn_flags & HASBUF) == 0)
-		cnp->cn_pnbuf = PNBUF_GET();
-    emul_retry:
+	if ((state->cnp->cn_flags & HASBUF) == 0)
+		state->cnp->cn_pnbuf = PNBUF_GET();
+}
+
+/*
+ * Start up namei. Copy the path, find the root dir and cwd, establish
+ * the starting directory for lookup, and lock it.
+ */
+static int
+namei_start2(struct namei_state *state)
+{
+	struct nameidata *ndp = state->ndp;
+	struct componentname *cnp = state->cnp;
+
+	struct cwdinfo *cwdi;		/* pointer to cwd state */
+	struct lwp *self = curlwp;	/* thread doing namei() */
+	int error;
+
 	if (ndp->ni_segflg == UIO_SYSSPACE)
 		error = copystr(ndp->ni_dirp, cnp->cn_pnbuf,
 			    MAXPATHLEN, &ndp->ni_pathlen);
@@ -268,12 +319,12 @@
 	/*
 	 * Get root directory for the translation.
 	 */
-	cwdi = l->l_proc->p_cwdi;
+	cwdi = self->l_proc->p_cwdi;
 	rw_enter(&cwdi->cwdi_lock, RW_READER);
-	dp = cwdi->cwdi_rdir;
-	if (dp == NULL)
-		dp = rootvnode;
-	ndp->ni_rootdir = dp;
+	state->dp = cwdi->cwdi_rdir;
+	if (state->dp == NULL)
+		state->dp = rootvnode;
+	ndp->ni_rootdir = state->dp;
 
 	/*
 	 * Check if starting from root directory or current directory.
@@ -282,7 +333,7 @@
 		if (cnp->cn_flags & TRYEMULROOT) {
 			if (cnp->cn_flags & EMULROOTSET) {
 				/* Called from (eg) emul_find_interp() */
-				dp = ndp->ni_erootdir;
+				state->dp = ndp->ni_erootdir;
 			} else {
 				if (cwdi->cwdi_edir == NULL
 				    || (cnp->cn_pnbuf[1] == '.' 
@@ -290,22 +341,25 @@
 					   && cnp->cn_pnbuf[3] == '/')) {
 					ndp->ni_erootdir = NULL;
 				} else {
-					dp = cwdi->cwdi_edir;
-					ndp->ni_erootdir = dp;
+					state->dp = cwdi->cwdi_edir;
+					ndp->ni_erootdir = state->dp;
 				}
 			}
 		} else {
 			ndp->ni_erootdir = NULL;
 			if (cnp->cn_flags & NOCHROOT)
-				dp = ndp->ni_rootdir = rootvnode;
+				state->dp = ndp->ni_rootdir = rootvnode;
 		}
 	} else {
-		dp = cwdi->cwdi_cdir;
+		state->dp = cwdi->cwdi_cdir;
 		ndp->ni_erootdir = NULL;
 	}
-	VREF(dp);
+	VREF(state->dp);
 	rw_exit(&cwdi->cwdi_lock);
- 
+
+	/*
+	 * Ktrace it.
+	 */
 	if (ktrpoint(KTR_NAMEI)) {
 		if (ndp->ni_erootdir != NULL) {
 			/*
@@ -320,26 +374,161 @@
 			if (cnp->cn_flags & EMULROOTSET)
 				emul_path = ndp->ni_next;
 			else
-				emul_path = l->l_proc->p_emul->e_path;
+				emul_path = self->l_proc->p_emul->e_path;
 			ktrnamei2(emul_path, strlen(emul_path),
 			    cnp->cn_pnbuf, ndp->ni_pathlen);
 		} else
 			ktrnamei(cnp->cn_pnbuf, ndp->ni_pathlen);
 	}
 
-	vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
+	vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY);
+
+	return 0;
+}
+
+/*
+ * Undo namei_start: unlock and release the current lookup directory,
+ * and discard the path buffer.
+ */
+static void
+namei_end(struct namei_state *state)
+{
+	vput(state->dp);
+	PNBUF_PUT(state->cnp->cn_pnbuf);
+	//state->cnp->cn_pnbuf = NULL; // not yet (just in case) (XXX)
+}
+
+/*
+ * Check for being at a symlink.
+ */
+static inline int
+namei_atsymlink(struct namei_state *state)
+{
+	return (state->cnp->cn_flags & ISSYMLINK) != 0;
+}
+
+/*
+ * Follow a symlink.
+ */
+static inline int
+namei_follow(struct namei_state *state)
+{
+	struct nameidata *ndp = state->ndp;
+	struct componentname *cnp = state->cnp;
+
+	struct lwp *self = curlwp;	/* thread doing namei() */
+	struct iovec aiov;		/* uio for reading symbolic links */
+	struct uio auio;
+	char *cp;			/* pointer into pathname argument */
+	size_t linklen;
+	int error;
+
+	if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
+		return ELOOP;
+	}
+	if (ndp->ni_vp->v_mount->mnt_flag & MNT_SYMPERM) {
+		error = VOP_ACCESS(ndp->ni_vp, VEXEC, cnp->cn_cred);
+		if (error != 0)
+			return error;
+	}
+	if (ndp->ni_pathlen > 1)
+		cp = PNBUF_GET();
+	else
+		cp = cnp->cn_pnbuf;
+	aiov.iov_base = cp;
+	aiov.iov_len = MAXPATHLEN;
+	auio.uio_iov = &aiov;
+	auio.uio_iovcnt = 1;
+	auio.uio_offset = 0;
+	auio.uio_rw = UIO_READ;
+	auio.uio_resid = MAXPATHLEN;
+	UIO_SETUP_SYSSPACE(&auio);
+	error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
+	if (error) {
+badlink:
+		if (ndp->ni_pathlen > 1)
+			PNBUF_PUT(cp);
+		return error;
+	}
+	linklen = MAXPATHLEN - auio.uio_resid;
+	if (linklen == 0) {
+		error = ENOENT;
+		goto badlink;
+	}
+
+	/*
+	 * Do symlink substitution, if appropriate, and
+	 * check length for potential overflow.
+	 */
+	if ((vfs_magiclinks &&
+	     symlink_magic(self->l_proc, cp, &linklen)) ||
+	    (linklen + ndp->ni_pathlen >= MAXPATHLEN)) {
+		error = ENAMETOOLONG;
+		goto badlink;
+	}
+	if (ndp->ni_pathlen > 1) {
+		memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen);
+		PNBUF_PUT(cnp->cn_pnbuf);
+		cnp->cn_pnbuf = cp;
+	} else
+		cnp->cn_pnbuf[linklen] = '\0';
+	ndp->ni_pathlen += linklen;
+	vput(ndp->ni_vp);
+	state->dp = ndp->ni_dvp;
+
+	/*
+	 * Check if root directory should replace current directory.
+	 */
+	if (cnp->cn_pnbuf[0] == '/') {
+		vput(state->dp);
+		/* Keep absolute symbolic links inside emulation root */
+		state->dp = ndp->ni_erootdir;
+		if (state->dp == NULL || (cnp->cn_pnbuf[1] == '.' 
+					  && cnp->cn_pnbuf[2] == '.'
+					  && cnp->cn_pnbuf[3] == '/')) {
+			ndp->ni_erootdir = NULL;
+			state->dp = ndp->ni_rootdir;
+		}
+		VREF(state->dp);
+		vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY);
+	}
+
+	return 0;
+}
+
+//////////////////////////////
+
+static int
+do_namei(struct namei_state *state)
+{
+	int error;
+
+	struct nameidata *ndp = state->ndp;
+	struct componentname *cnp = state->cnp;
+
+	KASSERT(cnp == &ndp->ni_cnd);
+
+	namei_start1(state);
+
+    emul_retry:
+
+	error = namei_start2(state);
+	if (error) {
+		return error;
+	}
+
 	/* Loop through symbolic links */
 	for (;;) {
-		if (!dp->v_mount) {
+		if (!state->dp->v_mount) {
 			/* Give up if the directory is no longer mounted */
-			vput(dp);
-			PNBUF_PUT(cnp->cn_pnbuf);
+			namei_end(state);
 			return (ENOENT);
 		}
 		cnp->cn_nameptr = cnp->cn_pnbuf;
-		ndp->ni_startdir = dp;
+		ndp->ni_startdir = state->dp;
 		error = lookup(ndp);
 		if (error != 0) {
+			/* XXX this should use namei_end() */
 			if (ndp->ni_dvp) {
 				vput(ndp->ni_dvp);
 			}
@@ -355,103 +544,56 @@
 		/*
 		 * Check for symbolic link
 		 */
-		if ((cnp->cn_flags & ISSYMLINK) == 0) {
-			if ((cnp->cn_flags & LOCKPARENT) == 0 && ndp->ni_dvp) {
-				if (ndp->ni_dvp == ndp->ni_vp) {
-					vrele(ndp->ni_dvp);
-				} else {
-					vput(ndp->ni_dvp);
-				}
-			}
-			if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0) {
+		if (namei_atsymlink(state)) {
+			error = namei_follow(state);
+			if (error) {
+				KASSERT(ndp->ni_dvp != ndp->ni_vp);
+				vput(ndp->ni_dvp);
+				vput(ndp->ni_vp);
+				ndp->ni_vp = NULL;
 				PNBUF_PUT(cnp->cn_pnbuf);
-#if defined(DIAGNOSTIC)
-				cnp->cn_pnbuf = NULL;
-#endif /* defined(DIAGNOSTIC) */
-			} else {
-				cnp->cn_flags |= HASBUF;
+				return error;
 			}
-			return (0);
 		}
-
-		if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
-			error = ELOOP;
+		else {
 			break;
 		}
-		if (ndp->ni_vp->v_mount->mnt_flag & MNT_SYMPERM) {
-			error = VOP_ACCESS(ndp->ni_vp, VEXEC, cnp->cn_cred);
-			if (error != 0)
-				break;
-		}
-		if (ndp->ni_pathlen > 1)
-			cp = PNBUF_GET();
-		else
-			cp = cnp->cn_pnbuf;
-		aiov.iov_base = cp;
-		aiov.iov_len = MAXPATHLEN;
-		auio.uio_iov = &aiov;
-		auio.uio_iovcnt = 1;
-		auio.uio_offset = 0;
-		auio.uio_rw = UIO_READ;
-		auio.uio_resid = MAXPATHLEN;
-		UIO_SETUP_SYSSPACE(&auio);
-		error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
-		if (error) {
-badlink:
-			if (ndp->ni_pathlen > 1)
-				PNBUF_PUT(cp);
-			break;
-		}
-		linklen = MAXPATHLEN - auio.uio_resid;
-		if (linklen == 0) {
-			error = ENOENT;
-			goto badlink;
-		}
+	}
 
-		/*
-		 * Do symlink substitution, if appropriate, and
-		 * check length for potential overflow.
-		 */
-		if ((vfs_magiclinks &&
-		     symlink_magic(l->l_proc, cp, &linklen)) ||
-		    (linklen + ndp->ni_pathlen >= MAXPATHLEN)) {
-			error = ENAMETOOLONG;
-			goto badlink;
-		}
-		if (ndp->ni_pathlen > 1) {
-			memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen);
-			PNBUF_PUT(cnp->cn_pnbuf);
-			cnp->cn_pnbuf = cp;
-		} else
-			cnp->cn_pnbuf[linklen] = '\0';
-		ndp->ni_pathlen += linklen;
-		vput(ndp->ni_vp);
-		dp = ndp->ni_dvp;
+	/*
+	 * Done
+	 */
 
-		/*
-		 * Check if root directory should replace current directory.
-		 */
-		if (cnp->cn_pnbuf[0] == '/') {
-			vput(dp);
-			/* Keep absolute symbolic links inside emulation root */
-			dp = ndp->ni_erootdir;
-			if (dp == NULL || (cnp->cn_pnbuf[1] == '.' 
-			    && cnp->cn_pnbuf[2] == '.'
-			    && cnp->cn_pnbuf[3] == '/')) {
-				ndp->ni_erootdir = NULL;
-				dp = ndp->ni_rootdir;
-			}
-			VREF(dp);
-			vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
+	if ((cnp->cn_flags & LOCKPARENT) == 0 && ndp->ni_dvp) {
+		if (ndp->ni_dvp == ndp->ni_vp) {
+			vrele(ndp->ni_dvp);
+		} else {
+			vput(ndp->ni_dvp);
 		}
 	}
-	/* Failed to process a symbolic link */
-	KASSERT(ndp->ni_dvp != ndp->ni_vp);
-	vput(ndp->ni_dvp);
-	vput(ndp->ni_vp);
-	ndp->ni_vp = NULL;
-	PNBUF_PUT(cnp->cn_pnbuf);
-	return (error);
+	if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0) {
+		PNBUF_PUT(cnp->cn_pnbuf);
+#if defined(DIAGNOSTIC)
+		cnp->cn_pnbuf = NULL;
+#endif /* defined(DIAGNOSTIC) */
+	} else {
+		cnp->cn_flags |= HASBUF;
+	}
+
+	return 0;
+}
+
+int
+namei(struct nameidata *ndp)
+{
+	struct namei_state state;
+	int error;
+
+	namei_init(&state, ndp);
+	error = do_namei(&state);
+	namei_cleanup(&state);
+
+	return error;
 }
 
 /*

Reply via email to