summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArtur Grabowski <art@cvs.openbsd.org>2003-01-31 17:37:51 +0000
committerArtur Grabowski <art@cvs.openbsd.org>2003-01-31 17:37:51 +0000
commit1b0b18abe62afb1a61733a6f5891a98bfbea81ec (patch)
tree29dc896fd65580ea85012ef60aaf813858629e3f
parent2bccdd51809becfe909c271f5fef4d380c663209 (diff)
File system locking fixups, mostly from NetBSD:
- cache_lookup move common code from various fs's here always return with vnode and parent locked adjust return codes - PDIRUNLOCK - new flag set if lookup couldn't lock parent vnode - kernfs and procfs lock vnode in get_root don't unlock (again) in kernfs_freevp fix memory leak in procfs From tedu@stanford.edu deraadt@ and various other ok
-rw-r--r--sys/adosfs/adlookup.c68
-rw-r--r--sys/isofs/cd9660/cd9660_lookup.c77
-rw-r--r--sys/kern/vfs_cache.c123
-rw-r--r--sys/kern/vfs_lookup.c25
-rw-r--r--sys/miscfs/fdesc/fdesc_vnops.c46
-rw-r--r--sys/miscfs/kernfs/kernfs_vfsops.c41
-rw-r--r--sys/miscfs/kernfs/kernfs_vnops.c24
-rw-r--r--sys/miscfs/portal/portal_vnops.c14
-rw-r--r--sys/miscfs/procfs/procfs.h3
-rw-r--r--sys/miscfs/procfs/procfs_vfsops.c28
-rw-r--r--sys/miscfs/procfs/procfs_vnops.c52
-rw-r--r--sys/msdosfs/msdosfs_lookup.c88
-rw-r--r--sys/nfs/nfs_vnops.c173
-rw-r--r--sys/sys/namei.h5
-rw-r--r--sys/ufs/ext2fs/ext2fs_lookup.c78
-rw-r--r--sys/ufs/ufs/ufs_lookup.c84
-rw-r--r--sys/xfs/xfs_node-bsd.c8
17 files changed, 540 insertions, 397 deletions
diff --git a/sys/adosfs/adlookup.c b/sys/adosfs/adlookup.c
index 304d6aac08d..1c2896397e7 100644
--- a/sys/adosfs/adlookup.c
+++ b/sys/adosfs/adlookup.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: adlookup.c,v 1.11 1997/12/18 00:59:01 gene Exp $ */
+/* $OpenBSD: adlookup.c,v 1.12 2003/01/31 17:37:49 art Exp $ */
/* $NetBSD: adlookup.c,v 1.17 1996/10/25 23:13:58 cgd Exp $ */
/*
@@ -90,6 +90,7 @@ adosfs_lookup(v)
*vpp = NULL;
ucp = cnp->cn_cred;
nameiop = cnp->cn_nameiop;
+ cnp->cn_flags &= ~PDIRUNLOCK;
flags = cnp->cn_flags;
last = flags & ISLASTCN;
lockp = flags & LOCKPARENT;
@@ -107,41 +108,17 @@ adosfs_lookup(v)
return (ENOTDIR);
if ((error = VOP_ACCESS(vdp, VEXEC, ucp, cnp->cn_proc)) != 0)
return (error);
+ if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) &&
+ (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
+ return (EROFS);
+
/*
- * cache lookup algorithm borrowed from ufs_lookup()
- * its not consistent with otherthings in this function..
+ * Before tediously performing a linear scan of the directory,
+ * check the name cache to see if the directory/name pair
+ * we are looking for is known already.
*/
- if ((error = cache_lookup(vdp, vpp, cnp)) != 0) {
- if (error == ENOENT)
- return (error);
-
- vpid = (*vpp)->v_id;
- if (vdp == *vpp) {
- VREF(vdp);
- error = 0;
- } else if (flags & ISDOTDOT) {
- VOP_UNLOCK(vdp, 0, p); /* race */
- error = vget(*vpp, LK_EXCLUSIVE, p);
- if (error == 0 && lockp && last)
- error =
- vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY, p);
- } else {
- error = vget(*vpp, LK_EXCLUSIVE, p);
- /* if (lockp == 0 || error || last) */
- if (lockp == 0 || error || last == 0)
- VOP_UNLOCK(vdp, 0, p);
- }
- if (error == 0) {
- if (vpid == vdp->v_id)
- return (0);
- vput(*vpp);
- if (lockp && vdp != *vpp && last)
- VOP_UNLOCK(vdp, 0, p);
- }
- *vpp = NULL;
- if ((error = vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY, p)) != 0)
- return (error);
- }
+ if ((error = cache_lookup(vdp, vpp, cnp)) >= 0)
+ return (error);
/*
* fake a '.'
@@ -174,12 +151,17 @@ adosfs_lookup(v)
*
*/
VOP_UNLOCK(vdp, 0, p); /* race */
+ cnp->cn_flags |= PDIRUNLOCK;
if ((error = VFS_VGET(vdp->v_mount, ABLKTOINO(adp->pblock),
- vpp)) != 0)
- vn_lock(vdp, LK_RETRY | LK_EXCLUSIVE, p);
- else if (last && lockp &&
- (error = vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY, p)))
- vput(*vpp);
+ vpp)) != 0) {
+ if (vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY, p) == 0)
+ cnp->cn_flags &= ~PDIRUNLOCK;
+ } else if (last && lockp) {
+ if ((error = vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY, p)))
+ vput(*vpp);
+ else
+ cnp->cn_flags &= ~PDIRUNLOCK;
+ }
if (error) {
*vpp = NULL;
return (error);
@@ -238,8 +220,10 @@ adosfs_lookup(v)
#endif
return (error);
}
- if (lockp == 0)
+ if (lockp == 0) {
VOP_UNLOCK(vdp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
cnp->cn_nameiop |= SAVENAME;
#ifdef ADOSFS_DIAGNOSTIC
printf("EJUSTRETURN)");
@@ -278,8 +262,10 @@ found:
}
if (vdp == *vpp)
VREF(vdp);
- else if (lockp == 0 || last == 0)
+ else if (lockp == 0 || last == 0) {
VOP_UNLOCK(vdp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
found_lockdone:
if ((cnp->cn_flags & MAKEENTRY) && nocache == 0)
cache_enter(vdp, *vpp, cnp);
diff --git a/sys/isofs/cd9660/cd9660_lookup.c b/sys/isofs/cd9660/cd9660_lookup.c
index d597dfac440..aa5c762a2ab 100644
--- a/sys/isofs/cd9660/cd9660_lookup.c
+++ b/sys/isofs/cd9660/cd9660_lookup.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cd9660_lookup.c,v 1.9 2001/06/23 02:14:22 csapuntz Exp $ */
+/* $OpenBSD: cd9660_lookup.c,v 1.10 2003/01/31 17:37:49 art Exp $ */
/* $NetBSD: cd9660_lookup.c,v 1.18 1997/05/08 16:19:59 mycroft Exp $ */
/*-
@@ -129,10 +129,13 @@ cd9660_lookup(v)
struct vnode **vpp = ap->a_vpp;
struct componentname *cnp = ap->a_cnp;
struct ucred *cred = cnp->cn_cred;
- int flags = cnp->cn_flags;
+ int flags;
int nameiop = cnp->cn_nameiop;
struct proc *p = cnp->cn_proc;
+ cnp->cn_flags &= ~PDIRUNLOCK;
+ flags = cnp->cn_flags;
+
bp = NULL;
*vpp = NULL;
vdp = ap->a_dvp;
@@ -158,55 +161,9 @@ cd9660_lookup(v)
* check the name cache to see if the directory/name pair
* we are looking for is known already.
*/
- if ((error = cache_lookup(vdp, vpp, cnp)) != 0) {
- int vpid; /* capability number of vnode */
+ if ((error = cache_lookup(vdp, vpp, cnp)) >= 0)
+ return (error);
- if (error == ENOENT)
- return (error);
-#ifdef PARANOID
- if ((vdp->v_flag & VROOT) && (flags & ISDOTDOT))
- panic("cd9660_lookup: .. through root");
-#endif
- /*
- * Get the next vnode in the path.
- * See comment below starting `Step through' for
- * an explaination of the locking protocol.
- */
- pdp = vdp;
- dp = VTOI(*vpp);
- vdp = *vpp;
- vpid = vdp->v_id;
- if (pdp == vdp) {
- VREF(vdp);
- error = 0;
- } else if (flags & ISDOTDOT) {
- VOP_UNLOCK(pdp, 0, p);
- error = vget(vdp, LK_EXCLUSIVE, p);
- if (!error && lockparent && (flags & ISLASTCN))
- error = vn_lock(pdp, LK_EXCLUSIVE, p);
- } else {
- error = vget(vdp, LK_EXCLUSIVE, p);
- if (!lockparent || error || !(flags & ISLASTCN))
- VOP_UNLOCK(pdp, 0, p);
- }
- /*
- * Check that the capability number did not change
- * while we were waiting for the lock.
- */
- if (!error) {
- if (vpid == vdp->v_id)
- return (0);
- vput(vdp);
- if (lockparent && pdp != vdp && (flags & ISLASTCN))
- VOP_UNLOCK(pdp, 0, p);
- }
- if ((error = vn_lock(pdp, LK_EXCLUSIVE, p)) != 0)
- return (error);
- vdp = pdp;
- dp = VTOI(pdp);
- *vpp = NULL;
- }
-
len = cnp->cn_namelen;
name = cnp->cn_nameptr;
/*
@@ -426,16 +383,20 @@ found:
if (flags & ISDOTDOT) {
brelse(bp);
VOP_UNLOCK(pdp, 0, p); /* race to get the inode */
+ cnp->cn_flags |= PDIRUNLOCK;
error = cd9660_vget_internal(vdp->v_mount, dp->i_ino, &tdp,
- dp->i_ino != ino, NULL);
+ dp->i_ino != ino, NULL);
if (error) {
- vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p);
+ if (vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p) == 0)
+ cnp->cn_flags &= ~PDIRUNLOCK;
return (error);
}
- if (lockparent && (flags & ISLASTCN) &&
- (error = vn_lock(pdp, LK_EXCLUSIVE, p))) {
- vput(tdp);
- return (error);
+ if (lockparent && (flags & ISLASTCN)) {
+ if ((error = vn_lock(pdp, LK_EXCLUSIVE, p))) {
+ vput(tdp);
+ return (error);
+ }
+ cnp->cn_flags &= ~PDIRUNLOCK;
}
*vpp = tdp;
} else if (dp->i_number == dp->i_ino) {
@@ -448,8 +409,10 @@ found:
brelse(bp);
if (error)
return (error);
- if (!lockparent || !(flags & ISLASTCN))
+ if (!lockparent || !(flags & ISLASTCN)) {
VOP_UNLOCK(pdp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
*vpp = tdp;
}
diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c
index 252dccb912f..0f0ec577101 100644
--- a/sys/kern/vfs_cache.c
+++ b/sys/kern/vfs_cache.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vfs_cache.c,v 1.8 2002/07/03 21:19:08 miod Exp $ */
+/* $OpenBSD: vfs_cache.c,v 1.9 2003/01/31 17:37:50 art Exp $ */
/* $NetBSD: vfs_cache.c,v 1.13 1996/02/04 02:18:09 christos Exp $ */
/*
@@ -90,9 +90,11 @@ u_long nextvnodeid;
* ni_ptr pointing to the name of the entry being sought, ni_namelen
* tells the length of the name, and ni_hash contains a hash of
* the name. If the lookup succeeds, the vnode is returned in ni_vp
- * and a status of -1 is returned. If the lookup determines that
- * the name does not exist (negative cacheing), a status of ENOENT
- * is returned. If the lookup fails, a status of zero is returned.
+ * and a status of 0 is returned. If the locking fails for whatever
+ * reason, the vnode is unlocked and the error is returned to caller.
+ * If the lookup determines that the name does not exist (negative cacheing),
+ * a status of ENOENT is returned. If the lookup fails, a status of -1
+ * is returned.
*/
int
cache_lookup(dvp, vpp, cnp)
@@ -100,65 +102,137 @@ cache_lookup(dvp, vpp, cnp)
struct vnode **vpp;
struct componentname *cnp;
{
- register struct namecache *ncp;
- register struct nchashhead *ncpp;
+ struct namecache *ncp;
+ struct nchashhead *ncpp;
+ struct vnode *vp;
+ struct proc *p = curproc;
+ u_long vpid;
+ int error;
if (!doingcache) {
cnp->cn_flags &= ~MAKEENTRY;
- return (0);
+ *vpp = NULL;
+ return (-1);
}
if (cnp->cn_namelen > NCHNAMLEN) {
nchstats.ncs_long++;
cnp->cn_flags &= ~MAKEENTRY;
- return (0);
+ *vpp = NULL;
+ return (-1);
}
+
ncpp = &nchashtbl[
hash32_buf(&dvp->v_id, sizeof(dvp->v_id), cnp->cn_hash) & nchash];
- for (ncp = ncpp->lh_first; ncp != 0; ncp = ncp->nc_hash.le_next) {
+ LIST_FOREACH(ncp, ncpp, nc_hash) {
if (ncp->nc_dvp == dvp &&
ncp->nc_dvpid == dvp->v_id &&
ncp->nc_nlen == cnp->cn_namelen &&
- !bcmp(ncp->nc_name, cnp->cn_nameptr, (u_int)ncp->nc_nlen))
+ !memcmp(ncp->nc_name, cnp->cn_nameptr, (u_int)ncp->nc_nlen))
break;
}
if (ncp == 0) {
nchstats.ncs_miss++;
- return (0);
+ *vpp = NULL;
+ return (-1);
}
if ((cnp->cn_flags & MAKEENTRY) == 0) {
nchstats.ncs_badhits++;
+ goto remove;
} else if (ncp->nc_vp == NULL) {
/*
* Restore the ISWHITEOUT flag saved earlier.
*/
cnp->cn_flags |= ncp->nc_vpid;
- if (cnp->cn_nameiop != CREATE) {
+ if (cnp->cn_nameiop != CREATE ||
+ (cnp->cn_flags & ISLASTCN) == 0) {
nchstats.ncs_neghits++;
/*
* Move this slot to end of LRU chain,
* if not already there.
*/
- if (ncp->nc_lru.tqe_next != 0) {
+ if (TAILQ_NEXT(ncp, nc_lru) != NULL) {
TAILQ_REMOVE(&nclruhead, ncp, nc_lru);
TAILQ_INSERT_TAIL(&nclruhead, ncp, nc_lru);
}
return (ENOENT);
+ } else {
+ nchstats.ncs_badhits++;
+ goto remove;
}
} else if (ncp->nc_vpid != ncp->nc_vp->v_id) {
nchstats.ncs_falsehits++;
+ goto remove;
+ }
+
+ vp = ncp->nc_vp;
+ vpid = vp->v_id;
+ if (vp == dvp) { /* lookup on "." */
+ VREF(dvp);
+ error = 0;
+ } else if (cnp->cn_flags & ISDOTDOT) {
+ VOP_UNLOCK(dvp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ error = vget(vp, LK_EXCLUSIVE, p);
+ /*
+ * If the above vget() succeeded and both LOCKPARENT and
+ * ISLASTCN is set, lock the directory vnode as well.
+ */
+ if (!error && (~cnp->cn_flags & (LOCKPARENT|ISLASTCN)) == 0) {
+ if ((error = vn_lock(dvp, LK_EXCLUSIVE, p)) != 0) {
+ vput(vp);
+ return (error);
+ }
+ cnp->cn_flags &= ~PDIRUNLOCK;
+ }
} else {
- nchstats.ncs_goodhits++;
+ error = vget(vp, LK_EXCLUSIVE, p);
/*
- * move this slot to end of LRU chain, if not already there
+ * If the above vget() failed or either of LOCKPARENT or
+ * ISLASTCN is set, unlock the directory vnode.
*/
- if (ncp->nc_lru.tqe_next != 0) {
- TAILQ_REMOVE(&nclruhead, ncp, nc_lru);
- TAILQ_INSERT_TAIL(&nclruhead, ncp, nc_lru);
+ if (error || (~cnp->cn_flags & (LOCKPARENT|ISLASTCN)) != 0) {
+ VOP_UNLOCK(dvp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
}
- *vpp = ncp->nc_vp;
+ }
+
+ /*
+ * Check that the lock succeeded, and that the capability number did
+ * not change while we were waiting for the lock.
+ */
+ if (error || vpid != vp->v_id) {
+ if (!error) {
+ vput(vp);
+ nchstats.ncs_falsehits++;
+ } else
+ nchstats.ncs_badhits++;
+ /*
+ * The parent needs to be locked when we return to VOP_LOOKUP().
+ * The `.' case here should be extremely rare (if it can happen
+ * at all), so we don't bother optimizing out the unlock/relock.
+ */
+ if (vp == dvp || error ||
+ (~cnp->cn_flags & (LOCKPARENT|ISLASTCN)) != 0) {
+ if ((error = vn_lock(dvp, LK_EXCLUSIVE, p)) != 0)
+ return (error);
+ cnp->cn_flags &= ~PDIRUNLOCK;
+ }
+ *vpp = NULL;
return (-1);
}
+ nchstats.ncs_goodhits++;
+ /*
+ * Move this slot to end of LRU chain, if not already there.
+ */
+ if (TAILQ_NEXT(ncp, nc_lru) != NULL) {
+ TAILQ_REMOVE(&nclruhead, ncp, nc_lru);
+ TAILQ_INSERT_TAIL(&nclruhead, ncp, nc_lru);
+ }
+ *vpp = vp;
+ return (0);
+
+remove:
/*
* Last component and we are renaming or deleting,
* the cache entry is invalid, or otherwise don't
@@ -166,9 +240,16 @@ cache_lookup(dvp, vpp, cnp)
*/
TAILQ_REMOVE(&nclruhead, ncp, nc_lru);
LIST_REMOVE(ncp, nc_hash);
- ncp->nc_hash.le_prev = 0;
+ ncp->nc_hash.le_prev = NULL;
+#if 0
+ if (ncp->nc_vhash.le_prev != NULL) {
+ LIST_REMOVE(ncp, nc_vhash);
+ ncp->nc_vhash.le_prev = NULL;
+ }
+#endif
TAILQ_INSERT_HEAD(&nclruhead, ncp, nc_lru);
- return (0);
+ *vpp = NULL;
+ return (-1);
}
/*
diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c
index 56aaaaa5ca9..b502f82ad85 100644
--- a/sys/kern/vfs_lookup.c
+++ b/sys/kern/vfs_lookup.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vfs_lookup.c,v 1.21 2002/08/27 16:04:42 mickey Exp $ */
+/* $OpenBSD: vfs_lookup.c,v 1.22 2003/01/31 17:37:50 art Exp $ */
/* $NetBSD: vfs_lookup.c,v 1.17 1996/02/09 19:00:59 christos Exp $ */
/*
@@ -289,6 +289,7 @@ lookup(ndp)
int wantparent; /* 1 => wantparent or lockparent flag */
int rdonly; /* lookup read-only flag bit */
int error = 0;
+ int dpunlocked = 0; /* dp has already been unlocked */
int slashes;
struct componentname *cnp = &ndp->ni_cnd;
struct proc *p = cnp->cn_proc;
@@ -439,6 +440,8 @@ dirloop:
unionlookup:
ndp->ni_dvp = dp;
ndp->ni_vp = NULL;
+ cnp->cn_flags &= ~PDIRUNLOCK;
+
if ((error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) != 0) {
#ifdef DIAGNOSTIC
if (ndp->ni_vp != NULL)
@@ -452,7 +455,10 @@ unionlookup:
(dp->v_mount->mnt_flag & MNT_UNION)) {
tdp = dp;
dp = dp->v_mount->mnt_vnodecovered;
- vput(tdp);
+ if (cnp->cn_flags & PDIRUNLOCK)
+ vrele(tdp);
+ else
+ vput(tdp);
VREF(dp);
vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
goto unionlookup;
@@ -517,11 +523,14 @@ unionlookup:
(cnp->cn_flags & NOCROSSMOUNT) == 0) {
if (vfs_busy(mp, 0, 0, p))
continue;
+ VOP_UNLOCK(dp, 0, p);
error = VFS_ROOT(mp, &tdp);
vfs_unbusy(mp, p);
- if (error)
+ if (error) {
+ dpunlocked = 1;
goto bad2;
- vput(dp);
+ }
+ vrele(dp);
ndp->ni_vp = dp = tdp;
}
@@ -585,11 +594,15 @@ terminal:
return (0);
bad2:
- if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))
+ if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN) &&
+ ((cnp->cn_flags & PDIRUNLOCK) == 0))
VOP_UNLOCK(ndp->ni_dvp, 0, p);
vrele(ndp->ni_dvp);
bad:
- vput(dp);
+ if (dpunlocked)
+ vrele(dp);
+ else
+ vput(dp);
ndp->ni_vp = NULL;
return (error);
}
diff --git a/sys/miscfs/fdesc/fdesc_vnops.c b/sys/miscfs/fdesc/fdesc_vnops.c
index c54cbe0a4e3..1e96dc206d3 100644
--- a/sys/miscfs/fdesc/fdesc_vnops.c
+++ b/sys/miscfs/fdesc/fdesc_vnops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: fdesc_vnops.c,v 1.32 2002/08/23 15:39:31 art Exp $ */
+/* $OpenBSD: fdesc_vnops.c,v 1.33 2003/01/31 17:37:50 art Exp $ */
/* $NetBSD: fdesc_vnops.c,v 1.32 1996/04/11 11:24:29 mrg Exp $ */
/*
@@ -254,11 +254,9 @@ fdesc_lookup(v)
struct vnode *fvp;
char *ln;
- VOP_UNLOCK(dvp, 0, p);
if (cnp->cn_namelen == 1 && *pname == '.') {
*vpp = dvp;
VREF(dvp);
- vn_lock(dvp, LK_SHARED | LK_RETRY, p);
return (0);
}
@@ -277,8 +275,7 @@ fdesc_lookup(v)
goto bad;
*vpp = fvp;
fvp->v_type = VDIR;
- vn_lock(fvp, LK_SHARED | LK_RETRY, p);
- return (0);
+ goto good;
}
if (cnp->cn_namelen == 3 && bcmp(pname, "tty", 3) == 0) {
@@ -292,8 +289,7 @@ fdesc_lookup(v)
goto bad;
*vpp = fvp;
fvp->v_type = VCHR;
- vn_lock(fvp, LK_SHARED | LK_RETRY, p);
- return (0);
+ goto good;
}
ln = 0;
@@ -323,8 +319,7 @@ fdesc_lookup(v)
VTOFDESC(fvp)->fd_link = ln;
*vpp = fvp;
fvp->v_type = VLNK;
- vn_lock(fvp, LK_SHARED | LK_RETRY, p);
- return (0);
+ goto good;
} else {
error = ENOENT;
goto bad;
@@ -334,10 +329,18 @@ fdesc_lookup(v)
case Fdevfd:
if (cnp->cn_namelen == 2 && bcmp(pname, "..", 2) == 0) {
- if ((error = fdesc_root(dvp->v_mount, vpp)))
+ VOP_UNLOCK(dvp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ error = fdesc_root(dvp->v_mount, vpp);
+ if (error)
goto bad;
-
- return (0);
+ /* If we're at the last component and need the
+ * parent locked, undo the unlock above.
+ */
+ if (((~cnp->cn_flags & (ISLASTCN | LOCKPARENT)) == 0) &&
+ ((error = vn_lock(dvp, LK_EXCLUSIVE, p)) == 0))
+ cnp->cn_flags &= ~PDIRUNLOCK;
+ return (error);
}
fd = 0;
@@ -361,15 +364,26 @@ fdesc_lookup(v)
if (error)
goto bad;
VTOFDESC(fvp)->fd_fd = fd;
- vn_lock(fvp, LK_SHARED | LK_RETRY, p);
*vpp = fvp;
- return (0);
+ goto good;
}
-bad:;
- vn_lock(dvp, LK_SHARED | LK_RETRY, p);
+bad:
*vpp = NULL;
return (error);
+
+good:
+ /*
+ * As "." was special cased above, we now unlock the parent if we're
+ * supposed to. We're only supposed to not unlock if this is the
+ * last component, and the caller requested LOCKPARENT. So if either
+ * condition is false, unlock.
+ */
+ if (((~cnp->cn_flags) & (ISLASTCN | LOCKPARENT)) != 0) {
+ VOP_UNLOCK(dvp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
+ return (0);
}
int
diff --git a/sys/miscfs/kernfs/kernfs_vfsops.c b/sys/miscfs/kernfs/kernfs_vfsops.c
index 68ded75d74b..561c2c4e904 100644
--- a/sys/miscfs/kernfs/kernfs_vfsops.c
+++ b/sys/miscfs/kernfs/kernfs_vfsops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kernfs_vfsops.c,v 1.19 2002/10/12 02:03:46 krw Exp $ */
+/* $OpenBSD: kernfs_vfsops.c,v 1.20 2003/01/31 17:37:50 art Exp $ */
/* $NetBSD: kernfs_vfsops.c,v 1.26 1996/04/22 01:42:27 christos Exp $ */
/*
@@ -102,7 +102,10 @@ kernfs_mount(mp, path, data, ndp, p)
struct nameidata *ndp;
struct proc *p;
{
+ int error = 0;
size_t size;
+ struct vnode *rvp;
+ struct kern_target *kt;
#ifdef KERNFS_DIAGNOSTIC
printf("kernfs_mount(mp = %p)\n", mp);
@@ -114,7 +117,17 @@ kernfs_mount(mp, path, data, ndp, p)
if (mp->mnt_flag & MNT_UPDATE)
return (EOPNOTSUPP);
+ kt = kernfs_findtarget(".", 1);
+ error = kernfs_allocvp(kt, mp, &rvp);
+ if (error)
+ return (error);
+
+ rvp->v_type = VDIR;
+ rvp->v_flag |= VROOT;
+
mp->mnt_flag |= MNT_LOCAL;
+ mp->mnt_data = (qaddr_t)rvp;
+ vrele(rvp);
vfs_getnewfsid(mp);
(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
@@ -158,8 +171,12 @@ kernfs_unmount(mp, mntflags, p)
#ifdef KERNFS_DIAGNOSTIC
printf("kernfs_unmount: calling vflush\n");
#endif
- if ((error = vflush(mp, 0, flags)) != 0)
+
+ if ((error = vflush(mp, 0, flags)) != 0) {
return (error);
+ }
+
+ mp->mnt_data = 0;
return (0);
}
@@ -169,24 +186,16 @@ kernfs_root(mp, vpp)
struct mount *mp;
struct vnode **vpp;
{
- struct kern_target *kt;
- int error;
+ struct vnode *vp = (struct vnode *)mp->mnt_data;
#ifdef KERNFS_DIAGNOSTIC
printf("kernfs_root(mp = %p)\n", mp);
#endif
- kt = kernfs_findtarget(".", 1);
- /* this should never happen */
- if (kt == NULL)
- panic("kernfs_root: findtarget returned NULL");
-
- error = kernfs_allocvp(kt, mp, vpp);
- /* this should never happen */
- if (error)
- panic("kernfs_root: couldn't find root");
-
- return(0);
-
+
+ vget(vp, LK_EXCLUSIVE | LK_RETRY, curproc);
+ *vpp = vp;
+
+ return (0);
}
int
diff --git a/sys/miscfs/kernfs/kernfs_vnops.c b/sys/miscfs/kernfs/kernfs_vnops.c
index 269c0842653..3db0fadc84e 100644
--- a/sys/miscfs/kernfs/kernfs_vnops.c
+++ b/sys/miscfs/kernfs/kernfs_vnops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kernfs_vnops.c,v 1.28 2002/10/12 02:03:46 krw Exp $ */
+/* $OpenBSD: kernfs_vnops.c,v 1.29 2003/01/31 17:37:50 art Exp $ */
/* $NetBSD: kernfs_vnops.c,v 1.43 1996/03/16 23:52:47 christos Exp $ */
/*
@@ -287,7 +287,6 @@ kernfs_freevp(vp, p)
struct kernfs_node *kf = VTOKERN(vp);
TAILQ_REMOVE(&kfshead, kf, list);
- VOP_UNLOCK(vp, 0, p);
FREE(vp->v_data, M_TEMP);
vp->v_data = 0;
return(0);
@@ -487,15 +486,16 @@ kernfs_lookup(v)
struct proc *p = cnp->cn_proc;
struct kern_target *kt;
struct vnode *vp;
- int error;
+ int error, wantpunlock;
#ifdef KERNFS_DIAGNOSTIC
printf("kernfs_lookup(%p)\n", ap);
printf("kernfs_lookup(dp = %p, vpp = %p, cnp = %p)\n", dvp, vpp, ap->a_cnp);
printf("kernfs_lookup(%s)\n", pname);
#endif
- VOP_UNLOCK(dvp, 0, p);
+
*vpp = NULLVP;
+ cnp->cn_flags &= ~PDIRUNLOCK;
if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
return (EROFS);
@@ -503,14 +503,14 @@ kernfs_lookup(v)
if (cnp->cn_namelen == 1 && *pname == '.') {
*vpp = dvp;
VREF(dvp);
- vn_lock(dvp, LK_SHARED | LK_RETRY, p);
return (0);
}
+ wantpunlock = (~cnp->cn_flags & (LOCKPARENT | ISLASTCN));
+
kt = kernfs_findtarget(pname, cnp->cn_namelen);
if (kt == NULL) {
/* not found */
- vn_lock(dvp, LK_SHARED | LK_RETRY, p);
return(cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS);
}
@@ -524,17 +524,25 @@ kernfs_lookup(v)
*vpp = vp;
if (vget(vp, LK_EXCLUSIVE, p))
goto loop;
+ if (wantpunlock) {
+ VOP_UNLOCK(dvp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
return(0);
}
if ((error = kernfs_allocvp(kt, dvp->v_mount, vpp)) != 0) {
- vn_lock(dvp, LK_SHARED | LK_RETRY, p);
return(error);
}
vn_lock(*vpp, LK_SHARED | LK_RETRY, p);
- return(error);
+
+ if (wantpunlock) {
+ VOP_UNLOCK(dvp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
+ return (0);
}
/*ARGSUSED*/
diff --git a/sys/miscfs/portal/portal_vnops.c b/sys/miscfs/portal/portal_vnops.c
index 5eb8a967ac9..c0b05be010a 100644
--- a/sys/miscfs/portal/portal_vnops.c
+++ b/sys/miscfs/portal/portal_vnops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: portal_vnops.c,v 1.12 2002/03/14 01:27:08 millert Exp $ */
+/* $OpenBSD: portal_vnops.c,v 1.13 2003/01/31 17:37:50 art Exp $ */
/* $NetBSD: portal_vnops.c,v 1.17 1996/02/13 13:12:57 mycroft Exp $ */
/*
@@ -187,6 +187,7 @@ portal_lookup(v)
struct vnode **vpp = ap->a_vpp;
struct vnode *dvp = ap->a_dvp;
char *pname = cnp->cn_nameptr;
+ struct proc *p = cnp->cn_proc;
struct portalnode *pt;
int error;
struct vnode *fvp = 0;
@@ -201,7 +202,6 @@ portal_lookup(v)
if (cnp->cn_namelen == 1 && *pname == '.') {
*vpp = dvp;
VREF(dvp);
- /*VOP_LOCK(dvp);*/
return (0);
}
@@ -228,7 +228,15 @@ portal_lookup(v)
pt->pt_fileid = portal_fileid++;
*vpp = fvp;
- /*VOP_LOCK(fvp);*/
+ VOP_LOCK(fvp, LK_EXCLUSIVE, p);
+ /*
+ * As we are the last component of the path name, fix up
+ * the locking on the directory node.
+ */
+ if ((cnp->cn_flags & LOCKPARENT) == 0) {
+ VOP_UNLOCK(dvp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
return (0);
bad:;
diff --git a/sys/miscfs/procfs/procfs.h b/sys/miscfs/procfs/procfs.h
index 9ee10e559fa..83577da1934 100644
--- a/sys/miscfs/procfs/procfs.h
+++ b/sys/miscfs/procfs/procfs.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: procfs.h,v 1.15 2002/03/14 01:27:08 millert Exp $ */
+/* $OpenBSD: procfs.h,v 1.16 2003/01/31 17:37:50 art Exp $ */
/* $NetBSD: procfs.h,v 1.17 1996/02/12 15:01:41 christos Exp $ */
/*
@@ -104,6 +104,7 @@ struct procfs_args {
struct procfsmount {
void *pmnt_exechook;
int pmnt_flags;
+ struct vnode *rvp;
};
#define VFSTOPROC(mp) ((struct procfsmount *)(mp)->mnt_data)
diff --git a/sys/miscfs/procfs/procfs_vfsops.c b/sys/miscfs/procfs/procfs_vfsops.c
index 899369f0ffa..166de670487 100644
--- a/sys/miscfs/procfs/procfs_vfsops.c
+++ b/sys/miscfs/procfs/procfs_vfsops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: procfs_vfsops.c,v 1.16 2002/03/14 01:27:08 millert Exp $ */
+/* $OpenBSD: procfs_vfsops.c,v 1.17 2003/01/31 17:37:50 art Exp $ */
/* $NetBSD: procfs_vfsops.c,v 1.25 1996/02/09 22:40:53 christos Exp $ */
/*
@@ -82,6 +82,7 @@ procfs_mount(mp, path, data, ndp, p)
size_t size;
struct procfsmount *pmnt;
struct procfs_args args;
+ struct vnode *rvp;
int error;
if (UIO_MX & (UIO_MX-1)) {
@@ -102,10 +103,18 @@ procfs_mount(mp, path, data, ndp, p)
} else
args.flags = 0;
+ error = procfs_allocvp(mp, &rvp, 0, Proot);
+ if (error)
+ return (error);
+ rvp->v_type = VDIR;
+ rvp->v_flag |= VROOT;
+
mp->mnt_flag |= MNT_LOCAL;
pmnt = (struct procfsmount *) malloc(sizeof(struct procfsmount),
M_UFSMNT, M_WAITOK); /* XXX need new malloc type */
+ pmnt->rvp = rvp;
+
mp->mnt_data = (qaddr_t)pmnt;
vfs_getnewfsid(mp);
@@ -134,6 +143,7 @@ procfs_unmount(mp, mntflags, p)
int error;
extern int doforce;
int flags = 0;
+ struct vnode *rvp = VFSTOPROC(mp)->rvp;
if (mntflags & MNT_FORCE) {
/* procfs can never be rootfs so don't check for it */
@@ -142,8 +152,15 @@ procfs_unmount(mp, mntflags, p)
flags |= FORCECLOSE;
}
- if ((error = vflush(mp, 0, flags)) != 0)
+ vrele(rvp);
+
+ if ((error = vflush(mp, 0, flags)) != 0) {
+ vget(rvp, 0, curproc);
return (error);
+ }
+
+ free(VFSTOPROC(mp), M_UFSMNT);
+ mp->mnt_data = 0;
return (0);
}
@@ -153,8 +170,13 @@ procfs_root(mp, vpp)
struct mount *mp;
struct vnode **vpp;
{
+ struct vnode *vp = VFSTOPROC(mp)->rvp;
- return (procfs_allocvp(mp, vpp, 0, Proot));
+ VREF(vp);
+ vn_lock(vp, LK_EXCLUSIVE, curproc);
+ *vpp = vp;
+
+ return (0);
}
/* ARGSUSED */
diff --git a/sys/miscfs/procfs/procfs_vnops.c b/sys/miscfs/procfs/procfs_vnops.c
index 9848edcadd5..4b0ec1630bd 100644
--- a/sys/miscfs/procfs/procfs_vnops.c
+++ b/sys/miscfs/procfs/procfs_vnops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: procfs_vnops.c,v 1.26 2002/04/06 23:40:13 miod Exp $ */
+/* $OpenBSD: procfs_vnops.c,v 1.27 2003/01/31 17:37:50 art Exp $ */
/* $NetBSD: procfs_vnops.c,v 1.40 1996/03/16 23:52:55 christos Exp $ */
/*
@@ -751,9 +751,10 @@ procfs_lookup(v)
pid_t pid;
struct pfsnode *pfs;
struct proc *p = NULL;
- int i, error, iscurproc = 0, isself = 0;
+ int i, error, wantpunlock, iscurproc = 0, isself = 0;
*vpp = NULL;
+ cnp->cn_flags &= ~PDIRUNLOCK;
if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
return (EROFS);
@@ -761,10 +762,10 @@ procfs_lookup(v)
if (cnp->cn_namelen == 1 && *pname == '.') {
*vpp = dvp;
VREF(dvp);
- /*VOP_LOCK(dvp);*/
return (0);
}
+ wantpunlock = (~cnp->cn_flags & (LOCKPARENT | ISLASTCN));
pfs = VTOPFS(dvp);
switch (pfs->pfs_type) {
case Proot:
@@ -777,12 +778,10 @@ procfs_lookup(v)
if (iscurproc || isself) {
error = procfs_allocvp(dvp->v_mount, vpp, 0,
iscurproc ? Pcurproc : Pself);
-#if 0
if ((error == 0) && (wantpunlock)) {
- VOP_UNLOCK(dvp, 0);
+ VOP_UNLOCK(dvp, 0, curp);
cnp->cn_flags |= PDIRUNLOCK;
}
-#endif
return (error);
}
@@ -798,12 +797,10 @@ procfs_lookup(v)
if (i != nproc_root_targets) {
error = procfs_allocvp(dvp->v_mount, vpp, 0,
pt->pt_pfstype);
-#if 0
if ((error == 0) && (wantpunlock)) {
- VOP_UNLOCK(dvp, 0);
+ VOP_UNLOCK(dvp, 0, curp);
cnp->cn_flags |= PDIRUNLOCK;
}
-#endif
return (error);
}
@@ -815,11 +812,29 @@ procfs_lookup(v)
if (p == 0)
break;
- return (procfs_allocvp(dvp->v_mount, vpp, pid, Pproc));
+ error = procfs_allocvp(dvp->v_mount, vpp, pid, Pproc);
+ if ((error == 0) && wantpunlock) {
+ VOP_UNLOCK(dvp, 0, curp);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
+ return (error);
case Pproc:
- if (cnp->cn_flags & ISDOTDOT)
- return (procfs_root(dvp->v_mount, vpp));
+ /*
+ * do the .. dance. We unlock the directory, and then
+ * get the root dir. That will automatically return ..
+ * locked. Then if the caller wanted dvp locked, we
+ * re-lock.
+ */
+ if (cnp->cn_flags & ISDOTDOT) {
+ VOP_UNLOCK(dvp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ error = procfs_root(dvp->v_mount, vpp);
+ if ((error == 0) && (wantpunlock == 0) &&
+ ((error = vn_lock(dvp, LK_EXCLUSIVE, curp)) == 0))
+ cnp->cn_flags &= ~PDIRUNLOCK;
+ return (error);
+ }
p = pfind(pfs->pfs_pid);
if (p == 0)
@@ -840,12 +855,21 @@ procfs_lookup(v)
/* We already checked that it exists. */
VREF(fvp);
vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, curp);
+ if (wantpunlock) {
+ VOP_UNLOCK(dvp, 0, curp);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
*vpp = fvp;
return (0);
}
- return (procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
- pt->pt_pfstype));
+ error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
+ pt->pt_pfstype);
+ if ((error == 0) && (wantpunlock)) {
+ VOP_UNLOCK(dvp, 0, curp);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
+ return (error);
default:
return (ENOTDIR);
diff --git a/sys/msdosfs/msdosfs_lookup.c b/sys/msdosfs/msdosfs_lookup.c
index 1a6baa0233b..1778a741972 100644
--- a/sys/msdosfs/msdosfs_lookup.c
+++ b/sys/msdosfs/msdosfs_lookup.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: msdosfs_lookup.c,v 1.11 1999/02/19 17:26:17 art Exp $ */
+/* $OpenBSD: msdosfs_lookup.c,v 1.12 2003/01/31 17:37:50 art Exp $ */
/* $NetBSD: msdosfs_lookup.c,v 1.34 1997/10/18 22:12:27 ws Exp $ */
/*-
@@ -110,12 +110,15 @@ msdosfs_lookup(v)
struct buf *bp = 0;
struct direntry *dep;
u_char dosfilename[12];
- int flags = cnp->cn_flags;
+ int flags;
int nameiop = cnp->cn_nameiop;
int wincnt = 1;
int chksum = -1;
int olddos = 1;
-
+
+ cnp->cn_flags &= ~PDIRUNLOCK; /* XXX why this ?? */
+ flags = cnp->cn_flags;
+
#ifdef MSDOSFS_DEBUG
printf("msdosfs_lookup(): looking for %s\n", cnp->cn_nameptr);
#endif
@@ -144,56 +147,8 @@ msdosfs_lookup(v)
* check the name cache to see if the directory/name pair
* we are looking for is known already.
*/
- if ((error = cache_lookup(vdp, vpp, cnp)) != 0) {
- int vpid;
-
- if (error == ENOENT)
- return (error);
- /*
- * Get the next vnode in the path.
- * See comment below starting `Step through' for
- * an explaination of the locking protocol.
- */
- pdp = vdp;
- dp = VTODE(*vpp);
- vdp = *vpp;
- vpid = vdp->v_id;
- if (pdp == vdp) { /* lookup on "." */
- VREF(vdp);
- error = 0;
- } else if (flags & ISDOTDOT) {
- VOP_UNLOCK(pdp, 0, p);
- error = vget(vdp, LK_EXCLUSIVE, p);
- if (!error && lockparent && (flags & ISLASTCN))
- error =
- vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p);
- } else {
- error = vget(vdp, LK_EXCLUSIVE, p);
- if (!lockparent || error || !(flags & ISLASTCN))
- VOP_UNLOCK(pdp, 0, p);
- }
- /*
- * Check that the capability number did not change
- * while we were waiting for the lock.
- */
- if (!error) {
- if (vpid == vdp->v_id) {
-#ifdef MSDOSFS_DEBUG
- printf("msdosfs_lookup(): cache hit, vnode %08x, file %s\n",
- vdp, dp->de_Name);
-#endif
- return (0);
- }
- vput(vdp);
- if (lockparent && pdp != vdp && (flags & ISLASTCN))
- VOP_UNLOCK(pdp, 0, p);
- }
- if ((error = vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p)) != 0)
- return (error);
- vdp = pdp;
- dp = VTODE(vdp);
- *vpp = NULL;
- }
+ if ((error = cache_lookup(vdp, vpp, cnp)) >= 0)
+ return (error);
/*
* If they are going after the . or .. entry in the root directory,
@@ -415,8 +370,10 @@ notfound:;
* information cannot be used.
*/
cnp->cn_flags |= SAVENAME;
- if (!lockparent)
+ if (!lockparent) {
VOP_UNLOCK(vdp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
return (EJUSTRETURN);
}
/*
@@ -504,8 +461,10 @@ foundroot:;
if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
return (error);
*vpp = DETOV(tdp);
- if (!lockparent)
+ if (!lockparent) {
VOP_UNLOCK(vdp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
return (0);
}
@@ -562,14 +521,19 @@ foundroot:;
pdp = vdp;
if (flags & ISDOTDOT) {
VOP_UNLOCK(pdp, 0, p); /* race to get the inode */
+ cnp->cn_flags |= PDIRUNLOCK;
if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0) {
- vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p);
+ if (vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p) == 0)
+ cnp->cn_flags &= ~PDIRUNLOCK;
return (error);
}
- if (lockparent && (flags & ISLASTCN) &&
- (error = vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p))) {
- vput(DETOV(tdp));
- return (error);
+ if (lockparent && (flags & ISLASTCN)) {
+ if ((error = vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY,
+ p))) {
+ vput(DETOV(tdp));
+ return (error);
+ }
+ cnp->cn_flags &= ~PDIRUNLOCK;
}
*vpp = DETOV(tdp);
} else if (dp->de_StartCluster == scn && isadir) {
@@ -578,8 +542,10 @@ foundroot:;
} else {
if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
return (error);
- if (!lockparent || !(flags & ISLASTCN))
+ if (!lockparent || !(flags & ISLASTCN)) {
VOP_UNLOCK(pdp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
*vpp = DETOV(tdp);
}
diff --git a/sys/nfs/nfs_vnops.c b/sys/nfs/nfs_vnops.c
index b0875e2b024..bc9f53d8291 100644
--- a/sys/nfs/nfs_vnops.c
+++ b/sys/nfs/nfs_vnops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: nfs_vnops.c,v 1.52 2002/11/08 04:34:17 art Exp $ */
+/* $OpenBSD: nfs_vnops.c,v 1.53 2003/01/31 17:37:50 art Exp $ */
/* $NetBSD: nfs_vnops.c,v 1.62.4.1 1996/07/08 20:26:52 jtc Exp $ */
/*
@@ -636,7 +636,7 @@ nfs_lookup(v)
struct vnode *dvp = ap->a_dvp;
struct vnode **vpp = ap->a_vpp;
struct proc *p = cnp->cn_proc;
- int flags = cnp->cn_flags;
+ int flags;
struct vnode *newvp;
u_int32_t *tl;
caddr_t cp;
@@ -650,6 +650,9 @@ nfs_lookup(v)
int lockparent, wantparent, error = 0, attrflag, fhsize;
int v3 = NFS_ISV3(dvp);
+ cnp->cn_flags &= ~PDIRUNLOCK;
+ flags = cnp->cn_flags;
+
*vpp = NULLVP;
if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
(cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
@@ -660,38 +663,76 @@ nfs_lookup(v)
wantparent = flags & (LOCKPARENT|WANTPARENT);
nmp = VFSTONFS(dvp->v_mount);
np = VTONFS(dvp);
- if ((error = cache_lookup(dvp, vpp, cnp)) != 0 && error != ENOENT) {
+
+ /*
+ * Before tediously performing a linear scan of the directory,
+ * check the name cache to see if the directory/name pair
+ * we are looking for is known already.
+ * If the directory/name pair is found in the name cache,
+ * we have to ensure the directory has not changed from
+ * the time the cache entry has been created. If it has,
+ * the cache entry has to be ignored.
+ */
+ if ((error = cache_lookup(dvp, vpp, cnp)) >= 0) {
struct vattr vattr;
- int vpid;
+ int err2;
- newvp = *vpp;
- vpid = newvp->v_id;
- /*
- * See the comment starting `Step through' in ufs/ufs_lookup.c
- * for an explanation of the locking protocol
- */
- if (dvp == newvp) {
- VREF(newvp);
- error = 0;
- } else
- error = vget(newvp, LK_EXCLUSIVE, p);
+ if (error && error != ENOENT) {
+ *vpp = NULLVP;
+ return (error);
+ }
- if (!error) {
- if (vpid == newvp->v_id) {
- if (!VOP_GETATTR(newvp, &vattr, cnp->cn_cred, cnp->cn_proc)
- && vattr.va_ctime.tv_sec == VTONFS(newvp)->n_ctime) {
- nfsstats.lookupcache_hits++;
- if (cnp->cn_nameiop != LOOKUP &&
- (flags & ISLASTCN))
- cnp->cn_flags |= SAVENAME;
- return (0);
- }
- cache_purge(newvp);
+ if (cnp->cn_flags & PDIRUNLOCK) {
+ err2 = vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
+ if (err2 != 0) {
+ *vpp = NULLVP;
+ return (err2);
}
- vrele(newvp);
+ cnp->cn_flags &= ~PDIRUNLOCK;
+ }
+
+ err2 = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, cnp->cn_proc);
+ if (err2 != 0) {
+ if (error == 0) {
+ if (*vpp != dvp)
+ vput(*vpp);
+ else
+ vrele(*vpp);
+ }
+ *vpp = NULLVP;
+ return (err2);
}
+
+ if (error == ENOENT) {
+ if (!VOP_GETATTR(dvp, &vattr, cnp->cn_cred,
+ cnp->cn_proc) && vattr.va_mtime.tv_sec ==
+ VTONFS(dvp)->n_ctime)
+ return (ENOENT);
+ cache_purge(dvp);
+ np->n_ctime = 0;
+ goto dorpc;
+ }
+
+ newvp = *vpp;
+ if (!VOP_GETATTR(newvp, &vattr, cnp->cn_cred, cnp->cn_proc)
+ && vattr.va_ctime.tv_sec == VTONFS(newvp)->n_ctime)
+ {
+ nfsstats.lookupcache_hits++;
+ if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
+ cnp->cn_flags |= SAVENAME;
+ if ((!lockparent || !(flags & ISLASTCN)) &&
+ newvp != dvp)
+ VOP_UNLOCK(dvp, 0, p);
+ return (0);
+ }
+ cache_purge(newvp);
+ if (newvp != dvp)
+ vput(newvp);
+ else
+ vrele(newvp);
*vpp = NULLVP;
}
+dorpc:
error = 0;
newvp = NULLVP;
nfsstats.lookupcache_misses++;
@@ -731,25 +772,72 @@ nfs_lookup(v)
*vpp = newvp;
m_freem(mrep);
cnp->cn_flags |= SAVENAME;
+ if (!lockparent) {
+ VOP_UNLOCK(dvp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
return (0);
}
+ /*
+ * The postop attr handling is duplicated for each if case,
+ * because it should be done while dvp is locked (unlocking
+ * dvp is different for each case).
+ */
+
if (NFS_CMPFH(np, fhp, fhsize)) {
VREF(dvp);
newvp = dvp;
- } else {
+ if (v3) {
+ nfsm_postop_attr(newvp, attrflag);
+ nfsm_postop_attr(dvp, attrflag);
+ } else
+ nfsm_loadattr(newvp, (struct vattr *)0);
+ } else if (flags & ISDOTDOT) {
+ VOP_UNLOCK(dvp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+
error = nfs_nget(dvp->v_mount, fhp, fhsize, &np);
if (error) {
+ if (vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p) == 0)
+ cnp->cn_flags &= ~PDIRUNLOCK;
m_freem(mrep);
return (error);
}
newvp = NFSTOV(np);
+
+ if (v3) {
+ nfsm_postop_attr(newvp, attrflag);
+ nfsm_postop_attr(dvp, attrflag);
+ } else
+ nfsm_loadattr(newvp, (struct vattr *)0);
+
+ if (lockparent && (flags & ISLASTCN)) {
+ if ((error = vn_lock(dvp, LK_EXCLUSIVE, p))) {
+ m_freem(mrep);
+ vput(newvp);
+ return error;
+ }
+ cnp->cn_flags &= ~PDIRUNLOCK;
+ }
+
+ } else {
+ error = nfs_nget(dvp->v_mount, fhp, fhsize, &np);
+ if (error) {
+ m_freem(mrep);
+ return error;
+ }
+ newvp = NFSTOV(np);
+ if (v3) {
+ nfsm_postop_attr(newvp, attrflag);
+ nfsm_postop_attr(dvp, attrflag);
+ } else
+ nfsm_loadattr(newvp, (struct vattr *)0);
+ if (!lockparent || !(flags & ISLASTCN)) {
+ VOP_UNLOCK(dvp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
}
- if (v3) {
- nfsm_postop_attr(newvp, attrflag);
- nfsm_postop_attr(dvp, attrflag);
- } else
- nfsm_loadattr(newvp, (struct vattr *)0);
if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
cnp->cn_flags |= SAVENAME;
if ((cnp->cn_flags & MAKEENTRY) &&
@@ -760,8 +848,24 @@ nfs_lookup(v)
*vpp = newvp;
nfsm_reqdone;
if (error) {
- if (newvp != NULLVP)
+ /*
+ * We get here only because of errors returned by
+ * the RPC. Otherwise we'll have returned above
+ * (the nfsm_* macros will jump to nfsm_reqdone
+ * on error).
+ */
+ if (error == ENOENT && (cnp->cn_flags & MAKEENTRY) &&
+ cnp->cn_nameiop != CREATE) {
+ if (VTONFS(dvp)->n_ctime == 0)
+ VTONFS(dvp)->n_ctime =
+ VTONFS(dvp)->n_vattr.va_mtime.tv_sec;
+ cache_enter(dvp, NULL, cnp);
+ }
+ if (newvp != NULLVP) {
vrele(newvp);
+ if (newvp != dvp)
+ VOP_UNLOCK(newvp, 0, p);
+ }
if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
(flags & ISLASTCN) && error == ENOENT) {
if (dvp->v_mount->mnt_flag & MNT_RDONLY)
@@ -771,6 +875,7 @@ nfs_lookup(v)
}
if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
cnp->cn_flags |= SAVENAME;
+ *vpp = NULL;
}
return (error);
}
diff --git a/sys/sys/namei.h b/sys/sys/namei.h
index 2a9aab95d36..1663891d357 100644
--- a/sys/sys/namei.h
+++ b/sys/sys/namei.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: namei.h,v 1.9 2002/07/03 21:19:08 miod Exp $ */
+/* $OpenBSD: namei.h,v 1.10 2003/01/31 17:37:50 art Exp $ */
/* $NetBSD: namei.h,v 1.11 1996/02/09 18:25:20 christos Exp $ */
/*
@@ -140,7 +140,8 @@ struct nameidata {
#define DOWHITEOUT 0x040000 /* do whiteouts */
#define REQUIREDIR 0x080000 /* must be a directory */
#define STRIPSLASHES 0x100000 /* strip trailing slashes */
-#define PARAMASK 0x1fff00 /* mask of parameter descriptors */
+#define PDIRUNLOCK 0x200000 /* vfs_lookup() unlocked parent dir */
+#define PARAMASK 0x2fff00 /* mask of parameter descriptors */
/*
* Initialization of an nameidata structure.
*/
diff --git a/sys/ufs/ext2fs/ext2fs_lookup.c b/sys/ufs/ext2fs/ext2fs_lookup.c
index b5c21c3957e..cf22aa06846 100644
--- a/sys/ufs/ext2fs/ext2fs_lookup.c
+++ b/sys/ufs/ext2fs/ext2fs_lookup.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ext2fs_lookup.c,v 1.14 2002/10/12 01:09:45 krw Exp $ */
+/* $OpenBSD: ext2fs_lookup.c,v 1.15 2003/01/31 17:37:50 art Exp $ */
/* $NetBSD: ext2fs_lookup.c,v 1.16 2000/08/03 20:29:26 thorpej Exp $ */
/*
@@ -317,50 +317,8 @@ ext2fs_lookup(v)
* check the name cache to see if the directory/name pair
* we are looking for is known already.
*/
- if ((error = cache_lookup(vdp, vpp, cnp)) != 0) {
- int vpid; /* capability number of vnode */
-
- if (error == ENOENT)
- return (error);
- /*
- * Get the next vnode in the path.
- * See comment below starting `Step through' for
- * an explaination of the locking protocol.
- */
- pdp = vdp;
- dp = VTOI(*vpp);
- vdp = *vpp;
- vpid = vdp->v_id;
- if (pdp == vdp) { /* lookup on "." */
- VREF(vdp);
- error = 0;
- } else if (flags & ISDOTDOT) {
- VOP_UNLOCK(pdp, 0, p);
- error = vget(vdp, LK_EXCLUSIVE, p);
- if (!error && lockparent && (flags & ISLASTCN))
- error = vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p);
- } else {
- error = vget(vdp, LK_EXCLUSIVE, p);
- if (!lockparent || error || !(flags & ISLASTCN))
- VOP_UNLOCK(pdp, 0, p);
- }
- /*
- * Check that the capability number did not change
- * while we were waiting for the lock.
- */
- if (!error) {
- if (vpid == vdp->v_id)
- return (0);
- vput(vdp);
- if (lockparent && pdp != vdp && (flags & ISLASTCN))
- VOP_UNLOCK(pdp, 0, p);
- }
- if ((error = vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p)) != 0)
- return (error);
- vdp = pdp;
- dp = VTOI(pdp);
- *vpp = NULL;
- }
+ if ((error = cache_lookup(vdp, vpp, cnp)) >= 0)
+ return (error);
/*
* Suppress search for slots unless creating
@@ -570,8 +528,10 @@ searchloop:
* information cannot be used.
*/
cnp->cn_flags |= SAVENAME;
- if (!lockparent)
+ if (!lockparent) {
VOP_UNLOCK(vdp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
return (EJUSTRETURN);
}
/*
@@ -646,8 +606,10 @@ found:
return (EPERM);
}
*vpp = tdp;
- if (!lockparent)
+ if (!lockparent) {
VOP_UNLOCK(vdp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
return (0);
}
@@ -671,8 +633,10 @@ found:
return (error);
*vpp = tdp;
cnp->cn_flags |= SAVENAME;
- if (!lockparent)
+ if (!lockparent) {
VOP_UNLOCK(vdp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
return (0);
}
@@ -698,14 +662,18 @@ found:
pdp = vdp;
if (flags & ISDOTDOT) {
VOP_UNLOCK(pdp, 0, p); /* race to get the inode */
+ cnp->cn_flags |= PDIRUNLOCK;
if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0) {
- vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p);
+ if (vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p) == 0)
+ cnp->cn_flags &= ~PDIRUNLOCK;
return (error);
}
- if (lockparent && (flags & ISLASTCN) &&
- (error = vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p)) != 0) {
- vput(tdp);
- return (error);
+ if (lockparent && (flags & ISLASTCN)) {
+ if ((error = vn_lock(pdp, LK_EXCLUSIVE, p)) != 0) {
+ vput(tdp);
+ return (error);
+ }
+ cnp->cn_flags &= ~PDIRUNLOCK;
}
*vpp = tdp;
} else if (dp->i_number == dp->i_ino) {
@@ -714,8 +682,10 @@ found:
} else {
if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0)
return (error);
- if (!lockparent || !(flags & ISLASTCN))
+ if (!lockparent || !(flags & ISLASTCN)) {
VOP_UNLOCK(pdp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
*vpp = tdp;
}
diff --git a/sys/ufs/ufs/ufs_lookup.c b/sys/ufs/ufs/ufs_lookup.c
index 1d3f46edf38..c4f60f3e25b 100644
--- a/sys/ufs/ufs/ufs_lookup.c
+++ b/sys/ufs/ufs/ufs_lookup.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ufs_lookup.c,v 1.19 2002/02/22 20:37:46 drahn Exp $ */
+/* $OpenBSD: ufs_lookup.c,v 1.20 2003/01/31 17:37:50 art Exp $ */
/* $NetBSD: ufs_lookup.c,v 1.7 1996/02/09 22:36:06 christos Exp $ */
/*
@@ -134,10 +134,13 @@ ufs_lookup(v)
struct vnode **vpp = ap->a_vpp;
struct componentname *cnp = ap->a_cnp;
struct ucred *cred = cnp->cn_cred;
- int flags = cnp->cn_flags;
+ int flags;
int nameiop = cnp->cn_nameiop;
struct proc *p = cnp->cn_proc;
+ cnp->cn_flags &= ~PDIRUNLOCK;
+ flags = cnp->cn_flags;
+
bp = NULL;
slotoffset = -1;
*vpp = NULL;
@@ -165,51 +168,8 @@ ufs_lookup(v)
* check the name cache to see if the directory/name pair
* we are looking for is known already.
*/
- if ((error = cache_lookup(vdp, vpp, cnp)) != 0) {
- int vpid; /* capability number of vnode */
-
- if (error == ENOENT)
- return (error);
- /*
- * Get the next vnode in the path.
- * See comment below starting `Step through' for
- * an explaination of the locking protocol.
- */
- pdp = vdp;
- dp = VTOI(*vpp);
- vdp = *vpp;
- vpid = vdp->v_id;
- if (pdp == vdp) { /* lookup on "." */
- VREF(vdp);
- error = 0;
- } else if (flags & ISDOTDOT) {
- VOP_UNLOCK(pdp, 0, p);
- error = vget(vdp, LK_EXCLUSIVE, p);
- if (!error && lockparent && (flags & ISLASTCN))
- error = vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p);
- } else {
- error = vget(vdp, LK_EXCLUSIVE, p);
- if (!lockparent || error || !(flags & ISLASTCN))
- VOP_UNLOCK(pdp, 0, p);
- }
- /*
- * Check that the capability number did not change
- * while we were waiting for the lock.
- */
- if (!error) {
- if (vpid == vdp->v_id)
- return (0);
- vput(vdp);
- if (lockparent && pdp != vdp && (flags & ISLASTCN))
- VOP_UNLOCK(pdp, 0, p);
- }
- *vpp = NULL;
-
- if ((error = vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p)) != 0)
- return (error);
- vdp = pdp;
- dp = VTOI(pdp);
- }
+ if ((error = cache_lookup(vdp, vpp, cnp)) >= 0)
+ return (error);
/*
* Suppress search for slots unless creating
@@ -455,8 +415,10 @@ notfound:
* information cannot be used.
*/
cnp->cn_flags |= SAVENAME;
- if (!lockparent)
+ if (!lockparent) {
VOP_UNLOCK(vdp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
return (EJUSTRETURN);
}
/*
@@ -534,8 +496,10 @@ found:
return (EPERM);
}
*vpp = tdp;
- if (!lockparent)
+ if (!lockparent) {
VOP_UNLOCK(vdp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
return (0);
}
@@ -561,8 +525,10 @@ found:
return (error);
*vpp = tdp;
cnp->cn_flags |= SAVENAME;
- if (!lockparent)
+ if (!lockparent) {
VOP_UNLOCK(vdp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
return (0);
}
@@ -588,15 +554,19 @@ found:
pdp = vdp;
if (flags & ISDOTDOT) {
VOP_UNLOCK(pdp, 0, p); /* race to get the inode */
+ cnp->cn_flags |= PDIRUNLOCK;
error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp);
if (error) {
- vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p);
+ if (vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p) == 0)
+ cnp->cn_flags &= ~PDIRUNLOCK;
return (error);
}
- if (lockparent && (flags & ISLASTCN) &&
- (error = vn_lock(pdp, LK_EXCLUSIVE, p))) {
- vput(tdp);
- return (error);
+ if (lockparent && (flags & ISLASTCN)) {
+ if ((error = vn_lock(pdp, LK_EXCLUSIVE, p))) {
+ vput(tdp);
+ return (error);
+ }
+ cnp->cn_flags &= ~PDIRUNLOCK;
}
*vpp = tdp;
} else if (dp->i_number == dp->i_ino) {
@@ -606,8 +576,10 @@ found:
error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp);
if (error)
return (error);
- if (!lockparent || !(flags & ISLASTCN))
+ if (!lockparent || !(flags & ISLASTCN)) {
VOP_UNLOCK(pdp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
*vpp = tdp;
}
diff --git a/sys/xfs/xfs_node-bsd.c b/sys/xfs/xfs_node-bsd.c
index 5e0d883a49d..afcbb8bdeda 100644
--- a/sys/xfs/xfs_node-bsd.c
+++ b/sys/xfs/xfs_node-bsd.c
@@ -37,7 +37,7 @@
#include <xfs/xfs_deb.h>
#include <xfs/xfs_vnodeops.h>
-RCSID("$Id: xfs_node-bsd.c,v 1.4 2002/06/07 04:10:32 hin Exp $");
+RCSID("$Id: xfs_node-bsd.c,v 1.5 2003/01/31 17:37:50 art Exp $");
extern vop_t **xfs_vnodeop_p;
@@ -533,9 +533,9 @@ xfs_dnlc_enter(struct vnode *dvp,
* The real change is sys/kern/vfs_cache:1.20
*/
-#if __NetBSD_Version__ >= 104120000
+#if __NetBSD_Version__ >= 104120000 || defined(__OpenBSD__)
if (cache_lookup(dvp, &dummy, cnp) != -1) {
- VOP_UNLOCK(dummy, 0);
+ VOP_UNLOCK(dummy, 0, cnp->cn_proc);
printf ("XFS PANIC WARNING! xfs_dnlc_enter: %s already in cache\n",
cnp->cn_nameptr);
}
@@ -700,7 +700,7 @@ xfs_dnlc_lock(struct vnode *dvp,
* (see the comment above for version information).
*/
-#if __NetBSD_Version__ >= 104120000
+#if __NetBSD_Version__ >= 104120000 || defined(__OpenBSD__)
int
xfs_dnlc_lookup(struct vnode *dvp,