diff options
author | jeff <jeff@FreeBSD.org> | 2005-01-28 17:48:58 +0000 |
---|---|---|
committer | jeff <jeff@FreeBSD.org> | 2005-01-28 17:48:58 +0000 |
commit | da8e6b049d64000330d05849f934c53d0de9d4be (patch) | |
tree | 17ce7797ccdf13f98be78a5dc720ed28d35071d9 | |
parent | 6173443fc51963d141a7f4ffbe9c05913d8e05d7 (diff) | |
download | FreeBSD-src-da8e6b049d64000330d05849f934c53d0de9d4be.zip FreeBSD-src-da8e6b049d64000330d05849f934c53d0de9d4be.tar.gz |
- Don't drop the wref on the bufobj until after bufdone() has completed.
Without this, threads waiting in bufobj_wwait() may wakeup prior to
bufdone() completing.
Sponsored by: Isilon Systems, Inc.
-rw-r--r-- | sys/kern/vfs_bio.c | 17 |
1 files changed, 10 insertions, 7 deletions
diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c index 1cdb6e5..044e7e1 100644 --- a/sys/kern/vfs_bio.c +++ b/sys/kern/vfs_bio.c @@ -3178,21 +3178,21 @@ dev_strategy(struct cdev *dev, struct buf *bp) void bufdone(struct buf *bp) { + struct bufobj *dropobj; int s; void (*biodone)(struct buf *); CTR3(KTR_BUF, "bufdone(%p) vp %p flags %X", bp, bp->b_vp, bp->b_flags); s = splbio(); + dropobj = NULL; KASSERT(BUF_REFCNT(bp) > 0, ("biodone: bp %p not busy %d", bp, BUF_REFCNT(bp))); KASSERT(!(bp->b_flags & B_DONE), ("biodone: bp %p already done", bp)); runningbufwakeup(bp); - - if (bp->b_iocmd == BIO_WRITE && bp->b_bufobj != NULL) - bufobj_wdrop(bp->b_bufobj); - + if (bp->b_iocmd == BIO_WRITE) + dropobj = bp->b_bufobj; /* call optional completion function if requested */ if (bp->b_iodone != NULL) { biodone = bp->b_iodone; @@ -3202,9 +3202,11 @@ bufdone(struct buf *bp) * if we're calling into unknown code. */ mtx_lock(&Giant); - bp->b_flags |= B_DONE; /* XXX Should happen after biodone? */ + bp->b_flags |= B_DONE; (*biodone) (bp); mtx_unlock(&Giant); + if (dropobj) + bufobj_wdrop(dropobj); splx(s); return; } @@ -3338,9 +3340,10 @@ bufdone(struct buf *bp) brelse(bp); else bqrelse(bp); - } else { + } else bdone(bp); - } + if (dropobj) + bufobj_wdrop(dropobj); splx(s); } |