Index: sys/kern/vfs_bio.c =================================================================== --- sys/kern/vfs_bio.c +++ sys/kern/vfs_bio.c @@ -3887,8 +3887,9 @@ */ lockflags = LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK; - if (flags & GB_LOCK_NOWAIT) + if ((flags & GB_LOCK_NOWAIT) != 0) lockflags |= LK_NOWAIT; + bp->b_flags &= ~B_HOLE; error = BUF_TIMELOCK(bp, lockflags, BO_LOCKPTR(bo), "getblk", slpflag, slptimeo); @@ -4006,10 +4007,10 @@ * here. */ if (flags & GB_NOCREAT) - return NULL; + return (NULL); if (bdomain[bo->bo_domain].bd_freebuffers == 0 && TD_IS_IDLETHREAD(curthread)) - return NULL; + return (NULL); bsize = vn_isdisk(vp, NULL) ? DEV_BSIZE : bo->bo_bsize; KASSERT(bsize != 0, ("bsize == 0, check bo->bo_bsize")); @@ -4027,7 +4028,7 @@ bp = getnewbuf(vp, slpflag, slptimeo, maxsize, flags); if (bp == NULL) { if (slpflag || slptimeo) - return NULL; + return (NULL); /* * XXX This is here until the sleep path is diagnosed * enough to work under very low memory conditions. @@ -4101,6 +4102,10 @@ allocbuf(bp, size); bufspace_release(bufdomain(bp), maxsize); bp->b_flags &= ~B_DONE; + if (flags & GB_HOLE) + bp->b_flags |= B_HOLE; + else + bp->b_flags &= ~B_HOLE; } CTR4(KTR_BUF, "getblk(%p, %ld, %d) = %p", vp, (long)blkno, size, bp); BUF_ASSERT_HELD(bp); @@ -4435,6 +4440,7 @@ KASSERT(buf_mapped(bp), ("bufdone: bp %p not mapped", bp)); (*bp->b_ckhashcalc)(bp); } + bp->b_flags &= ~B_HOLE; /* * For asynchronous completions, release the buffer now. The brelse * will do a wakeup there if necessary - so no need to do a wakeup Index: sys/sys/buf.h =================================================================== --- sys/sys/buf.h +++ sys/sys/buf.h @@ -225,7 +225,7 @@ #define B_NOCACHE 0x00008000 /* Do not cache block after use. */ #define B_MALLOC 0x00010000 /* malloced b_data */ #define B_CLUSTEROK 0x00020000 /* Pagein op, so swap() can count it. */ -#define B_00040000 0x00040000 /* Available flag. */ +#define B_HOLE 0x00040000 /* Do not instantiate hole. */ #define B_00080000 0x00080000 /* Available flag. */ #define B_00100000 0x00100000 /* Available flag. */ #define B_00200000 0x00200000 /* Available flag. */ @@ -479,6 +479,7 @@ #define GB_UNMAPPED 0x0008 /* Do not mmap buffer pages. */ #define GB_KVAALLOC 0x0010 /* But allocate KVA. */ #define GB_CKHASH 0x0020 /* If reading, calc checksum hash */ +#define GB_HOLE 0x0040 /* Do not instantiate holes */ #ifdef _KERNEL extern int nbuf; /* The number of buffer headers */ Index: sys/ufs/ffs/ffs_vnops.c =================================================================== --- sys/ufs/ffs/ffs_vnops.c +++ sys/ufs/ffs/ffs_vnops.c @@ -462,6 +462,25 @@ #endif } +static int +ffs_read_hole(struct uio *uio, long xfersize, long *size) +{ + ssize_t saved_resid, tlen; + int error; + + while (xfersize > 0) { + tlen = min(xfersize, ZERO_REGION_SIZE); + saved_resid = uio->uio_resid; + error = uiomove(__DECONST(void *, zero_region), tlen, uio); + if (error != 0) + return (error); + tlen = saved_resid - uio->uio_resid; + xfersize -= tlen; + *size -= tlen; + } + return (0); +} + /* * Vnode op for reading. */ @@ -566,7 +585,7 @@ * Don't do readahead if this is the end of the file. */ error = bread_gb(vp, lbn, size, NOCRED, - GB_UNMAPPED, &bp); + GB_UNMAPPED | GB_HOLE, &bp); } else if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) { /* * Otherwise if we are allowed to cluster, @@ -577,7 +596,7 @@ */ error = cluster_read(vp, ip->i_size, lbn, size, NOCRED, blkoffset + uio->uio_resid, - seqcount, GB_UNMAPPED, &bp); + seqcount, GB_UNMAPPED | GB_HOLE, &bp); } else if (seqcount > 1) { /* * If we are NOT allowed to cluster, then @@ -589,7 +608,8 @@ */ u_int nextsize = blksize(fs, ip, nextlbn); error = breadn_flags(vp, lbn, size, &nextlbn, - &nextsize, 1, NOCRED, GB_UNMAPPED, NULL, &bp); + &nextsize, 1, NOCRED, GB_UNMAPPED | GB_HOLE, + NULL, &bp); } else { /* * Failing all of the above, just read what the @@ -597,9 +617,14 @@ * the first option above. */ error = bread_gb(vp, lbn, size, NOCRED, - GB_UNMAPPED, &bp); + GB_UNMAPPED | GB_HOLE, &bp); } - if (error) { + if (error == EJUSTRETURN) { + error = ffs_read_hole(uio, xfersize, &size); + if (error == 0) + continue; + } + if (error != 0) { brelse(bp); bp = NULL; break; Index: sys/ufs/ufs/ufs_vnops.c =================================================================== --- sys/ufs/ufs/ufs_vnops.c +++ sys/ufs/ufs/ufs_vnops.c @@ -2334,10 +2334,14 @@ bufdone(bp); return (0); } - if ((long)bp->b_blkno == -1) + if ((long)bp->b_blkno == -1 && (bp->b_flags & B_HOLE) == 0) vfs_bio_clrbuf(bp); } if ((long)bp->b_blkno == -1) { + if ((bp->b_flags & B_HOLE) != 0) { + bp->b_error = EJUSTRETURN; + bp->b_ioflags |= BIO_ERROR; + } bufdone(bp); return (0); }