diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c index 81c7af40811f..333f44789fba 100644 --- a/sys/ufs/ffs/ffs_vnops.c +++ b/sys/ufs/ffs/ffs_vnops.c @@ -718,15 +718,6 @@ ffs_write(ap) vnode_pager_setsize(vp, ip->i_size); break; } - /* - * If the buffer is not valid we have to clear out any - * garbage data from the pages instantiated for the buffer. - * If we do not, a failed uiomove() during a write can leave - * the prior contents of the pages exposed to a userland - * mmap(). XXX deal with uiomove() errors a better way. - */ - if ((bp->b_flags & B_CACHE) == 0 && fs->fs_bsize <= xfersize) - vfs_bio_clrbuf(bp); if (ioflag & IO_DIRECT) bp->b_flags |= B_DIRECT; if ((ioflag & (IO_SYNC|IO_INVAL)) == (IO_SYNC|IO_INVAL)) @@ -743,6 +734,26 @@ ffs_write(ap) error = uiomove((char *)bp->b_data + blkoffset, (int)xfersize, uio); + /* + * If the buffer is not already filled and we encounter an + * error while trying to fill it, we have to clear out any + * garbage data from the pages instantiated for the buffer. + * If we do not, a failed uiomove() during a write can leave + * the prior contents of the pages exposed to a userland mmap. + * + * Note that we need only clear buffers with a transfer size + * equal to the block size because buffers with a shorter + * transfer size were cleared above by the call to UFS_BALLOC() + * with the BA_CLRBUF flag set. + * + * If the source region for uiomove identically mmaps the + * buffer, uiomove() performed the NOP copy, and the buffer + * content remains valid because the page fault handler + * validated the pages. + */ + if (error != 0 && (bp->b_flags & B_CACHE) == 0 && + fs->fs_bsize == xfersize) + vfs_bio_clrbuf(bp); if ((ioflag & (IO_VMIO|IO_DIRECT)) && (LIST_EMPTY(&bp->b_dep))) { bp->b_flags |= B_RELBUF;