- Don't set our bio op to be a READ when we've just completed a write. There

are subtle differences in the read and write completion path.  Instead,
   grab an extra write ref so the write path can drop it when we recursively
   call bufdone().  I believe this may be the source of the wrong bufobj
   panics.

Reported by:	pho, kkenn
This commit is contained in:
Jeff Roberson 2005-05-30 07:04:15 +00:00
parent 1f22a07afd
commit 204ec66d38

View File

@ -1507,15 +1507,19 @@ SYSCTL_INT(_debug, OID_AUTO, dobkgrdwrite, CTLFLAG_RW, &dobkgrdwrite, 0,
static void
ffs_backgroundwritedone(struct buf *bp)
{
struct bufobj *bufobj;
struct buf *origbp;
/*
* Find the original buffer that we are writing.
*/
BO_LOCK(bp->b_bufobj);
bufobj = bp->b_bufobj;
BO_LOCK(bufobj);
if ((origbp = gbincore(bp->b_bufobj, bp->b_lblkno)) == NULL)
panic("backgroundwritedone: lost buffer");
BO_UNLOCK(bp->b_bufobj);
/* Grab an extra reference to be dropped by the bufdone() below. */
bufobj_wrefl(bufobj);
BO_UNLOCK(bufobj);
/*
* Process dependencies then return any unfinished ones.
*/
@ -1525,18 +1529,14 @@ ffs_backgroundwritedone(struct buf *bp)
if (LIST_FIRST(&bp->b_dep) != NULL)
softdep_move_dependencies(bp, origbp);
#endif
/*
* This buffer is marked B_NOCACHE, so when it is released
* by biodone, it will be tossed. We mark it with BIO_READ
* to avoid biodone doing a second bufobj_wdrop.
* This buffer is marked B_NOCACHE so when it is released
* by biodone it will be tossed.
*/
bp->b_flags |= B_NOCACHE;
bp->b_iocmd = BIO_READ;
bp->b_flags &= ~(B_CACHE | B_DONE);
bp->b_iodone = 0;
bufdone(bp);
BO_LOCK(origbp->b_bufobj);
BO_LOCK(bufobj);
/*
* Clear the BV_BKGRDINPROG flag in the original buffer
* and awaken it if it is waiting for the write to complete.
@ -1550,7 +1550,7 @@ ffs_backgroundwritedone(struct buf *bp)
origbp->b_vflags &= ~BV_BKGRDWAIT;
wakeup(&origbp->b_xflags);
}
BO_UNLOCK(origbp->b_bufobj);
BO_UNLOCK(bufobj);
}