Index: sys/fs/ext2fs/ext2_vnops.c =================================================================== --- sys/fs/ext2fs/ext2_vnops.c +++ sys/fs/ext2fs/ext2_vnops.c @@ -1726,25 +1726,7 @@ (int)xfersize, uio); if (error) break; - - if (ioflag & (IO_VMIO|IO_DIRECT)) { - /* - * If it's VMIO or direct I/O, then we don't - * need the buf, mark it available for - * freeing. If it's non-direct VMIO, the VM has - * the data. - */ - bp->b_flags |= B_RELBUF; - brelse(bp); - } else { - /* - * Otherwise let whoever - * made the request take care of - * freeing it. We just queue - * it onto another list. - */ - bqrelse(bp); - } + vfs_bio_rbrelse(bp, ioflag); } /* @@ -1753,14 +1735,8 @@ * and on normal completion has not set a new value into it. * so it must have come from a 'break' statement */ - if (bp != NULL) { - if (ioflag & (IO_VMIO|IO_DIRECT)) { - bp->b_flags |= B_RELBUF; - brelse(bp); - } else { - bqrelse(bp); - } - } + if (bp != NULL) + vfs_bio_rbrelse(bp, ioflag); if ((error == 0 || uio->uio_resid != orig_resid) && (vp->v_mount->mnt_flag & (MNT_NOATIME | MNT_RDONLY)) == 0) @@ -2018,8 +1994,10 @@ if (error != 0 && (bp->b_flags & B_CACHE) == 0 && fs->e2fs_bsize == xfersize) vfs_bio_clrbuf(bp); - if (ioflag & (IO_VMIO|IO_DIRECT)) { + if ((ioflag & (IO_VMIO | IO_DIRECT)) != 0) { bp->b_flags |= B_RELBUF; + if ((ioflag & IO_NOREUSE) != 0) + bp->b_flags |= B_NOREUSE; } /* Index: sys/kern/vfs_bio.c =================================================================== --- sys/kern/vfs_bio.c +++ sys/kern/vfs_bio.c @@ -4414,6 +4414,28 @@ } /* + * Release a buffer that was used for reading. If it's VMIO or direct I/O, + * release the buffer pages to the VM, where they may be placed on a page queue + * (VMIO) or freed immediately (direct I/O). Otherwise the buffer is released + * to the cache. + */ +void +vfs_bio_rbrelse(struct buf *bp, int ioflag) +{ + + KASSERT((ioflag & IO_NOREUSE) == 0 || (ioflag & IO_VMIO) != 0, + ("buf %p non-VMIO noreuse", bp)); + + if ((ioflag & (IO_VMIO | IO_DIRECT)) != 0 && LIST_EMPTY(&bp->b_dep)) { + bp->b_flags |= B_RELBUF; + if ((ioflag & IO_NOREUSE) != 0) + bp->b_flags |= B_NOREUSE; + brelse(bp); + } else + bqrelse(bp); +} + +/* * vm_hold_load_pages and vm_hold_free_pages get pages into * a buffers address space. The pages are anonymous and are * not associated with a file object. Index: sys/sys/buf.h =================================================================== --- sys/sys/buf.h +++ sys/sys/buf.h @@ -539,8 +539,9 @@ int cluster_wbuild(struct vnode *, long, daddr_t, int, int); void cluster_write(struct vnode *, struct buf *, u_quad_t, int, int); void vfs_bio_bzero_buf(struct buf *bp, int base, int size); -void vfs_bio_set_valid(struct buf *, int base, int size); void vfs_bio_clrbuf(struct buf *); +void vfs_bio_rbrelse(struct buf *bp, int ioflags); +void vfs_bio_set_valid(struct buf *, int base, int size); void vfs_busy_pages(struct buf *, int clear_modify); void vfs_unbusy_pages(struct buf *); int vmapbuf(struct buf *, int); Index: sys/sys/vnode.h =================================================================== --- sys/sys/vnode.h +++ sys/sys/vnode.h @@ -307,6 +307,7 @@ #define IO_INVAL 0x0040 /* invalidate after I/O */ #define IO_SYNC 0x0080 /* do I/O synchronously */ #define IO_DIRECT 0x0100 /* attempt to bypass buffer cache */ +#define IO_NOREUSE 0x0200 /* VMIO data won't be reused */ #define IO_EXT 0x0400 /* operate on external attributes */ #define IO_NORMAL 0x0800 /* operate on regular data */ #define IO_NOMACCHECK 0x1000 /* MAC checks unnecessary */ Index: sys/ufs/ffs/ffs_vnops.c =================================================================== --- sys/ufs/ffs/ffs_vnops.c +++ sys/ufs/ffs/ffs_vnops.c @@ -632,26 +632,7 @@ } if (error) break; - - if ((ioflag & (IO_VMIO|IO_DIRECT)) && - (LIST_EMPTY(&bp->b_dep))) { - /* - * If there are no dependencies, and it's VMIO, - * then we don't need the buf, mark it available - * for freeing. For non-direct VMIO reads, the VM - * has the data. - */ - bp->b_flags |= B_RELBUF; - brelse(bp); - } else { - /* - * Otherwise let whoever - * made the request take care of - * freeing it. We just queue - * it onto another list. - */ - bqrelse(bp); - } + vfs_bio_rbrelse(bp, ioflag); } /* @@ -660,15 +641,8 @@ * and on normal completion has not set a new value into it. * so it must have come from a 'break' statement */ - if (bp != NULL) { - if ((ioflag & (IO_VMIO|IO_DIRECT)) && - (LIST_EMPTY(&bp->b_dep))) { - bp->b_flags |= B_RELBUF; - brelse(bp); - } else { - bqrelse(bp); - } - } + if (bp != NULL) + vfs_bio_rbrelse(bp, ioflag); if ((error == 0 || uio->uio_resid != orig_resid) && (vp->v_mount->mnt_flag & (MNT_NOATIME | MNT_RDONLY)) == 0 && @@ -827,9 +801,11 @@ 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))) { + if ((ioflag & (IO_VMIO | IO_DIRECT)) != 0 && + LIST_EMPTY(&bp->b_dep)) { bp->b_flags |= B_RELBUF; + if ((ioflag & IO_NOREUSE) != 0) + bp->b_flags |= B_NOREUSE; } /* @@ -1004,26 +980,7 @@ (int)xfersize, uio); if (error) break; - - if ((ioflag & (IO_VMIO|IO_DIRECT)) && - (LIST_EMPTY(&bp->b_dep))) { - /* - * If there are no dependencies, and it's VMIO, - * then we don't need the buf, mark it available - * for freeing. For non-direct VMIO reads, the VM - * has the data. - */ - bp->b_flags |= B_RELBUF; - brelse(bp); - } else { - /* - * Otherwise let whoever - * made the request take care of - * freeing it. We just queue - * it onto another list. - */ - bqrelse(bp); - } + vfs_bio_rbrelse(bp, ioflag); } /* @@ -1032,15 +989,8 @@ * and on normal completion has not set a new value into it. * so it must have come from a 'break' statement */ - if (bp != NULL) { - if ((ioflag & (IO_VMIO|IO_DIRECT)) && - (LIST_EMPTY(&bp->b_dep))) { - bp->b_flags |= B_RELBUF; - brelse(bp); - } else { - bqrelse(bp); - } - } + if (bp != NULL) + vfs_bio_rbrelse(bp, ioflag); return (error); } @@ -1121,9 +1071,11 @@ error = uiomove((char *)bp->b_data + blkoffset, (int)xfersize, uio); - if ((ioflag & (IO_VMIO|IO_DIRECT)) && - (LIST_EMPTY(&bp->b_dep))) { + if ((ioflag & (IO_VMIO | IO_DIRECT)) != 0 && + LIST_EMPTY(&bp->b_dep)) { bp->b_flags |= B_RELBUF; + if ((ioflag & IO_NOREUSE) != 0) + bp->b_flags |= B_NOREUSE; } /* Index: sys/vm/vm_pageout.c =================================================================== --- sys/vm/vm_pageout.c +++ sys/vm/vm_pageout.c @@ -483,8 +483,8 @@ if (ib != 0 && pageout_count < vm_pageout_page_count) goto more; - return (vm_pageout_flush(&mc[page_base], pageout_count, 0, 0, NULL, - NULL)); + return (vm_pageout_flush(&mc[page_base], pageout_count, + VM_PAGER_PUT_NOREUSE, 0, NULL, NULL)); } /* Index: sys/vm/vm_pager.h =================================================================== --- sys/vm/vm_pager.h +++ sys/vm/vm_pager.h @@ -95,6 +95,7 @@ #define VM_PAGER_PUT_SYNC 0x0001 #define VM_PAGER_PUT_INVAL 0x0002 +#define VM_PAGER_PUT_NOREUSE 0x0004 #define VM_PAGER_CLUSTER_OK 0x0008 #ifdef _KERNEL Index: sys/vm/vnode_pager.c =================================================================== --- sys/vm/vnode_pager.c +++ sys/vm/vnode_pager.c @@ -1281,6 +1281,7 @@ else if ((flags & VM_PAGER_CLUSTER_OK) == 0) ioflags |= IO_ASYNC; ioflags |= (flags & VM_PAGER_PUT_INVAL) ? IO_INVAL: 0; + ioflags |= (flags & VM_PAGER_PUT_NOREUSE) ? IO_NOREUSE : 0; ioflags |= IO_SEQMAX << IO_SEQSHIFT; aiov.iov_base = (caddr_t) 0;