Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 29 Aug 1997 12:20:44 +0200
From:      Poul-Henning Kamp <phk@critter.freebsd.dk>
To:        "Jordan K. Hubbard" <jkh@time.cdrom.com>
Cc:        current@freebsd.org
Subject:   Re: Another SNAPshot CD of 3.0 coming up.. 
Message-ID:  <8608.872850044@critter.freebsd.dk>
In-Reply-To: Your message of "Fri, 29 Aug 1997 02:16:49 PDT." <344.872846209@time.cdrom.com> 

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

In message <344.872846209@time.cdrom.com>, "Jordan K. Hubbard" writes:
>The last 3.0 SNAP CD was done on May 22 and we're slightly overdue for
>the next one.  Therefore, assuming that things aren't too badly broken
>or can't be fixed with a couple of week's work, consider this my
>early-warning announcement that another 3.0 SNAPshot for CD will be
>done in 10 days or so.  "Smoke 'em if you've got 'em."
>
>					Jordan

I have just sent the following vfs patch out for review to jdp,bde,
dyson & davidg.  Considering this, I would like if more people would
jump on this patch and test it.  I've run on it for weeks now with
no ill effects on my laptop

Please report any observations to me.

        Change the 0xdeadb hack to a flag called VDOOMED.
        Introduce VFREE which indicates that vnode is on freelist.
        Rename vholdrele() to vdrop().
        Create vfree() and vbusy() to add/delete vnode from freelist.
        Add vfree()/vbusy() to keep (v_holdcnt != 0 || v_usecount != 0)
          vnodes off the freelist.
        Generalize vhold()/v_holdcnt to mean "do not recycle".
        Fix reassignbuf()s lack of use of vhold().
        Use vhold() instead of checking v_cache_src list.
        Remove vtouch(), the vnodes are always vget'ed soon enough
          after for it to have any measuable effect.
        Add sysctl debug.freevnodes to keep track of things.
        Move cache_purge() up in getnewvnodes to avoid race.
        Decrement v_usecount after VOP_INACTIVE(), put a vhold() on
          it during VOP_INACTIVE()
        Unmacroize vhold()/vdrop()
        Print out VDOOMED and VFREE flags (XXX: should use %b)

Poul-Henning

Index: kern/vfs_cache.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/vfs_cache.c,v
retrieving revision 1.27
diff -u -r1.27 vfs_cache.c
--- vfs_cache.c	1997/08/26 07:32:34	1.27
+++ vfs_cache.c	1997/08/27 14:24:59
@@ -103,6 +103,8 @@
 {
 	LIST_REMOVE(ncp, nc_hash);
 	LIST_REMOVE(ncp, nc_src);
+	if (LIST_EMPTY(&ncp->nc_dvp->v_cache_src)) 
+		vdrop(ncp->nc_dvp);
 	if (ncp->nc_vp) {
 		TAILQ_REMOVE(&ncp->nc_vp->v_cache_dst, ncp, nc_dst);
 	} else {
@@ -180,7 +182,6 @@
 	/* We found a "positive" match, return the vnode */
         if (ncp->nc_vp) {
 		nchstats.ncs_goodhits++;
-		vtouch(ncp->nc_vp);
 		*vpp = ncp->nc_vp;
 		return (-1);
 	}
@@ -239,8 +240,10 @@
 		malloc(sizeof *ncp + cnp->cn_namelen, M_CACHE, M_WAITOK);
 	bzero((char *)ncp, sizeof *ncp);
 	numcache++;
-	if (!vp)
+	if (!vp) {
 		numneg++;
+		ncp->nc_flag = cnp->cn_flags & ISWHITEOUT ? NCF_WHITE : 0;
+	}
 
 	/*
 	 * Fill in cache info, if vp is NULL this is a "negative" cache entry.
@@ -249,15 +252,13 @@
 	 * otherwise unused.
 	 */
 	ncp->nc_vp = vp;
-	if (vp)
-		vtouch(vp);
-	else
-		ncp->nc_flag = cnp->cn_flags & ISWHITEOUT ? NCF_WHITE : 0;
 	ncp->nc_dvp = dvp;
 	ncp->nc_nlen = cnp->cn_namelen;
 	bcopy(cnp->cn_nameptr, ncp->nc_name, (unsigned)ncp->nc_nlen);
 	ncpp = NCHHASH(dvp, cnp);
 	LIST_INSERT_HEAD(ncpp, ncp, nc_hash);
+	if (LIST_EMPTY(&dvp->v_cache_src))
+		vhold(dvp);
 	LIST_INSERT_HEAD(&dvp->v_cache_src, ncp, nc_src);
 	if (vp) {
 		TAILQ_INSERT_HEAD(&vp->v_cache_dst, ncp, nc_dst);
Index: kern/vfs_subr.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/vfs_subr.c,v
retrieving revision 1.95
diff -u -r1.95 vfs_subr.c
--- vfs_subr.c	1997/08/26 11:59:20	1.95
+++ vfs_subr.c	1997/08/27 14:28:38
@@ -103,6 +103,7 @@
 }
 TAILQ_HEAD(freelst, vnode) vnode_free_list;	/* vnode free list */
 static u_long freevnodes = 0;
+SYSCTL_INT(_debug, OID_AUTO, freevnodes, CTLFLAG_RD, &freevnodes, 0, "");
 
 struct mntlist mountlist;	/* mounted filesystem list */
 struct simplelock mountlist_slock;
@@ -380,11 +381,11 @@
 	}
 
 	if (vp) {
+		vp->v_flag |= VDOOMED;
 		TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
 		freevnodes--;
-		/* see comment on why 0xdeadb is set at end of vgone (below) */
-		vp->v_freelist.tqe_prev = (struct vnode **) 0xdeadb;
 		simple_unlock(&vnode_free_list_slock);
+		cache_purge(vp);
 		vp->v_lease = NULL;
 		if (vp->v_type != VBAD)
 			vgonel(vp, p);
@@ -418,13 +419,13 @@
 		    M_VNODE, M_WAITOK);
 		bzero((char *) vp, sizeof *vp);
 		vp->v_dd = vp;
+		cache_purge(vp);
 		LIST_INIT(&vp->v_cache_src);
 		TAILQ_INIT(&vp->v_cache_dst);
 		numvnodes++;
 	}
 
 	vp->v_type = VNON;
-	cache_purge(vp);
 	vp->v_tag = tag;
 	vp->v_op = vops;
 	insmntque(vp, mp);
@@ -582,7 +583,7 @@
 
 	if (bp->b_vp)
 		panic("bgetvp: not free");
-	VHOLD(vp);
+	vhold(vp);
 	bp->b_vp = vp;
 	if (vp->v_type == VBLK || vp->v_type == VCHR)
 		bp->b_dev = vp->v_rdev;
@@ -618,7 +619,7 @@
 
 	vp = bp->b_vp;
 	bp->b_vp = (struct vnode *) 0;
-	HOLDRELE(vp);
+	vdrop(vp);
 }
 
 /*
@@ -678,8 +679,10 @@
 	/*
 	 * Delete from old vnode list, if on one.
 	 */
-	if (bp->b_vnbufs.le_next != NOLIST)
+	if (bp->b_vnbufs.le_next != NOLIST) {
 		bufremvn(bp);
+		vdrop(bp->b_vp);
+	}
 	/*
 	 * If dirty, put on list of dirty buffers; otherwise insert onto list
 	 * of clean buffers.
@@ -700,6 +703,8 @@
 	} else {
 		bufinsvn(bp, &newvp->v_cleanblkhd);
 	}
+	bp->b_vp = newvp;
+	vhold(bp->b_vp);
 	splx(s);
 }
 
@@ -836,13 +841,9 @@
 		tsleep((caddr_t)vp, PINOD, "vget", 0);
 		return (ENOENT);
 	}
-	if (vp->v_usecount == 0) {
-		simple_lock(&vnode_free_list_slock);
-		TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
-		simple_unlock(&vnode_free_list_slock);
-		freevnodes--;
-	}
 	vp->v_usecount++;
+	if (VSHOULDBUSY(vp))
+		vbusy(vp);
 	/*
 	 * Create the VM object, if needed
 	 */
@@ -1089,11 +1090,11 @@
 		panic("vputrele: null vp");
 #endif
 	simple_lock(&vp->v_interlock);
-	vp->v_usecount--;
 
-	if ((vp->v_usecount == 1) &&
+	if ((vp->v_usecount == 2) &&
 		vp->v_object &&
 		(vp->v_object->flags & OBJ_VFS_REF)) {
+		vp->v_usecount--;
 		vp->v_object->flags &= ~OBJ_VFS_REF;
 		if (put) {
 			VOP_UNLOCK(vp, LK_INTERLOCK, p);
@@ -1104,7 +1105,8 @@
 		return;
 	}
 
-	if (vp->v_usecount > 0) {
+	if (vp->v_usecount > 1) {
+		vp->v_usecount--;
 		if (put) {
 			VOP_UNLOCK(vp, LK_INTERLOCK, p);
 		} else {
@@ -1113,23 +1115,14 @@
 		return;
 	}
 
-	if (vp->v_usecount < 0) {
+	if (vp->v_usecount < 1) {
 #ifdef DIAGNOSTIC
 		vprint("vputrele: negative ref count", vp);
 #endif
 		panic("vputrele: negative ref cnt");
 	}
-	simple_lock(&vnode_free_list_slock);
-	if (vp->v_flag & VAGE) {
-		vp->v_flag &= ~VAGE;
-		if(vp->v_tag != VT_TFS)
-			TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist);
-	} else {
-		if(vp->v_tag != VT_TFS)
-			TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist);
-	}
-	freevnodes++;
-	simple_unlock(&vnode_free_list_slock);
+
+	vp->v_holdcnt++; 	/* Make sure vnode isn't recycled */
 
 	/*
 	 * If we are doing a vput, the node is already locked, and we must
@@ -1139,8 +1132,18 @@
 	if (put) {
 		simple_unlock(&vp->v_interlock);
 		VOP_INACTIVE(vp, p);
+		simple_lock(&vp->v_interlock);
+		vp->v_usecount--;
+		vp->v_holdcnt--;
+		if (VSHOULDFREE(vp))
+			vfree(vp);
+		simple_unlock(&vp->v_interlock);
 	} else if (vn_lock(vp, LK_EXCLUSIVE | LK_INTERLOCK, p) == 0) {
 		VOP_INACTIVE(vp, p);
+		vp->v_usecount--;
+		vp->v_holdcnt--;
+		if (VSHOULDFREE(vp))
+			vfree(vp);
 	}
 }
 
@@ -1161,9 +1164,8 @@
 	vputrele(vp, 0);
 }
 
-#ifdef DIAGNOSTIC
 /*
- * Page or buffer structure gets a reference.
+ * Somebody doesn't want the vnode recycled.
  */
 void
 vhold(vp)
@@ -1172,14 +1174,16 @@
 
 	simple_lock(&vp->v_interlock);
 	vp->v_holdcnt++;
+	if (VSHOULDBUSY(vp))
+		vbusy(vp);
 	simple_unlock(&vp->v_interlock);
 }
 
 /*
- * Page or buffer structure frees a reference.
+ * One less who cares about this vnode.
  */
 void
-holdrele(vp)
+vdrop(vp)
 	register struct vnode *vp;
 {
 
@@ -1187,9 +1191,10 @@
 	if (vp->v_holdcnt <= 0)
 		panic("holdrele: holdcnt");
 	vp->v_holdcnt--;
+	if (VSHOULDFREE(vp))
+		vfree(vp);
 	simple_unlock(&vp->v_interlock);
 }
-#endif /* DIAGNOSTIC */
 
 /*
  * Remove any vnodes in the vnode table belonging to mount point mp.
@@ -1572,17 +1577,11 @@
 	 * after calling vgone. If the reference count were
 	 * incremented first, vgone would (incorrectly) try to
 	 * close the previous instance of the underlying object.
-	 * So, the back pointer is explicitly set to `0xdeadb' in
-	 * getnewvnode after removing it from the freelist to ensure
-	 * that we do not try to move it here.
 	 */
-	if (vp->v_usecount == 0) {
+	if (vp->v_usecount == 0 && !(vp->v_flag & VDOOMED)) {
 		simple_lock(&vnode_free_list_slock);
-		if ((vp->v_freelist.tqe_prev != (struct vnode **)0xdeadb) &&
-			vnode_free_list.tqh_first != vp) {
-			TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
-			TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist);
-		}
+		TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
+		TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist);
 		simple_unlock(&vnode_free_list_slock);
 	}
 
@@ -1680,6 +1679,10 @@
 		strcat(buf, "|VBWAIT");
 	if (vp->v_flag & VALIASED)
 		strcat(buf, "|VALIASED");
+	if (vp->v_flag & VDOOMED)
+		strcat(buf, "|VDOOMED");
+	if (vp->v_flag & VFREE)
+		strcat(buf, "|VFREE");
 	if (buf[0] != '\0')
 		printf(" flags (%s)", &buf[1]);
 	if (vp->v_data == NULL) {
@@ -2255,20 +2258,28 @@
 }
 
 void
-vtouch(vp)
+vfree(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)) {
-		if (vp->v_freelist.tqe_prev != (struct vnode **)0xdeadb) {
-			TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
-			TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist);
-		}
-		simple_unlock(&vnode_free_list_slock);
+	simple_lock(&vnode_free_list_slock);
+	if (vp->v_flag & VAGE) {
+		TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist);
+	} else {
+		TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist);
 	}
-	simple_unlock(&vp->v_interlock);
+	freevnodes++;
+	simple_unlock(&vnode_free_list_slock);
+	vp->v_flag &= ~VAGE;
+	vp->v_flag |= VFREE;
+}
+
+void
+vbusy(vp)
+	struct vnode *vp;
+{
+	simple_lock(&vnode_free_list_slock);
+	TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
+	freevnodes--;
+	simple_unlock(&vnode_free_list_slock);
+	vp->v_flag &= ~VFREE;
 }
Index: sys/vnode.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/vnode.h,v
retrieving revision 1.46
diff -u -r1.46 vnode.h
--- vnode.h	1997/08/26 07:32:46	1.46
+++ vnode.h	1997/08/26 22:29:57
@@ -141,6 +141,8 @@
 #define	VAGE		0x08000	/* Insert vnode at head of free list */
 #define	VOLOCK		0x10000	/* vnode is locked waiting for an object */
 #define	VOWANT		0x20000	/* a process is waiting for VOLOCK */
+#define	VDOOMED		0x40000	/* This vnode is being recycled */
+#define	VFREE		0x80000	/* This vnode is on the freelist */
 
 /*
  * Vnode attributes.  A field value of VNOVAL represents a field whose value
@@ -221,35 +223,12 @@
 #define	V_SAVEMETA	0x0002		/* vinvalbuf: leave indirect blocks */
 #define	REVOKEALL	0x0001		/* vop_revoke: revoke all aliases */
 
-#ifdef DIAGNOSTIC
-#define	HOLDRELE(vp)	holdrele(vp)
-#define	VATTR_NULL(vap)	vattr_null(vap)
-#define	VHOLD(vp)	vhold(vp)
 #define	VREF(vp)	vref(vp)
 
-void	holdrele __P((struct vnode *));
-void	vhold __P((struct vnode *));
-void 	vref __P((struct vnode *vp));
+#ifdef DIAGNOSTIC
+#define	VATTR_NULL(vap)	vattr_null(vap)
 #else
 #define	VATTR_NULL(vap)	(*(vap) = va_null)	/* initialize a vattr */
-#define	HOLDRELE(vp)	holdrele(vp)		/* decrease buf or page ref */
-static __inline void
-holdrele(struct vnode *vp)
-{
-	simple_lock(&vp->v_interlock);
-	vp->v_holdcnt--;
-	simple_unlock(&vp->v_interlock);
-}
-#define	VHOLD(vp)	vhold(vp)		/* increase buf or page ref */
-static __inline void
-vhold(struct vnode *vp)
-{
-	simple_lock(&vp->v_interlock);
-	vp->v_holdcnt++;
-	simple_unlock(&vp->v_interlock);
-}
-#define	VREF(vp)	vref(vp)		/* increase reference */
-void 	vref __P((struct vnode *vp));
 #endif /* DIAGNOSTIC */
 
 #define	NULLVP	((struct vnode *)NULL)
@@ -288,6 +267,15 @@
 	do { if(lease_updatetime) lease_updatetime(dt); } while(0)
 #endif /* NFS */
 
+#define VSHOULDFREE(vp)	\
+	(!((vp)->v_flag & (VFREE|VDOOMED)) && \
+	 !(vp)->v_holdcnt && !(vp)->v_usecount)
+
+#define VSHOULDBUSY(vp)	\
+	(((vp)->v_flag & VFREE) && \
+	 ((vp)->v_holdcnt || (vp)->v_usecount))
+
+
 #endif /* KERNEL */
 
 
@@ -482,12 +470,16 @@
 void	insmntque __P((struct vnode *vp, struct mount *mp));
 int	lease_check __P((struct vop_lease_args *ap));
 void 	vattr_null __P((struct vattr *vap));
+void	vbusy __P((struct vnode *));
 int 	vcount __P((struct vnode *vp));
+void	vdrop __P((struct vnode *));
 int	vfinddev __P((dev_t dev, enum vtype type, struct vnode **vpp));
+void	vfree __P((struct vnode *));
 void	vfs_opv_init __P((struct vnodeopv_desc **them));
 int	vflush __P((struct mount *mp, struct vnode *skipvp, int flags));
 int 	vget __P((struct vnode *vp, int lockflag, struct proc *p));
 void 	vgone __P((struct vnode *vp));
+void	vhold __P((struct vnode *));
 int	vinvalbuf __P((struct vnode *vp, int save, struct ucred *cred,
 	    struct proc *p, int slpflag, int slptimeo));
 void	vprint __P((char *label, struct vnode *vp));
@@ -514,8 +506,8 @@
 struct vnode *
 	checkalias __P((struct vnode *vp, dev_t nvp_rdev, struct mount *mp));
 void 	vput __P((struct vnode *vp));
+void 	vref __P((struct vnode *vp));
 void 	vrele __P((struct vnode *vp));
-void	vtouch __P((struct vnode *vp));
 #endif /* KERNEL */
 
 #endif /* !_SYS_VNODE_H_ */
Index: ufs/lfs/lfs_segment.c
===================================================================
RCS file: /home/ncvs/src/sys/ufs/lfs/lfs_segment.c,v
retrieving revision 1.23
diff -u -r1.23 lfs_segment.c
--- lfs_segment.c	1997/08/02 14:33:20	1.23
+++ lfs_segment.c	1997/08/26 21:52:22
@@ -1222,7 +1222,7 @@
 
 	if ((vp->v_flag & VXLOCK) ||	/* XXX */
 	    (vp->v_usecount == 0 &&
-	     vp->v_freelist.tqe_prev == (struct vnode **)0xdeadb))
+	     vp->v_flag & VDOOMED))
 		return(1);
 	return (vget(vp, 0, p));
 }
Index: vm/vm_swap.c
===================================================================
RCS file: /home/ncvs/src/sys/vm/vm_swap.c,v
retrieving revision 1.43
diff -u -r1.43 vm_swap.c
--- vm_swap.c	1997/03/23 03:37:54	1.43
+++ vm_swap.c	1997/08/26 22:03:54
@@ -136,7 +136,7 @@
 		biodone(bp);
 		return;
 	}
-	VHOLD(sp->sw_vp);
+	vhold(sp->sw_vp);
 	if ((bp->b_flags & B_READ) == 0) {
 		vp = bp->b_vp;
 		if (vp) {
--
Poul-Henning Kamp             FreeBSD coreteam member
phk@FreeBSD.ORG               "Real hackers run -current on their laptop."



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