Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 02 May 1997 20:36:17 +0200
From:      Poul-Henning Kamp <phk@dk.tfs.com>
To:        current@freebsd.org
Subject:   Re: vnode->v_usage
Message-ID:  <12725.862598177@critter>
In-Reply-To: Your message of "Fri, 02 May 1997 16:36:43 %2B0200." <2055.862583803@critter> 

next in thread | previous in thread | raw e-mail | index | archive | help

Well, one bug less in the last patch I sent out.  In rare circumstances
ufs will enter a ("..", NULL) tupple into the namecache...

new patch:

Index: sys/namei.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/namei.h,v
retrieving revision 1.13
diff -u -r1.13 namei.h
--- namei.h	1997/02/22 09:45:38	1.13
+++ namei.h	1997/05/02 13:24:24
@@ -153,30 +153,18 @@
 
 /*
  * This structure describes the elements in the cache of recent
- * names looked up by namei. NCHNAMLEN is sized to make structure
- * size a power of two to optimize malloc's. Minimum reasonable
- * size is 15.
+ * names looked up by namei.
  */
 
-#ifdef NCH_STATISTICS
-#define	NCHNAMLEN	23	/* maximum name segment length we bother with */
-#else
-#define	NCHNAMLEN	31	/* maximum name segment length we bother with */
-#endif
-
 struct	namecache {
 	LIST_ENTRY(namecache) nc_hash;	/* hash chain */
-	TAILQ_ENTRY(namecache) nc_lru;	/* LRU chain */
+	LIST_ENTRY(namecache) nc_src;	/* source vnode list */
+	TAILQ_ENTRY(namecache) nc_dst;	/* destination vnode list */
 	struct	vnode *nc_dvp;		/* vnode of parent of name */
-	u_long	nc_dvpid;		/* capability number of nc_dvp */
 	struct	vnode *nc_vp;		/* vnode the name refers to */
-	u_long	nc_vpid;		/* capability number of nc_vp */
-#ifdef NCH_STATISTICS
-	u_long	nc_nbr;			/* a serial number */
-	u_long	nc_hits;		/* how many times we got hit */
-#endif
+	char	nc_flag;		/* flag bits */
 	char	nc_nlen;		/* length of name */
-	char	nc_name[NCHNAMLEN];	/* segment name */
+	char	nc_name[0];	/* segment name */
 };
 
 #ifdef KERNEL
Index: sys/vnode.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/vnode.h,v
retrieving revision 1.43
diff -u -r1.43 vnode.h
--- vnode.h	1997/04/04 17:43:32	1.43
+++ vnode.h	1997/05/02 13:24:10
@@ -70,6 +70,7 @@
 
 typedef	int 	vop_t __P((void *));
 struct vm_object;
+struct namecache;
 
 /*
  * Reading or writing any of these items requires holding the appropriate lock.
@@ -104,12 +105,15 @@
 	daddr_t	v_cstart;			/* start block of cluster */
 	daddr_t	v_lasta;			/* last allocation */
 	int	v_clen;				/* length of current cluster */
-	int	v_usage;			/* Vnode usage counter */
 	struct vm_object *v_object;		/* Place to store VM object */
 	struct	simplelock v_interlock;		/* lock on usecount and flag */
 	struct	lock *v_vnlock;			/* used for non-locking fs's */
 	enum	vtagtype v_tag;			/* type of underlying data */
 	void 	*v_data;			/* private data for fs */
+	LIST_HEAD(, namecache) v_cache_src;	/* Cache entries from us */
+	TAILQ_HEAD(, namecache) v_cache_dst;	/* Cache entries to us */
+	struct	vnode *v_dd;			/* .. vnode */
+	u_long	v_ddid;				/* .. capability identifier */
 };
 #define	v_mountedhere	v_un.vu_mountedhere
 #define	v_socket	v_un.vu_socket
@@ -506,6 +510,7 @@
 	checkalias __P((struct vnode *vp, dev_t nvp_rdev, struct mount *mp));
 void 	vput __P((struct vnode *vp));
 void 	vrele __P((struct vnode *vp));
+void	vtouch __P((struct vnode *vp));
 #endif /* KERNEL */
 
 #endif /* !_SYS_VNODE_H_ */
Index: kern/vfs_cache.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/vfs_cache.c,v
retrieving revision 1.24
diff -u -r1.24 vfs_cache.c
--- vfs_cache.c	1997/03/08 15:22:14	1.24
+++ vfs_cache.c	1997/05/02 18:19:02
@@ -62,10 +62,6 @@
  * If it is a "negative" entry, (i.e. for a name that is known NOT to
  * exist) the vnode pointer will be NULL.
  *
- * For simplicity (and economy of storage), names longer than
- * a maximum length of NCHNAMLEN are not cached; they occur
- * infrequently in any case, and are almost never of interest.
- *
  * Upon reaching the last segment of a path, if the reference
  * is for DELETE, or NOCACHE is set (rewrite), and the
  * name is located in the cache, it will be dropped.
@@ -77,44 +73,45 @@
 #define NCHHASH(dvp, cnp) \
 	(&nchashtbl[((dvp)->v_id + (cnp)->cn_hash) % nchash])
 static LIST_HEAD(nchashhead, namecache) *nchashtbl;	/* Hash Table */
+static TAILQ_HEAD(, namecache) ncneg;	/* Hash Table */
 static u_long	nchash;			/* size of hash table */
+static u_long	ncnegfactor = 16;	/* ratio of negative entries */
+SYSCTL_INT(_debug, OID_AUTO, ncnegfactor, CTLFLAG_RW, &ncnegfactor, 0, "");
+static u_long	numneg;		/* number of cache entries allocated */
+SYSCTL_INT(_debug, OID_AUTO, numneg, CTLFLAG_RD, &numneg, 0, "");
 static u_long	numcache;		/* number of cache entries allocated */
-static TAILQ_HEAD(, namecache) nclruhead;	/* LRU chain */
+SYSCTL_INT(_debug, OID_AUTO, numcache, CTLFLAG_RD, &numcache, 0, "");
 struct	nchstats nchstats;		/* cache effectiveness statistics */
 
 static int	doingcache = 1;		/* 1 => enable the cache */
 SYSCTL_INT(_debug, OID_AUTO, vfscache, CTLFLAG_RW, &doingcache, 0, "");
+SYSCTL_INT(_debug, OID_AUTO, vnsize, CTLFLAG_RD, 0, sizeof(struct vnode), "");
+SYSCTL_INT(_debug, OID_AUTO, ncsize, CTLFLAG_RD, 0, sizeof(struct namecache), "");
 
-#ifdef NCH_STATISTICS
-u_long	nchnbr;
-#define NCHNBR(ncp) (ncp)->nc_nbr = ++nchnbr;
-#define NCHHIT(ncp) (ncp)->nc_hits++
-#else
-#define NCHNBR(ncp)
-#define NCHHIT(ncp)
-#endif
+static void cache_zap __P((struct namecache *ncp));
 
 /*
- * Delete an entry from its hash list and move it to the front
- * of the LRU list for immediate reuse.
+ * Flags in namecache.nc_flag
  */
-#define PURGE(ncp)  {						\
-	LIST_REMOVE(ncp, nc_hash);				\
-	ncp->nc_hash.le_prev = 0;				\
-	TAILQ_REMOVE(&nclruhead, ncp, nc_lru);			\
-	TAILQ_INSERT_HEAD(&nclruhead, ncp, nc_lru);		\
-}
-
+#define NCF_WHITE	1
 /*
- * Move an entry that has been used to the tail of the LRU list
- * so that it will be preserved for future use.
+ * Delete an entry from its hash list and move it to the front
+ * of the LRU list for immediate reuse.
  */
-#define TOUCH(ncp)  {						\
-	if (ncp->nc_lru.tqe_next != 0) {			\
-		TAILQ_REMOVE(&nclruhead, ncp, nc_lru);		\
-		TAILQ_INSERT_TAIL(&nclruhead, ncp, nc_lru);	\
-		NCHNBR(ncp);					\
-	}							\
+static void
+cache_zap(ncp)
+	struct namecache *ncp;
+{
+	LIST_REMOVE(ncp, nc_hash);
+	LIST_REMOVE(ncp, nc_src);
+	if (ncp->nc_vp) {
+		TAILQ_REMOVE(&ncp->nc_vp->v_cache_dst, ncp, nc_dst);
+	} else {
+		TAILQ_REMOVE(&ncneg, ncp, nc_dst);
+		numneg--;
+	}
+	numcache--;
+	free(ncp, M_CACHE);
 }
 
 /*
@@ -145,25 +142,25 @@
 		cnp->cn_flags &= ~MAKEENTRY;
 		return (0);
 	}
-	if (cnp->cn_namelen > NCHNAMLEN) {
-		nchstats.ncs_long++;
-		cnp->cn_flags &= ~MAKEENTRY;
-		return (0);
-	}
 
-	ncpp = NCHHASH(dvp, cnp);
-	for (ncp = ncpp->lh_first; ncp != 0; ncp = nnp) {
-		nnp = ncp->nc_hash.le_next;
-		/* If one of the vp's went stale, don't bother anymore. */
-		if ((ncp->nc_dvpid != ncp->nc_dvp->v_id) ||
-		    (ncp->nc_vp && ncp->nc_vpid != ncp->nc_vp->v_id)) {
-			nchstats.ncs_falsehits++;
-			PURGE(ncp);
-			continue;
+	if (cnp->cn_nameptr[0] == '.') {
+		if (cnp->cn_namelen == 1) {
+			*vpp = dvp;
+			return (-1);
+		}
+		if (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.') {
+			if (dvp->v_dd->v_id != dvp->v_ddid ||
+			    (cnp->cn_flags & MAKEENTRY) == 0) {
+				dvp->v_ddid = 0;
+				return (0);
+			}
+			*vpp = dvp->v_dd;
+			return (-1);
 		}
-		/* Now that we know the vp's to be valid, is it ours ? */
-		if (ncp->nc_dvp == dvp &&
-		    ncp->nc_nlen == cnp->cn_namelen &&
+	}
+
+	LIST_FOREACH(ncp, (NCHHASH(dvp, cnp)), nc_hash) {
+		if (ncp->nc_dvp == dvp && ncp->nc_nlen == cnp->cn_namelen &&
 		    !bcmp(ncp->nc_name, cnp->cn_nameptr, (u_int)ncp->nc_nlen))
 			break;
 	}
@@ -174,29 +171,25 @@
 		return (0);
 	}
 
-	NCHHIT(ncp);
-
 	/* We don't want to have an entry, so dump it */
 	if ((cnp->cn_flags & MAKEENTRY) == 0) {
 		nchstats.ncs_badhits++;
-		PURGE(ncp);
+		cache_zap(ncp);
 		return (0);
 	}
 
 	/* We found a "positive" match, return the vnode */
         if (ncp->nc_vp) {
 		nchstats.ncs_goodhits++;
-		TOUCH(ncp);
+		vtouch(ncp->nc_vp);
 		*vpp = ncp->nc_vp;
-		if ((*vpp)->v_usage < MAXVNODEUSE)
-			(*vpp)->v_usage++;
 		return (-1);
 	}
 
 	/* We found a negative match, and want to create it, so purge */
 	if (cnp->cn_nameiop == CREATE) {
 		nchstats.ncs_badhits++;
-		PURGE(ncp);
+		cache_zap(ncp);
 		return (0);
 	}
 
@@ -204,9 +197,11 @@
 	 * We found a "negative" match, ENOENT notifies client of this match.
 	 * The nc_vpid field records whether this is a whiteout.
 	 */
+	TAILQ_REMOVE(&ncneg, ncp, nc_dst);
+	TAILQ_INSERT_TAIL(&ncneg, ncp, nc_dst);
 	nchstats.ncs_neghits++;
-	TOUCH(ncp);
-	cnp->cn_flags |= ncp->nc_vpid;
+	if (ncp->nc_flag & NCF_WHITE)
+		cnp->cn_flags |= ISWHITEOUT;
 	return (ENOENT);
 }
 
@@ -225,35 +220,30 @@
 	if (!doingcache)
 		return;
 
-	if (cnp->cn_namelen > NCHNAMLEN) {
-		printf("cache_enter: name too long");
-		return;
-	}
-
-	/*
-	 * We allocate a new entry if we are less than the maximum
-	 * allowed and the one at the front of the LRU list is in use.
-	 * Otherwise we use the one at the front of the LRU list.
-	 */
-	if (numcache < desiredvnodes &&
-	    ((ncp = nclruhead.tqh_first) == NULL ||
-	    ncp->nc_hash.le_prev != 0)) {
-		/* Add one more entry */
-		ncp = (struct namecache *)
-			malloc((u_long)sizeof *ncp, M_CACHE, M_WAITOK);
-		bzero((char *)ncp, sizeof *ncp);
-		numcache++;
-	} else if (ncp = nclruhead.tqh_first) {
-		/* reuse an old entry */
-		TAILQ_REMOVE(&nclruhead, ncp, nc_lru);
-		if (ncp->nc_hash.le_prev != 0) {
-			LIST_REMOVE(ncp, nc_hash);
-			ncp->nc_hash.le_prev = 0;
+	if (cnp->cn_nameptr[0] == '.') {
+		if (cnp->cn_namelen == 1) {
+			return;
+		}
+		if (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.') {
+			if (vp) {
+				dvp->v_dd = vp;
+				dvp->v_ddid = vp->v_id;
+			} else {
+				dvp->v_dd = dvp;
+				dvp->v_ddid = 0;
+			}
+			return;
 		}
-	} else {
-		/* give up */
-		return;
 	}
+	 
+	ncp = (struct namecache *)
+		malloc(sizeof *ncp + cnp->cn_namelen, M_CACHE, M_WAITOK);
+	if (!ncp)
+Debugger("What??");
+	bzero((char *)ncp, sizeof *ncp);
+	numcache++;
+	if (!vp)
+		numneg++;
 
 	/*
 	 * Fill in cache info, if vp is NULL this is a "negative" cache entry.
@@ -262,19 +252,25 @@
 	 * otherwise unused.
 	 */
 	ncp->nc_vp = vp;
-	if (vp) {
-		ncp->nc_vpid = vp->v_id;
-		if (vp->v_usage < MAXVNODEUSE)
-			++vp->v_usage;
-	} else
-		ncp->nc_vpid = cnp->cn_flags & ISWHITEOUT;
+	if (vp)
+		vtouch(vp);
+	else
+		ncp->nc_flag = cnp->cn_flags & ISWHITEOUT ? NCF_WHITE : 0;
 	ncp->nc_dvp = dvp;
-	ncp->nc_dvpid = dvp->v_id;
 	ncp->nc_nlen = cnp->cn_namelen;
 	bcopy(cnp->cn_nameptr, ncp->nc_name, (unsigned)ncp->nc_nlen);
-	TAILQ_INSERT_TAIL(&nclruhead, ncp, nc_lru);
 	ncpp = NCHHASH(dvp, cnp);
 	LIST_INSERT_HEAD(ncpp, ncp, nc_hash);
+	LIST_INSERT_HEAD(&dvp->v_cache_src, ncp, nc_src);
+	if (vp) {
+		TAILQ_INSERT_HEAD(&vp->v_cache_dst, ncp, nc_dst);
+	} else {
+		TAILQ_INSERT_TAIL(&ncneg, ncp, nc_dst);
+	}
+	if (numneg*ncnegfactor > numcache) {
+		ncp = TAILQ_FIRST(&ncneg);
+		cache_zap(ncp);
+	}
 }
 
 /*
@@ -284,7 +280,7 @@
 nchinit()
 {
 
-	TAILQ_INIT(&nclruhead);
+	TAILQ_INIT(&ncneg);
 	nchashtbl = phashinit(desiredvnodes, M_CACHE, &nchash);
 }
 
@@ -304,14 +300,20 @@
 	struct nchashhead *ncpp;
 	static u_long nextvnodeid;
 
-	vp->v_id = ++nextvnodeid;
-	if (nextvnodeid != 0)
-		return;
-	for (ncpp = &nchashtbl[nchash - 1]; ncpp >= nchashtbl; ncpp--) {
-		while (ncp = ncpp->lh_first)
-			PURGE(ncp);
-	}
-	vp->v_id = ++nextvnodeid;
+	while (!LIST_EMPTY(&vp->v_cache_src)) 
+		cache_zap(LIST_FIRST(&vp->v_cache_src));
+	while (!TAILQ_EMPTY(&vp->v_cache_dst)) 
+		cache_zap(TAILQ_FIRST(&vp->v_cache_dst));
+
+	/* Never assign the same v_id, and never assign zero as v_id */
+	do {
+		if (++nextvnodeid == vp->v_id)
+			++nextvnodeid;
+	} while (!nextvnodeid);
+
+	vp->v_id = nextvnodeid;
+	vp->v_dd = vp;
+	vp->v_ddid = 0;
 }
 
 /*
@@ -329,12 +331,10 @@
 
 	/* Scan hash tables for applicable entries */
 	for (ncpp = &nchashtbl[nchash - 1]; ncpp >= nchashtbl; ncpp--) {
-		for (ncp = ncpp->lh_first; ncp != 0; ncp = nnp) {
-			nnp = ncp->nc_hash.le_next;
-			if (ncp->nc_dvpid != ncp->nc_dvp->v_id ||
-			    (ncp->nc_vp && ncp->nc_vpid != ncp->nc_vp->v_id) ||
-			    ncp->nc_dvp->v_mount == mp) {
-				PURGE(ncp);
+		for (ncp = LIST_FIRST(ncpp); ncp != 0; ncp = nnp) {
+			nnp = LIST_NEXT(ncp, nc_hash);
+			if (ncp->nc_dvp->v_mount == mp) {
+				cache_zap(ncp);
 			}
 		}
 	}
Index: kern/vfs_subr.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/vfs_subr.c,v
retrieving revision 1.84
diff -u -r1.84 vfs_subr.c
--- vfs_subr.c	1997/04/30 03:09:15	1.84
+++ vfs_subr.c	1997/05/02 13:24:43
@@ -361,6 +361,9 @@
 		vp = (struct vnode *) malloc((u_long) sizeof *vp,
 		    M_VNODE, M_WAITOK);
 		bzero((char *) vp, sizeof *vp);
+		vp->v_dd = vp;
+		LIST_INIT(&vp->v_cache_src);
+		TAILQ_INIT(&vp->v_cache_dst);
 		numvnodes++;
 	} else {
 		for (vp = vnode_free_list.tqh_first;
@@ -382,12 +385,6 @@
 		if (vp->v_usecount)
 			panic("free vnode isn't");
 		TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
-		if (vp->v_usage > 0) {
-			simple_unlock(&vp->v_interlock);
-			--vp->v_usage;
-			TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist);
-			goto retry;
-		}
 		freevnodes--;
 
 		/* see comment on why 0xdeadb is set at end of vgone (below) */
@@ -420,7 +417,6 @@
 		vp->v_clen = 0;
 		vp->v_socket = 0;
 		vp->v_writecount = 0;	/* XXX */
-		vp->v_usage = 0;
 	}
 	vp->v_type = VNON;
 	cache_purge(vp);
@@ -1119,7 +1115,6 @@
 	simple_lock(&vnode_free_list_slock);
 	if (vp->v_flag & VAGE) {
 		vp->v_flag &= ~VAGE;
-		vp->v_usage = 0;
 		if(vp->v_tag != VT_TFS)
 			TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist);
 	} else {
@@ -2146,4 +2141,21 @@
 
 retn:
 	return error;
+}
+
+void
+vtouch(vp)
+	struct vnode *vp;
+{
+	simple_lock(&vp->v_interlock);
+	if (vp->v_usecount) {
+		simple_unlock(&vp->v_interlock);
+		return;
+	}
+	if (simple_lock_try(&vnode_free_list_slock)) {
+		TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
+		TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist);
+		simple_unlock(&vnode_free_list_slock);
+	}
+	simple_unlock(&vp->v_interlock);
 }

--
Poul-Henning Kamp           | phk@FreeBSD.ORG       FreeBSD Core-team.
http://www.freebsd.org/~phk | phk@login.dknet.dk    Private mailbox.
whois: [PHK]                | phk@tfs.com           TRW Financial Systems, Inc.
Power and ignorance is a disgusting cocktail.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?12725.862598177>