summaryrefslogtreecommitdiffstats
path: root/sys/kern/vfs_bio.c
diff options
context:
space:
mode:
authormdf <mdf@FreeBSD.org>2010-06-11 17:03:26 +0000
committermdf <mdf@FreeBSD.org>2010-06-11 17:03:26 +0000
commit09830f0c6f6176f6e31316658158ef9f89afb842 (patch)
treef8d3891a1ce51c848f38a113365c3c5280b65285 /sys/kern/vfs_bio.c
parent972d4b6a91487a21f17e0c177eb6e6d6c2f5ee48 (diff)
downloadFreeBSD-src-09830f0c6f6176f6e31316658158ef9f89afb842.zip
FreeBSD-src-09830f0c6f6176f6e31316658158ef9f89afb842.tar.gz
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)
Diffstat (limited to 'sys/kern/vfs_bio.c')
-rw-r--r--sys/kern/vfs_bio.c64
1 files changed, 54 insertions, 10 deletions
diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c
index 5429b14..df8bf66 100644
--- a/sys/kern/vfs_bio.c
+++ b/sys/kern/vfs_bio.c
@@ -393,10 +393,16 @@ runningbufwakeup(struct buf *bp)
*/
static __inline void
-bufcountwakeup(void)
+bufcountwakeup(struct buf *bp)
{
-
- atomic_add_int(&numfreebuffers, 1);
+ int old;
+
+ 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_vnodebufs)
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 */
OpenPOWER on IntegriCloud