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)
This commit is contained in:
parent
3ba5db25bb
commit
d19511c357
@ -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 @@ getnewbuf(struct vnode *vp, int slpflag, int slptimeo, int size, int maxsize,
|
||||
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 */
|
||||
|
@ -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
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user