Pantek Library
Hosting Provided By
CybrHost
High Speed Hosting

vfs 1

From: Ted Unangst <tedu(at)Stanford.EDU>
Date: Sun Dec 29 2002 - 21:06:04 EST


This is a series of patches to fix locking problems with many of the file systems. By the end, layered filesystems should work reliably, and there will be a better starting point to fix other issues. The problems can essentially be described by the statement, "In a virtual file system, the files aren't real, so neither are the locks."

Short description of each patch; more details come with the patch. They were tested not to break anything in this order. Sometimes order won't matter, other times it will.

patch 1:
PDIRUNLOCK handling in lookup(). Make all real file systems use the new cache_lookup() which handles ".." and things for them, instead of having a private copy in every fs.

patch 2:
PDIRUNLOCK for the stuff in miscfs.

patch 3:
clean up kernfs and procfs and make them ready for real locks.

patch 4:
VLAYER flag, new WILLUNLOCK and WILLPUT vop descriptions, stuff to prep for coming changes.

patch 5:
genfs_lock: real vnode locking. replace vop_generic_lock with genfs_nolock.

patch 6:
layerfs: common code from nullfs goes to layerfs, adds working locking.

Do you need help?X

patch 7:
unionfs: fix up unionfs to handle the changes.

patch 8:
genfs_lock for ufs. remove inode lock and use vnode lock.

This is patch 1. PDIRUNLOCK handling in lookup(). Make all real file systems use the new cache_lookup() whih handles ".." and things for them, instead of having a private copy in every fs. Affects all file systems which have disk data, and nfs. Changes the return values for cache_lookup().

diff -ruNX nodiff orig/sys/adosfs/adlookup.c vfs1/adosfs/adlookup.c

--- orig/sys/adosfs/adlookup.c	Thu Dec 18 00:59:01 1997

+++ vfs1/adosfs/adlookup.c Wed Dec 25 09:35:57 2002
@@ -90,6 +90,7 @@ *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 @@ 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))
/* - * 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 @@ * */ 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 &&
Do you need more help?X
- (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 @@
 #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 @@ } 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 -ruNX nodiff orig/sys/isofs/cd9660/cd9660_lookup.c vfs1/isofs/cd9660/cd9660_lookup.c --- orig/sys/isofs/cd9660/cd9660_lookup.c Sat Jun 23 02:14:22 2001
+++ vfs1/isofs/cd9660/cd9660_lookup.c Wed Dec 25 09:35:57 2002
@@ -129,10 +129,13 @@ 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 @@ * 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.
Can we help you?X
- */ - 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 @@ 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 @@ brelse(bp); if (error) return (error); - if (!lockparent || !(flags & ISLASTCN))
+ if (!lockparent || !(flags & ISLASTCN)) {
Can't find what you're looking for?X

VOP_UNLOCK(pdp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
*vpp = tdp; } diff -ruNX nodiff orig/sys/kern/vfs_cache.c vfs1/kern/vfs_cache.c --- orig/sys/kern/vfs_cache.c Wed Jul 3 21:19:08 2002
+++ vfs1/kern/vfs_cache.c Wed Dec 25 09:35:57 2002
@@ -90,9 +90,11 @@
  • 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 @@ 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;
 	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) {
Don't know where to look next?X
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);
+ /*
+ * If the above vget() failed or either of LOCKPARENT or
+ * ISLASTCN is set, unlock the directory vnode.
+ */
+ if (error || (~cnp->cn_flags & (LOCKPARENT|ISLASTCN)) != 0) {
+ VOP_UNLOCK(dvp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
+ }
+
+ /*
+ * 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++;
/* - * move this slot to end of LRU chain, if not already there
+ * 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 (ncp->nc_lru.tqe_next != 0) { - TAILQ_REMOVE(&nclruhead, ncp, nc_lru); - TAILQ_INSERT_TAIL(&nclruhead, ncp, nc_lru);
+ 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 = ncp->nc_vp;
+ *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;
 	/*
 	 * Last component and we are renaming or deleting,
 	 * the cache entry is invalid, or otherwise don't
@@ -166,9 +240,16 @@
 	 */
 	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 -ruNX nodiff orig/sys/kern/vfs_lookup.c vfs1/kern/vfs_lookup.c

--- orig/sys/kern/vfs_lookup.c	Tue Aug 27 16:04:42 2002

+++ vfs1/kern/vfs_lookup.c Wed Dec 25 09:35:57 2002
@@ -289,6 +289,7 @@ 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 @@
 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 @@ (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 @@ (cnp->cn_flags & NOCROSSMOUNT) == 0) {
Confused? Frustrated?X
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 @@ 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 -ruNX nodiff orig/sys/msdosfs/msdosfs_lookup.c vfs1/msdosfs/msdosfs_lookup.c
--- orig/sys/msdosfs/msdosfs_lookup.c	Fri Feb 19 17:26:17 1999

+++ vfs1/msdosfs/msdosfs_lookup.c Wed Dec 25 09:35:58 2002
@@ -110,12 +110,15 @@ 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 @@

  • 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 @@
 		 * 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 @@ 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 @@ 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;
Call Pantek today for Open Source Technical Support at 1-877-546-8934 - 24/7/365X

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 @@ } 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 -ruNX nodiff orig/sys/nfs/nfs_vnops.c vfs1/nfs/nfs_vnops.c --- orig/sys/nfs/nfs_vnops.c Fri Nov 29 10:48:20 2002
+++ vfs1/nfs/nfs_vnops.c Wed Dec 25 09:35:58 2002
@@ -636,7 +636,7 @@ 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 @@ 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 @@ 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;
- if (!error) { - if (vpid == newvp->v_id) {
Do you need help?X
- 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;
} - 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 @@ *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 @@ *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 @@ } if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN)) cnp->cn_flags |= SAVENAME;
+ *vpp = NULL;
} return (error);

 }
diff -ruNX nodiff orig/sys/sys/namei.h vfs1/sys/namei.h
--- orig/sys/sys/namei.h	Wed Jul  3 21:19:08 2002
Do you need more help?X

+++ vfs1/sys/namei.h Wed Dec 25 09:35:58 2002
@@ -140,7 +140,8 @@ #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 -ruNX nodiff orig/sys/ufs/ext2fs/ext2fs_lookup.c vfs1/ufs/ext2fs/ext2fs_lookup.c --- orig/sys/ufs/ext2fs/ext2fs_lookup.c Sat Oct 12 01:09:45 2002
    +++ vfs1/ufs/ext2fs/ext2fs_lookup.c Wed Dec 25 09:35:58 2002
    @@ -317,50 +317,8 @@
    • 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 @@
 		 * 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 @@ return (EPERM); } *vpp = tdp; - if (!lockparent)
+ if (!lockparent) {
VOP_UNLOCK(vdp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
return (0); } @@ -671,8 +633,10 @@ 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 @@ 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 @@ } else {
Can we help you?X
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 -ruNX nodiff orig/sys/ufs/ufs/ufs_lookup.c vfs1/ufs/ufs/ufs_lookup.c --- orig/sys/ufs/ufs/ufs_lookup.c Fri Feb 22 20:37:46 2002
+++ vfs1/ufs/ufs/ufs_lookup.c Wed Dec 25 09:35:58 2002
@@ -134,10 +134,13 @@ 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 @@ * 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) {
Can't find what you're looking for?X
- 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 @@ * 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 @@ return (EPERM); } *vpp = tdp; - if (!lockparent)
+ if (!lockparent) {
VOP_UNLOCK(vdp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
return (0); } @@ -561,8 +525,10 @@ 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 @@ 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 @@ error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp); if (error) return (error); - if (!lockparent || !(flags & ISLASTCN))
+ if (!lockparent || !(flags & ISLASTCN)) {
Don't know where to look next?X

VOP_UNLOCK(pdp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
*vpp = tdp; } diff -ruNX nodiff orig/sys/xfs/xfs_node-bsd.c vfs1/xfs/xfs_node-bsd.c --- orig/sys/xfs/xfs_node-bsd.c Fri Jun 7 04:10:32 2002
+++ vfs1/xfs/xfs_node-bsd.c Wed Dec 25 09:40:54 2002
@@ -533,9 +533,9 @@
  • 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 @@
  • (see the comment above for version information). */

-#if __NetBSD_Version__ >= 104120000
+#if __NetBSD_Version__ >= 104120000 || defined(__OpenBSD__)

Confused? Frustrated?X

 int
 xfs_dnlc_lookup(struct vnode *dvp,

--
"I promise you a police car on every sidewalk."
      - M. Barry, Mayor of Washington, DC
Received on Sun Dec 29 22:02:18 2002

This archive was generated by hypermail 2.1.8 : Wed Aug 23 2006 - 13:29:42 EDT


Contact Us  Legal Notices  Order Services Online 
Pantek Home  Privacy Policy  IT news  Site Map  Pantek Library