Don't try to write out bufs that have already failed with ENXIO.

This fixes some panics after disconnecting mounted disks.

Submitted by:	imp (slightly different version, which I've then lost)
Reviewed by:	kib, imp, mckusick
MFC after:	2 weeks
Differential Revision:	https://reviews.freebsd.org/D9674
This commit is contained in:
Edward Tomasz Napierala 2017-04-14 20:15:34 +00:00
parent e3951def25
commit b66f26e931

View File

@ -2290,18 +2290,28 @@ brelse(struct buf *bp)
bdirty(bp);
}
if (bp->b_iocmd == BIO_WRITE && (bp->b_ioflags & BIO_ERROR) &&
(bp->b_error != ENXIO || !LIST_EMPTY(&bp->b_dep)) &&
!(bp->b_flags & B_INVAL)) {
/*
* Failed write, redirty. Must clear BIO_ERROR to prevent
* pages from being scrapped.
* Failed write, redirty. All errors except ENXIO (which
* means the device is gone) are expected to be potentially
* transient - underlying media might work if tried again
* after EIO, and memory might be available after an ENOMEM.
*
* Do this also for buffers that failed with ENXIO, but have
* non-empty dependencies - the soft updates code might need
* to access the buffer to untangle them.
*
* Must clear BIO_ERROR to prevent pages from being scrapped.
*/
bp->b_ioflags &= ~BIO_ERROR;
bdirty(bp);
} else if ((bp->b_flags & (B_NOCACHE | B_INVAL)) ||
(bp->b_ioflags & BIO_ERROR) || (bp->b_bufsize <= 0)) {
/*
* Either a failed read I/O or we were asked to free or not
* cache the buffer.
* Either a failed read I/O, or we were asked to free or not
* cache the buffer, or we failed to write to a device that's
* no longer present.
*/
bp->b_flags |= B_INVAL;
if (!LIST_EMPTY(&bp->b_dep))