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>