Module Name: src
Committed By: dholland
Date: Mon Apr 11 01:37:43 UTC 2011
Modified Files:
src/sys/kern: vfs_lookup.c
Log Message:
ZZmsg
To generate a diff of this commit:
cvs rdiff -u -r1.138 -r1.139 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.138 src/sys/kern/vfs_lookup.c:1.139
--- src/sys/kern/vfs_lookup.c:1.138 Mon Apr 11 01:37:14 2011
+++ src/sys/kern/vfs_lookup.c Mon Apr 11 01:37:43 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: vfs_lookup.c,v 1.138 2011/04/11 01:37:14 dholland Exp $ */
+/* $NetBSD: vfs_lookup.c,v 1.139 2011/04/11 01:37:43 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.138 2011/04/11 01:37:14 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.139 2011/04/11 01:37:43 dholland Exp $");
#include "opt_magiclinks.h"
@@ -415,7 +415,6 @@
int slashes;
unsigned attempt_retry:1; /* true if error allows emul retry */
- unsigned lookup_terminal:1; /* flag returned from lookup */
};
@@ -641,7 +640,8 @@
static inline int
namei_atsymlink(struct namei_state *state)
{
- return (state->cnp->cn_flags & ISSYMLINK) != 0;
+ return (state->dp->v_type == VLNK) &&
+ (state->cnp->cn_flags & (FOLLOW|REQUIREDIR));
}
/*
@@ -775,67 +775,6 @@
* if LOCKPARENT set, return locked parent in ni_dvp
*/
-/*
- * Begin lookup().
- */
-static int
-lookup_start(struct namei_state *state, struct vnode *startdir)
-{
- const char *cp; /* pointer into pathname argument */
-
- 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.
- */
- state->docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
- if (cnp->cn_nameiop == DELETE)
- state->docache = 0;
- state->rdonly = cnp->cn_flags & RDONLY;
- ndp->ni_dvp = NULL;
- cnp->cn_flags &= ~ISSYMLINK;
- state->dp = startdir;
-
- /*
- * If we have a leading string of slashes, remove them, and just make
- * sure the current node is a directory.
- */
- cp = cnp->cn_nameptr;
- if (*cp == '/') {
- do {
- cp++;
- } while (*cp == '/');
- ndp->ni_pathlen -= cp - cnp->cn_nameptr;
- cnp->cn_nameptr = cp;
-
- if (state->dp->v_type != VDIR) {
- vput(state->dp);
- return ENOTDIR;
- }
-
- /*
- * If we've exhausted the path name, then just return the
- * current node.
- */
- if (cnp->cn_nameptr[0] == '\0') {
- ndp->ni_vp = state->dp;
- cnp->cn_flags |= ISLASTCN;
-
- /* bleh */
- state->lookup_alldone = 1;
- return 0;
- }
- }
-
- return 0;
-}
-
static int
lookup_parsepath(struct namei_state *state)
{
@@ -1102,6 +1041,7 @@
{
struct nameidata *ndp = state->ndp;
struct componentname *cnp = state->cnp;
+ const char *cp;
int error;
error = namei_start(state, forcecwd);
@@ -1110,8 +1050,17 @@
}
/*
+ * Setup: break out flag bits into variables.
+ */
+ state->docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
+ if (cnp->cn_nameiop == DELETE)
+ state->docache = 0;
+ state->rdonly = cnp->cn_flags & RDONLY;
+
+ /*
* Keep going until we run out of path components.
*/
+ cnp->cn_nameptr = ndp->ni_pnbuf;
for (;;) {
/*
@@ -1127,190 +1076,98 @@
* Look up the next path component.
* (currently, this may consume more than one)
*/
- cnp->cn_nameptr = ndp->ni_pnbuf;
-
- error = lookup_start(state, state->namei_startdir);
- if (error) {
- ndp->ni_vp = NULL;
- return (error);
- }
- // XXX: this case should not be necessary given proper handling
- // of slashes elsewhere.
- if (state->lookup_alldone) {
- state->lookup_terminal = 1;
- error = 0;
- } else {
-
- dirloop:
- error = lookup_parsepath(state);
- if (error) {
- state->lookup_terminal = 0;
- ndp->ni_vp = NULL;
- goto lookup_out;
- }
+ state->lookup_alldone = 0;
- error = lookup_once(state);
- if (error) {
- state->lookup_terminal = 0;
- ndp->ni_vp = NULL;
- goto lookup_out;
- }
- // XXX ought to be able to avoid this case too
- if (state->lookup_alldone) {
- /* this should NOT set lookup_terminal */
- state->lookup_terminal = 0;
- error = 0;
- goto lookup_out;
- }
+ ndp->ni_dvp = NULL;
+ cnp->cn_flags &= ~ISSYMLINK;
+ state->dp = state->namei_startdir;
- /*
- * Check for symbolic link. Back up over any
- * slashes that we skipped, as we will need
- * them again.
- */
- 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;
- state->lookup_terminal = 0;
- error = 0;
- goto lookup_out;
- }
+ dirloop:
+ /*
+ * If we have a leading string of slashes, remove
+ * them, and just make sure the current node is a
+ * directory.
+ */
+ cp = cnp->cn_nameptr;
+ if (*cp == '/') {
+ do {
+ cp++;
+ } while (*cp == '/');
+ ndp->ni_pathlen -= cp - cnp->cn_nameptr;
+ cnp->cn_nameptr = cp;
- /*
- * Check for directory, if the component was
- * followed by a series of slashes.
- */
- if ((state->dp->v_type != VDIR) && (cnp->cn_flags & REQUIREDIR)) {
- error = ENOTDIR;
- KASSERT(state->dp != ndp->ni_dvp);
+ if (state->dp->v_type != VDIR) {
vput(state->dp);
- state->lookup_terminal = 0;
ndp->ni_vp = NULL;
- goto lookup_out;
- }
-
- /*
- * 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 == state->dp) {
- vrele(ndp->ni_dvp);
- } else {
+ /* XXX this should use namei_end() */
+ if (ndp->ni_dvp) {
vput(ndp->ni_dvp);
}
- goto dirloop;
+ state->attempt_retry = 1;
+ return ENOTDIR;
}
+ }
- state->lookup_terminal = 1;
- error = 0;
- goto lookup_out;
- lookup_out:
- ;
+ /*
+ * If we've exhausted the path name, then just return the
+ * current node.
+ */
+ if (cnp->cn_nameptr[0] == '\0') {
+ ndp->ni_vp = state->dp;
+ cnp->cn_flags |= ISLASTCN;
+
+ /* bleh */
+ goto terminal;
}
- if (error != 0) {
+
+ error = lookup_parsepath(state);
+ if (error) {
+ ndp->ni_vp = NULL;
/* XXX this should use namei_end() */
if (ndp->ni_dvp) {
vput(ndp->ni_dvp);
}
- /*
- * Note that if we're doing TRYEMULROOT we can
- * retry with the normal root. Setting this
- * here matches previous practice, but the
- * previous practice didn't make much sense
- * and somebody should sit down and figure out
- * which cases should cause retry and which
- * shouldn't. XXX.
- */
state->attempt_retry = 1;
return (error);
}
- if (state->lookup_terminal) {
- if (state->dp == ndp->ni_erootdir) {
- /*
- * We are about to return the
- * emulation root. This isn't a good
- * idea because code might repeatedly
- * lookup ".." until the file matches
- * that returned for "/" and loop
- * forever. So convert it to the real
- * root.
- */
- if (ndp->ni_dvp == state->dp)
- vrele(state->dp);
- else
- if (ndp->ni_dvp != NULL)
- vput(ndp->ni_dvp);
- ndp->ni_dvp = NULL;
- vput(state->dp);
- state->dp = ndp->ni_rootdir;
- vref(state->dp);
- vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY);
- ndp->ni_vp = state->dp;
- }
-
- /*
- * If the caller requested the parent node
- * (i.e. it's a CREATE, DELETE, or RENAME),
- * and we don't have one (because this is the
- * root directory), then we must fail.
- */
- if (ndp->ni_dvp == NULL && cnp->cn_nameiop != LOOKUP) {
- switch (cnp->cn_nameiop) {
- case CREATE:
- error = EEXIST;
- break;
- case DELETE:
- case RENAME:
- error = EBUSY;
- break;
- default:
- KASSERT(0);
- }
- vput(state->dp);
- ndp->ni_vp = NULL;
- goto lookup_terminal_fail;
+ error = lookup_once(state);
+ if (error) {
+ ndp->ni_vp = NULL;
+ /* XXX this should use namei_end() */
+ if (ndp->ni_dvp) {
+ vput(ndp->ni_dvp);
}
-
/*
- * Disallow directory write attempts on
- * read-only lookups. Prefers EEXIST over
- * EROFS for the CREATE case.
+ * Note that if we're doing TRYEMULROOT we can
+ * retry with the normal root. Where this is
+ * currently set matches previous practice,
+ * but the previous practice didn't make much
+ * sense and somebody should sit down and
+ * figure out which cases should cause retry
+ * and which shouldn't. XXX.
*/
- if (state->rdonly &&
- (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
- error = EROFS;
- if (state->dp != ndp->ni_dvp) {
- vput(state->dp);
- }
- ndp->ni_vp = NULL;
- goto lookup_terminal_fail;
- }
- if ((cnp->cn_flags & LOCKLEAF) == 0) {
- VOP_UNLOCK(state->dp);
- }
-
- if (0) {
- lookup_terminal_fail:
- /* XXX this should use namei_end() */
- if (ndp->ni_dvp) {
- vput(ndp->ni_dvp);
- }
- state->attempt_retry = 1;
- return (error);
- }
+ state->attempt_retry = 1;
+ return (error);
+ }
+ // XXX ought to be able to avoid this case too
+ if (state->lookup_alldone) {
+ error = 0;
+ /* break out of main loop */
+ break;
}
/*
- * If we've reached a symbolic link, follow it, unless we
- * aren't supposed to.
+ * Check for symbolic link. If we've reached one,
+ * follow it, unless we aren't supposed to. Back up
+ * over any slashes that we skipped, as we will need
+ * them again.
*/
if (namei_atsymlink(state)) {
+ ndp->ni_pathlen += state->slashes;
+ ndp->ni_next -= state->slashes;
+ cnp->cn_flags |= ISSYMLINK;
if (neverfollow) {
error = EINVAL;
} else {
@@ -1323,10 +1180,116 @@
ndp->ni_vp = NULL;
return error;
}
+ cnp->cn_nameptr = ndp->ni_pnbuf;
+ continue;
}
- else {
- break;
+
+ /*
+ * Check for directory, if the component was
+ * followed by a series of slashes.
+ */
+ if ((state->dp->v_type != VDIR) && (cnp->cn_flags & REQUIREDIR)) {
+ KASSERT(state->dp != ndp->ni_dvp);
+ vput(state->dp);
+ ndp->ni_vp = NULL;
+ /* XXX this should use namei_end() */
+ if (ndp->ni_dvp) {
+ vput(ndp->ni_dvp);
+ }
+ state->attempt_retry = 1;
+ return ENOTDIR;
+ }
+
+ /*
+ * 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 == state->dp) {
+ vrele(ndp->ni_dvp);
+ } else {
+ vput(ndp->ni_dvp);
+ }
+ ndp->ni_dvp = NULL;
+ goto dirloop;
+ }
+
+ terminal:
+ error = 0;
+ if (state->dp == ndp->ni_erootdir) {
+ /*
+ * We are about to return the emulation root.
+ * This isn't a good idea because code might
+ * repeatedly lookup ".." until the file
+ * matches that returned for "/" and loop
+ * forever. So convert it to the real root.
+ */
+ if (ndp->ni_dvp == state->dp)
+ vrele(state->dp);
+ else
+ if (ndp->ni_dvp != NULL)
+ vput(ndp->ni_dvp);
+ ndp->ni_dvp = NULL;
+ vput(state->dp);
+ state->dp = ndp->ni_rootdir;
+ vref(state->dp);
+ vn_lock(state->dp, LK_EXCLUSIVE | LK_RETRY);
+ ndp->ni_vp = state->dp;
}
+
+ /*
+ * If the caller requested the parent node
+ * (i.e. it's a CREATE, DELETE, or RENAME),
+ * and we don't have one (because this is the
+ * root directory), then we must fail.
+ */
+ if (ndp->ni_dvp == NULL && cnp->cn_nameiop != LOOKUP) {
+ switch (cnp->cn_nameiop) {
+ case CREATE:
+ error = EEXIST;
+ break;
+ case DELETE:
+ case RENAME:
+ error = EBUSY;
+ break;
+ default:
+ KASSERT(0);
+ }
+ vput(state->dp);
+ ndp->ni_vp = NULL;
+ /* XXX this should use namei_end() */
+ if (ndp->ni_dvp) {
+ vput(ndp->ni_dvp);
+ }
+ state->attempt_retry = 1;
+ return (error);
+ }
+
+ /*
+ * Disallow directory write attempts on read-only lookups.
+ * Prefers EEXIST over EROFS for the CREATE case.
+ */
+ if (state->rdonly &&
+ (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
+ error = EROFS;
+ if (state->dp != ndp->ni_dvp) {
+ vput(state->dp);
+ }
+ ndp->ni_vp = NULL;
+ /* XXX this should use namei_end() */
+ if (ndp->ni_dvp) {
+ vput(ndp->ni_dvp);
+ }
+ state->attempt_retry = 1;
+ return (error);
+ }
+ if ((cnp->cn_flags & LOCKLEAF) == 0) {
+ VOP_UNLOCK(state->dp);
+ }
+
+ break;
}
/*