svn commit: r190973 - in stable/7/sys: . contrib/pf dev/ath/ath_hal dev/cxgb kern sys

Alexander Kabaev kan at FreeBSD.org
Sun Apr 12 19:41:18 UTC 2009


Author: kan
Date: Sun Apr 12 19:41:16 2009
New Revision: 190973
URL: http://svn.freebsd.org/changeset/base/190973

Log:
  MFC changes 190533 and 190945:
  
  Replace v_dd vnode pointer with v_cache_dd pointer to struct namecache
  in directory vnodes. Allow namecache dotdot entry to be created pointing
  from child vnode to parent vnode if no existing links in opposite
  direction exist. Use direct link from parent to child for dotdot lookups
  otherwise.
  
  This restores more efficient dotdot caching in NFS filesystems which
  was lost when vnodes stoppped being type stable.
  
  Majority of backporting work for this was done by jhb.
  
  Reviewed by:	jhb, kib
  Approved by:	re (kib)

Modified:
  stable/7/sys/   (props changed)
  stable/7/sys/contrib/pf/   (props changed)
  stable/7/sys/dev/ath/ath_hal/   (props changed)
  stable/7/sys/dev/cxgb/   (props changed)
  stable/7/sys/kern/vfs_cache.c
  stable/7/sys/kern/vfs_subr.c
  stable/7/sys/sys/vnode.h

Modified: stable/7/sys/kern/vfs_cache.c
==============================================================================
--- stable/7/sys/kern/vfs_cache.c	Sun Apr 12 19:06:41 2009	(r190972)
+++ stable/7/sys/kern/vfs_cache.c	Sun Apr 12 19:41:16 2009	(r190973)
@@ -182,7 +182,8 @@ static MALLOC_DEFINE(M_VFSCACHE, "vfscac
 /*
  * Flags in namecache.nc_flag
  */
-#define NCF_WHITE	1
+#define NCF_WHITE	0x01
+#define NCF_ISDOTDOT	0x02
 
 #ifdef DIAGNOSTIC
 /*
@@ -283,14 +284,20 @@ cache_zap(ncp)
 	CTR2(KTR_VFS, "cache_zap(%p) vp %p", ncp, ncp->nc_vp);
 	vp = NULL;
 	LIST_REMOVE(ncp, nc_hash);
-	LIST_REMOVE(ncp, nc_src);
-	if (LIST_EMPTY(&ncp->nc_dvp->v_cache_src)) {
-		vp = ncp->nc_dvp;
-		numcachehv--;
+	if (ncp->nc_flag & NCF_ISDOTDOT) {
+		if (ncp == ncp->nc_dvp->v_cache_dd)
+			ncp->nc_dvp->v_cache_dd = NULL;
+	} else {
+		LIST_REMOVE(ncp, nc_src);
+		if (LIST_EMPTY(&ncp->nc_dvp->v_cache_src)) {
+			vp = ncp->nc_dvp;
+			numcachehv--;
+		}
 	}
 	if (ncp->nc_vp) {
 		TAILQ_REMOVE(&ncp->nc_vp->v_cache_dst, ncp, nc_dst);
-		ncp->nc_vp->v_dd = NULL;
+		if (ncp == ncp->nc_vp->v_cache_dd)
+			ncp->nc_vp->v_cache_dd = NULL;
 	} else {
 		TAILQ_REMOVE(&ncneg, ncp, nc_dst);
 		numneg--;
@@ -348,12 +355,21 @@ retry:
 		}
 		if (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.') {
 			dotdothits++;
-			if (dvp->v_dd == NULL ||
-			    (cnp->cn_flags & MAKEENTRY) == 0) {
+			if (dvp->v_cache_dd == NULL) {
 				CACHE_UNLOCK();
 				return (0);
 			}
-			*vpp = dvp->v_dd;
+			if ((cnp->cn_flags & MAKEENTRY) == 0) {
+				if (dvp->v_cache_dd->nc_flag & NCF_ISDOTDOT)
+					cache_zap(dvp->v_cache_dd);
+				dvp->v_cache_dd = NULL;
+				CACHE_UNLOCK();
+				return (0);
+			}
+			if (dvp->v_cache_dd->nc_flag & NCF_ISDOTDOT)
+				*vpp = dvp->v_cache_dd->nc_vp;
+			else
+				*vpp = dvp->v_cache_dd->nc_dvp;
 			CTR3(KTR_VFS, "cache_lookup(%p, %s) found %p via ..",
 			    dvp, cnp->cn_nameptr, *vpp);
 			goto success;
@@ -484,6 +500,7 @@ cache_enter(dvp, vp, cnp)
 	struct namecache *ncp, *n2;
 	struct nchashhead *ncpp;
 	u_int32_t hash;
+	int flag;
 	int hold;
 	int zap;
 	int len;
@@ -501,23 +518,33 @@ cache_enter(dvp, vp, cnp)
 	if (numcache >= desiredvnodes * 2)
 		return;
 
+	flag = 0;
 	if (cnp->cn_nameptr[0] == '.') {
-		if (cnp->cn_namelen == 1) {
+		if (cnp->cn_namelen == 1)
 			return;
-		}
-		/*
-		 * For dotdot lookups only cache the v_dd pointer if the
-		 * directory has a link back to its parent via v_cache_dst.
-		 * Without this an unlinked directory would keep a soft
-		 * reference to its parent which could not be NULLd at
-		 * cache_purge() time.
-		 */
 		if (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.') {
 			CACHE_LOCK();
-			if (!TAILQ_EMPTY(&dvp->v_cache_dst))
-				dvp->v_dd = vp;
+			/*
+			 * If dotdot entry already exists, just retarget it
+			 * to new parent vnode, otherwise continue with new
+			 * namecache entry allocation.
+			 */
+			if ((ncp = dvp->v_cache_dd) != NULL) {
+				if (ncp->nc_flag & NCF_ISDOTDOT) {
+					KASSERT(ncp->nc_dvp == dvp,
+					    ("wrong isdotdot parent"));
+					TAILQ_REMOVE(&ncp->nc_vp->v_cache_dst,
+					    ncp, nc_dst);
+					TAILQ_INSERT_HEAD(&vp->v_cache_dst,
+					    ncp, nc_dst);
+					ncp->nc_vp = vp;
+					CACHE_UNLOCK();
+					return;
+				}
+			}
+			dvp->v_cache_dd = NULL;
 			CACHE_UNLOCK();
-			return;
+			flag = NCF_ISDOTDOT;
 		}
 	}
 
@@ -531,6 +558,7 @@ cache_enter(dvp, vp, cnp)
 	ncp = cache_alloc(cnp->cn_namelen);
 	ncp->nc_vp = vp;
 	ncp->nc_dvp = dvp;
+	ncp->nc_flag = flag;
 	len = ncp->nc_nlen = cnp->cn_namelen;
 	hash = fnv_32_buf(cnp->cn_nameptr, len, FNV1_32_INIT);
 	bcopy(cnp->cn_nameptr, ncp->nc_name, len);
@@ -553,14 +581,35 @@ cache_enter(dvp, vp, cnp)
 		}
 	}
 
+	if (flag == NCF_ISDOTDOT) {
+		/*
+		 * See if we are trying to add .. entry, but some other lookup
+		 * has populated v_cache_dd pointer already.
+		 */
+		if (dvp->v_cache_dd != NULL) {
+			CACHE_UNLOCK();
+			cache_free(ncp);
+			return;
+		}
+		KASSERT(vp == NULL || vp->v_type == VDIR,
+		    ("wrong vnode type %p", vp));
+		dvp->v_cache_dd = ncp;
+	}
+
 	numcache++;
 	if (!vp) {
 		numneg++;
-		ncp->nc_flag = cnp->cn_flags & ISWHITEOUT ? NCF_WHITE : 0;
+		if (cnp->cn_flags & ISWHITEOUT)
+			ncp->nc_flag |= NCF_WHITE;
 	} else if (vp->v_type == VDIR) {
-		vp->v_dd = dvp;
+		if (flag != NCF_ISDOTDOT) {
+			if ((n2 = vp->v_cache_dd) != NULL &&
+			    (n2->nc_flag & NCF_ISDOTDOT) != 0)
+				cache_zap(n2);
+			vp->v_cache_dd = ncp;
+		}
 	} else {
-		vp->v_dd = NULL;
+		vp->v_cache_dd = NULL;
 	}
 
 	/*
@@ -568,11 +617,14 @@ cache_enter(dvp, vp, cnp)
 	 * within the cache entries table.
 	 */
 	LIST_INSERT_HEAD(ncpp, ncp, nc_hash);
-	if (LIST_EMPTY(&dvp->v_cache_src)) {
-		hold = 1;
-		numcachehv++;
+	if (flag != NCF_ISDOTDOT) {
+		if (LIST_EMPTY(&dvp->v_cache_src)) {
+			hold = 1;
+			numcachehv++;
+		}
+		LIST_INSERT_HEAD(&dvp->v_cache_src, ncp, nc_src);
 	}
-	LIST_INSERT_HEAD(&dvp->v_cache_src, ncp, nc_src);
+
 	/*
 	 * If the entry is "negative", we place it into the
 	 * "negative" cache queue, otherwise, we place it into the
@@ -627,7 +679,12 @@ cache_purge(vp)
 		cache_zap(LIST_FIRST(&vp->v_cache_src));
 	while (!TAILQ_EMPTY(&vp->v_cache_dst))
 		cache_zap(TAILQ_FIRST(&vp->v_cache_dst));
-	vp->v_dd = NULL;
+	if (vp->v_cache_dd != NULL) {
+		KASSERT(vp->v_cache_dd->nc_flag & NCF_ISDOTDOT,
+		   ("lost dotdot link"));
+		cache_zap(vp->v_cache_dd);
+	}
+	KASSERT(vp->v_cache_dd == NULL, ("incomplete purge"));
 	CACHE_UNLOCK();
 }
 
@@ -877,18 +934,19 @@ vn_fullpath1(struct thread *td, struct v
 			vp = vp->v_mount->mnt_vnodecovered;
 			continue;
 		}
-		if (vp->v_dd == NULL) {
+		if (vp->v_type != VDIR) {
 			numfullpathfail1++;
 			error = ENOTDIR;
 			break;
 		}
-		ncp = TAILQ_FIRST(&vp->v_cache_dst);
+		TAILQ_FOREACH(ncp, &vp->v_cache_dst, nc_dst)
+			if ((ncp->nc_flag & NCF_ISDOTDOT) == 0)
+				break;
 		if (!ncp) {
 			numfullpathfail2++;
 			error = ENOENT;
 			break;
 		}
-		MPASS(ncp->nc_dvp == vp->v_dd);
 		for (i = ncp->nc_nlen - 1; i >= 0 && bp != buf; i--)
 			*--bp = ncp->nc_name[i];
 		if (bp == buf) {

Modified: stable/7/sys/kern/vfs_subr.c
==============================================================================
--- stable/7/sys/kern/vfs_subr.c	Sun Apr 12 19:06:41 2009	(r190972)
+++ stable/7/sys/kern/vfs_subr.c	Sun Apr 12 19:41:16 2009	(r190973)
@@ -800,6 +800,7 @@ vdestroy(struct vnode *vp)
 	VNASSERT(bo->bo_dirty.bv_root == NULL, vp, ("dirtyblkroot not NULL"));
 	VNASSERT(TAILQ_EMPTY(&vp->v_cache_dst), vp, ("vp has namecache dst"));
 	VNASSERT(LIST_EMPTY(&vp->v_cache_src), vp, ("vp has namecache src"));
+	VNASSERT(vp->v_cache_dd == NULL, vp, ("vp has namecache for .."));
 	VI_UNLOCK(vp);
 #ifdef MAC
 	mac_destroy_vnode(vp);

Modified: stable/7/sys/sys/vnode.h
==============================================================================
--- stable/7/sys/sys/vnode.h	Sun Apr 12 19:06:41 2009	(r190972)
+++ stable/7/sys/sys/vnode.h	Sun Apr 12 19:41:16 2009	(r190973)
@@ -138,7 +138,7 @@ struct vnode {
 	 */
 	LIST_HEAD(, namecache) v_cache_src;	/* c Cache entries from us */
 	TAILQ_HEAD(, namecache) v_cache_dst;	/* c Cache entries to us */
-	struct	vnode *v_dd;			/* c .. vnode */
+	struct namecache *v_cache_dd;		/* c Cache entry for .. vnode */
 
 	/*
 	 * clustering stuff


More information about the svn-src-all mailing list