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;
}
/*