Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 11 Jun 2010 17:03:26 +0000 (UTC)
From:      Matthew D Fleming <mdf@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r209053 - in head/sys: kern sys
Message-ID:  <201006111703.o5BH3Qrx035790@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mdf
Date: Fri Jun 11 17:03:26 2010
New Revision: 209053
URL: http://svn.freebsd.org/changeset/base/209053

Log:
  Add INVARIANTS checking that numfreebufs values are sane.  Also add a
  per-buf flag to catch if a buf is double-counted in the free count.
  This code was useful to debug an instance where a local patch at Isilon
  was incorrectly managing numfreebufs for a new buf state.
  
  Reviewed by:	jeff
  Approved by:	zml (mentor)

Modified:
  head/sys/kern/vfs_bio.c
  head/sys/sys/buf.h

Modified: head/sys/kern/vfs_bio.c
==============================================================================
--- head/sys/kern/vfs_bio.c	Fri Jun 11 17:03:04 2010	(r209052)
+++ head/sys/kern/vfs_bio.c	Fri Jun 11 17:03:26 2010	(r209053)
@@ -393,10 +393,16 @@ runningbufwakeup(struct buf *bp)
  */
 
 static __inline void
-bufcountwakeup(void) 
+bufcountwakeup(struct buf *bp) 
 {
+	int old;
 
-	atomic_add_int(&numfreebuffers, 1);
+	KASSERT((bp->b_vflags & BV_INFREECNT) == 0,
+	    ("buf %p already counted as free", bp));
+	bp->b_vflags |= BV_INFREECNT;
+	old = atomic_fetchadd_int(&numfreebuffers, 1);
+	KASSERT(old >= 0 && old < nbuf,
+	    ("numfreebuffers climbed to %d", old + 1));
 	mtx_lock(&nblock);
 	if (needsbuffer) {
 		needsbuffer &= ~VFS_BIO_NEED_ANY;
@@ -592,7 +598,7 @@ bufinit(void)
 		bp->b_rcred = NOCRED;
 		bp->b_wcred = NOCRED;
 		bp->b_qindex = QUEUE_EMPTY;
-		bp->b_vflags = 0;
+		bp->b_vflags = BV_INFREECNT;	/* buf is counted as free */
 		bp->b_xflags = 0;
 		LIST_INIT(&bp->b_dep);
 		BUF_LOCKINIT(bp);
@@ -686,6 +692,7 @@ bfreekva(struct buf *bp)
 void
 bremfree(struct buf *bp)
 {
+	int old;
 
 	CTR3(KTR_BUF, "bremfree(%p) vp %p flags %X", bp, bp->b_vp, bp->b_flags);
 	KASSERT((bp->b_flags & B_REMFREE) == 0,
@@ -696,8 +703,13 @@ bremfree(struct buf *bp)
 
 	bp->b_flags |= B_REMFREE;
 	/* Fixup numfreebuffers count.  */
-	if ((bp->b_flags & B_INVAL) || (bp->b_flags & B_DELWRI) == 0)
-		atomic_subtract_int(&numfreebuffers, 1);
+	if ((bp->b_flags & B_INVAL) || (bp->b_flags & B_DELWRI) == 0) {
+		KASSERT((bp->b_vflags & BV_INFREECNT) != 0,
+		    ("buf %p not counted in numfreebuffers", bp));
+		bp->b_vflags &= ~BV_INFREECNT;
+		old = atomic_fetchadd_int(&numfreebuffers, -1);
+		KASSERT(old > 0, ("numfreebuffers dropped to %d", old - 1));
+	}
 }
 
 /*
@@ -723,6 +735,8 @@ bremfreef(struct buf *bp)
 static void
 bremfreel(struct buf *bp)
 {
+	int old;
+
 	CTR3(KTR_BUF, "bremfreel(%p) vp %p flags %X",
 	    bp, bp->b_vp, bp->b_flags);
 	KASSERT(bp->b_qindex != QUEUE_NONE,
@@ -745,8 +759,13 @@ bremfreel(struct buf *bp)
 	 * delayed-write, the buffer was free and we must decrement
 	 * numfreebuffers.
 	 */
-	if ((bp->b_flags & B_INVAL) || (bp->b_flags & B_DELWRI) == 0)
-		atomic_subtract_int(&numfreebuffers, 1);
+	if ((bp->b_flags & B_INVAL) || (bp->b_flags & B_DELWRI) == 0) {
+		KASSERT((bp->b_vflags & BV_INFREECNT) != 0,
+		    ("buf %p not counted in numfreebuffers", bp));
+		bp->b_vflags &= ~BV_INFREECNT;
+		old = atomic_fetchadd_int(&numfreebuffers, -1);
+		KASSERT(old > 0, ("numfreebuffers dropped to %d", old - 1));
+	}
 }
 
 
@@ -1448,7 +1467,7 @@ brelse(struct buf *bp)
 	 */
 
 	if (!(bp->b_flags & B_DELWRI))
-		bufcountwakeup();
+		bufcountwakeup(bp);
 
 	/*
 	 * Something we can maybe free or reuse
@@ -1537,7 +1556,7 @@ bqrelse(struct buf *bp)
 	mtx_unlock(&bqlock);
 
 	if ((bp->b_flags & B_INVAL) || !(bp->b_flags & B_DELWRI))
-		bufcountwakeup();
+		bufcountwakeup(bp);
 
 	/*
 	 * Something we can maybe free or reuse.
@@ -1916,6 +1935,8 @@ restart:
 		bp->b_flags = 0;
 		bp->b_ioflags = 0;
 		bp->b_xflags = 0;
+		KASSERT((bp->b_vflags & BV_INFREECNT) == 0,
+		    ("buf %p still counted as free?", bp));
 		bp->b_vflags = 0;
 		bp->b_vp = NULL;
 		bp->b_blkno = bp->b_lblkno = 0;
@@ -4103,4 +4124,27 @@ DB_SHOW_COMMAND(vnodebufs, db_show_vnode
 		db_printf("\n");
 	}
 }
+
+DB_COMMAND(countfreebufs, db_coundfreebufs)
+{
+	struct buf *bp;
+	int i, used = 0, nfree = 0;
+
+	if (have_addr) {
+		db_printf("usage: countfreebufs\n");
+		return;
+	}
+
+	for (i = 0; i < nbuf; i++) {
+		bp = &buf[i];
+		if ((bp->b_vflags & BV_INFREECNT) != 0)
+			nfree++;
+		else
+			used++;
+	}
+
+	db_printf("Counted %d free, %d used (%d tot)\n", nfree, used,
+	    nfree + used);
+	db_printf("numfreebuffers is %d\n", numfreebuffers);
+}
 #endif /* DDB */

Modified: head/sys/sys/buf.h
==============================================================================
--- head/sys/sys/buf.h	Fri Jun 11 17:03:04 2010	(r209052)
+++ head/sys/sys/buf.h	Fri Jun 11 17:03:26 2010	(r209053)
@@ -247,6 +247,7 @@ struct buf {
 #define	BV_SCANNED	0x00000001	/* VOP_FSYNC funcs mark written bufs */
 #define	BV_BKGRDINPROG	0x00000002	/* Background write in progress */
 #define	BV_BKGRDWAIT	0x00000004	/* Background write waiting */
+#define	BV_INFREECNT	0x80000000	/* buf is counted in numfreebufs */
 
 #ifdef _KERNEL
 /*



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