diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c index 6b8f79f9623..eb392cb1b83 100644 --- a/sys/kern/vfs_bio.c +++ b/sys/kern/vfs_bio.c @@ -1809,6 +1809,8 @@ breada(struct vnode * vp, daddr_t * rablkno, int * rabsize, * must clear BIO_ERROR and B_INVAL prior to initiating I/O. If B_CACHE * is set, the buffer is valid and we do not have to do anything, see * getblk(). Also starts asynchronous I/O on read-ahead blocks. + * + * Always return a NULL buffer pointer (in bpp) when returning an error. */ int breadn_flags(struct vnode *vp, daddr_t blkno, int size, daddr_t *rablkno, @@ -1844,6 +1846,10 @@ breadn_flags(struct vnode *vp, daddr_t blkno, int size, daddr_t *rablkno, if (readwait) { rv = bufwait(bp); + if (rv != 0) { + brelse(bp); + *bpp = NULL; + } } return (rv); } @@ -2238,6 +2244,12 @@ brelse(struct buf *bp) { int qindex; + /* + * Many function erroneously call brelse with a NULL bp under rare + * error conditions. Simply return when called with a NULL bp. + */ + if (bp == NULL) + return; CTR3(KTR_BUF, "brelse(%p) vp %p flags %X", bp, bp->b_vp, bp->b_flags); KASSERT(!(bp->b_flags & (B_CLUSTER|B_PAGING)), diff --git a/sys/kern/vfs_cluster.c b/sys/kern/vfs_cluster.c index 476b28a0153..9871a505631 100644 --- a/sys/kern/vfs_cluster.c +++ b/sys/kern/vfs_cluster.c @@ -119,6 +119,8 @@ cluster_read(struct vnode *vp, u_quad_t filesize, daddr_t lblkno, long size, * get the requested block */ *bpp = reqbp = bp = getblk(vp, lblkno, size, 0, 0, gbflags); + if (bp == NULL) + return (EBUSY); origblkno = lblkno; /* @@ -295,10 +297,18 @@ cluster_read(struct vnode *vp, u_quad_t filesize, daddr_t lblkno, long size, curthread->td_ru.ru_inblock++; } - if (reqbp) - return (bufwait(reqbp)); - else - return (error); + if (reqbp) { + /* + * Like bread, always brelse() the buffer when + * returning an error. + */ + error = bufwait(reqbp); + if (error != 0) { + brelse(reqbp); + *bpp = NULL; + } + } + return (error); } /* diff --git a/sys/ufs/ffs/ffs_inode.c b/sys/ufs/ffs/ffs_inode.c index 1647080371e..b41e04b05ad 100644 --- a/sys/ufs/ffs/ffs_inode.c +++ b/sys/ufs/ffs/ffs_inode.c @@ -113,10 +113,8 @@ loop: fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), (int) fs->fs_bsize, 0, 0, 0, NOCRED, flags, &bp); if (error != 0) { - if (error != EBUSY) { - brelse(bp); + if (error != EBUSY) return (error); - } KASSERT((IS_SNAPSHOT(ip)), ("EBUSY from non-snapshot")); /* * Wait for our inode block to become available.