summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorattilio <attilio@FreeBSD.org>2009-03-17 16:30:49 +0000
committerattilio <attilio@FreeBSD.org>2009-03-17 16:30:49 +0000
commit9c2a3fc7812497e081f6d5eafee175078576df39 (patch)
tree12f7aeec43c8db88c9f3bdf1bda56a24fcf4e608
parent1723e39bc493ee094c80dc9da904119a566cc56f (diff)
downloadFreeBSD-src-9c2a3fc7812497e081f6d5eafee175078576df39.zip
FreeBSD-src-9c2a3fc7812497e081f6d5eafee175078576df39.tar.gz
Fix an old-standing bug that crept in along the several revisions:
B_DELWRI cleanup and vnode disassociation should happen just before to assign the buffer to a queue. Reported by: miwi, Volker <volker at vwsoft dot com>, Ben Kaduk <minimarmot at gmail dot com>, Christopher Mallon <christoph dot mallon at gmx dot de> Tested by: lulf, miwi
-rw-r--r--sys/kern/vfs_bio.c30
1 files changed, 15 insertions, 15 deletions
diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c
index e4d1e47..7597a39 100644
--- a/sys/kern/vfs_bio.c
+++ b/sys/kern/vfs_bio.c
@@ -1369,9 +1369,23 @@ brelse(struct buf *bp)
if (bp->b_qindex != QUEUE_NONE)
panic("brelse: free buffer onto another queue???");
+ /*
+ * If the buffer has junk contents signal it and eventually
+ * clean up B_DELWRI and diassociate the vnode so that gbincore()
+ * doesn't find it.
+ */
+ if (bp->b_bufsize == 0 || (bp->b_ioflags & BIO_ERROR) != 0 ||
+ (bp->b_flags & (B_INVAL | B_NOCACHE | B_RELBUF)) != 0)
+ bp->b_flags |= B_INVAL;
+ if (bp->b_flags & B_INVAL) {
+ if (bp->b_flags & B_DELWRI)
+ bundirty(bp);
+ if (bp->b_vp)
+ brelvp(bp);
+ }
+
/* buffers with no memory */
if (bp->b_bufsize == 0) {
- bp->b_flags |= B_INVAL;
bp->b_xflags &= ~(BX_BKGRDWRITE | BX_ALTDATA);
if (bp->b_vflags & BV_BKGRDINPROG)
panic("losing buffer 1");
@@ -1384,7 +1398,6 @@ brelse(struct buf *bp)
/* buffers with junk contents */
} else if (bp->b_flags & (B_INVAL | B_NOCACHE | B_RELBUF) ||
(bp->b_ioflags & BIO_ERROR)) {
- bp->b_flags |= B_INVAL;
bp->b_xflags &= ~(BX_BKGRDWRITE | BX_ALTDATA);
if (bp->b_vflags & BV_BKGRDINPROG)
panic("losing buffer 2");
@@ -1407,19 +1420,6 @@ brelse(struct buf *bp)
mtx_unlock(&bqlock);
/*
- * If B_INVAL and B_DELWRI is set, clear B_DELWRI. We have already
- * placed the buffer on the correct queue. We must also disassociate
- * the device and vnode for a B_INVAL buffer so gbincore() doesn't
- * find it.
- */
- if (bp->b_flags & B_INVAL) {
- if (bp->b_flags & B_DELWRI)
- bundirty(bp);
- if (bp->b_vp)
- brelvp(bp);
- }
-
- /*
* Fixup numfreebuffers count. The bp is on an appropriate queue
* unless locked. We then bump numfreebuffers if it is not B_DELWRI.
* We've already handled the B_INVAL case ( B_DELWRI will be clear
OpenPOWER on IntegriCloud