diff options
author | Artur Grabowski <art@cvs.openbsd.org> | 2003-01-31 17:37:51 +0000 |
---|---|---|
committer | Artur Grabowski <art@cvs.openbsd.org> | 2003-01-31 17:37:51 +0000 |
commit | 1b0b18abe62afb1a61733a6f5891a98bfbea81ec (patch) | |
tree | 29dc896fd65580ea85012ef60aaf813858629e3f | |
parent | 2bccdd51809becfe909c271f5fef4d380c663209 (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.c | 68 | ||||
-rw-r--r-- | sys/isofs/cd9660/cd9660_lookup.c | 77 | ||||
-rw-r--r-- | sys/kern/vfs_cache.c | 123 | ||||
-rw-r--r-- | sys/kern/vfs_lookup.c | 25 | ||||
-rw-r--r-- | sys/miscfs/fdesc/fdesc_vnops.c | 46 | ||||
-rw-r--r-- | sys/miscfs/kernfs/kernfs_vfsops.c | 41 | ||||
-rw-r--r-- | sys/miscfs/kernfs/kernfs_vnops.c | 24 | ||||
-rw-r--r-- | sys/miscfs/portal/portal_vnops.c | 14 | ||||
-rw-r--r-- | sys/miscfs/procfs/procfs.h | 3 | ||||
-rw-r--r-- | sys/miscfs/procfs/procfs_vfsops.c | 28 | ||||
-rw-r--r-- | sys/miscfs/procfs/procfs_vnops.c | 52 | ||||
-rw-r--r-- | sys/msdosfs/msdosfs_lookup.c | 88 | ||||
-rw-r--r-- | sys/nfs/nfs_vnops.c | 173 | ||||
-rw-r--r-- | sys/sys/namei.h | 5 | ||||
-rw-r--r-- | sys/ufs/ext2fs/ext2fs_lookup.c | 78 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_lookup.c | 84 | ||||
-rw-r--r-- | sys/xfs/xfs_node-bsd.c | 8 |
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, |