1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1990 University of Utah. 326f9a767SRodney W. Grimes * Copyright (c) 1991 The Regents of the University of California. 426f9a767SRodney W. Grimes * All rights reserved. 526f9a767SRodney W. Grimes * Copyright (c) 1993,1994 John S. Dyson 6df8bae1dSRodney W. Grimes * 7df8bae1dSRodney W. Grimes * This code is derived from software contributed to Berkeley by 8df8bae1dSRodney W. Grimes * the Systems Programming Group of the University of Utah Computer 9df8bae1dSRodney W. Grimes * Science Department. 10df8bae1dSRodney W. Grimes * 11df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 12df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 13df8bae1dSRodney W. Grimes * are met: 14df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 15df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 16df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 17df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 18df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 19df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 20df8bae1dSRodney W. Grimes * must display the following acknowledgement: 21df8bae1dSRodney W. Grimes * This product includes software developed by the University of 22df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 23df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 24df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 25df8bae1dSRodney W. Grimes * without specific prior written permission. 26df8bae1dSRodney W. Grimes * 27df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37df8bae1dSRodney W. Grimes * SUCH DAMAGE. 38df8bae1dSRodney W. Grimes * 3926f9a767SRodney W. Grimes * from: @(#)vnode_pager.c 7.5 (Berkeley) 4/20/91 40a83c285cSDavid Greenman * $Id: vnode_pager.c,v 1.14 1994/10/15 13:33:09 davidg Exp $ 41df8bae1dSRodney W. Grimes */ 42df8bae1dSRodney W. Grimes 43df8bae1dSRodney W. Grimes /* 44df8bae1dSRodney W. Grimes * Page to/from files (vnodes). 45df8bae1dSRodney W. Grimes * 46df8bae1dSRodney W. Grimes * TODO: 47df8bae1dSRodney W. Grimes * pageouts 48df8bae1dSRodney W. Grimes * fix credential use (uses current process credentials now) 49df8bae1dSRodney W. Grimes */ 50df8bae1dSRodney W. Grimes 5126f9a767SRodney W. Grimes /* 5226f9a767SRodney W. Grimes * MODIFICATIONS: 5326f9a767SRodney W. Grimes * John S. Dyson 08 Dec 93 5426f9a767SRodney W. Grimes * 5526f9a767SRodney W. Grimes * This file in conjunction with some vm_fault mods, eliminate the performance 5626f9a767SRodney W. Grimes * advantage for using the buffer cache and minimize memory copies. 5726f9a767SRodney W. Grimes * 5826f9a767SRodney W. Grimes * 1) Supports multiple - block reads 5926f9a767SRodney W. Grimes * 2) Bypasses buffer cache for reads 6026f9a767SRodney W. Grimes * 6126f9a767SRodney W. Grimes * TODO: 6226f9a767SRodney W. Grimes * 6326f9a767SRodney W. Grimes * 1) Totally bypass buffer cache for reads 6426f9a767SRodney W. Grimes * (Currently will still sometimes use buffer cache for reads) 6526f9a767SRodney W. Grimes * 2) Bypass buffer cache for writes 6626f9a767SRodney W. Grimes * (Code does not support it, but mods are simple) 6726f9a767SRodney W. Grimes */ 6826f9a767SRodney W. Grimes 69df8bae1dSRodney W. Grimes #include <sys/param.h> 70df8bae1dSRodney W. Grimes #include <sys/systm.h> 71df8bae1dSRodney W. Grimes #include <sys/proc.h> 72df8bae1dSRodney W. Grimes #include <sys/malloc.h> 73df8bae1dSRodney W. Grimes #include <sys/vnode.h> 74df8bae1dSRodney W. Grimes #include <sys/uio.h> 75df8bae1dSRodney W. Grimes #include <sys/mount.h> 76df8bae1dSRodney W. Grimes 77df8bae1dSRodney W. Grimes #include <vm/vm.h> 78df8bae1dSRodney W. Grimes #include <vm/vm_page.h> 79df8bae1dSRodney W. Grimes #include <vm/vnode_pager.h> 80df8bae1dSRodney W. Grimes 8126f9a767SRodney W. Grimes #include <sys/buf.h> 8226f9a767SRodney W. Grimes #include <miscfs/specfs/specdev.h> 83df8bae1dSRodney W. Grimes 8426f9a767SRodney W. Grimes int vnode_pager_putmulti(); 85df8bae1dSRodney W. Grimes 8626f9a767SRodney W. Grimes void vnode_pager_init(); 8726f9a767SRodney W. Grimes vm_pager_t vnode_pager_alloc(caddr_t, vm_offset_t, vm_prot_t, vm_offset_t); 8826f9a767SRodney W. Grimes void vnode_pager_dealloc(); 8926f9a767SRodney W. Grimes int vnode_pager_getpage(); 9026f9a767SRodney W. Grimes int vnode_pager_getmulti(); 9126f9a767SRodney W. Grimes int vnode_pager_putpage(); 9226f9a767SRodney W. Grimes boolean_t vnode_pager_haspage(); 93df8bae1dSRodney W. Grimes 94df8bae1dSRodney W. Grimes struct pagerops vnodepagerops = { 95df8bae1dSRodney W. Grimes vnode_pager_init, 96df8bae1dSRodney W. Grimes vnode_pager_alloc, 97df8bae1dSRodney W. Grimes vnode_pager_dealloc, 98df8bae1dSRodney W. Grimes vnode_pager_getpage, 9926f9a767SRodney W. Grimes vnode_pager_getmulti, 100df8bae1dSRodney W. Grimes vnode_pager_putpage, 10126f9a767SRodney W. Grimes vnode_pager_putmulti, 10226f9a767SRodney W. Grimes vnode_pager_haspage 103df8bae1dSRodney W. Grimes }; 104df8bae1dSRodney W. Grimes 10516f62314SDavid Greenman 10616f62314SDavid Greenman 10726f9a767SRodney W. Grimes static int vnode_pager_input(vn_pager_t vnp, vm_page_t * m, int count, int reqpage); 10826f9a767SRodney W. Grimes static int vnode_pager_output(vn_pager_t vnp, vm_page_t * m, int count, int *rtvals); 10926f9a767SRodney W. Grimes 11026f9a767SRodney W. Grimes extern vm_map_t pager_map; 11126f9a767SRodney W. Grimes 11226f9a767SRodney W. Grimes struct pagerlst vnode_pager_list; /* list of managed vnodes */ 11326f9a767SRodney W. Grimes 11426f9a767SRodney W. Grimes #define MAXBP (PAGE_SIZE/DEV_BSIZE); 11526f9a767SRodney W. Grimes 11626f9a767SRodney W. Grimes void 117df8bae1dSRodney W. Grimes vnode_pager_init() 118df8bae1dSRodney W. Grimes { 119df8bae1dSRodney W. Grimes TAILQ_INIT(&vnode_pager_list); 120df8bae1dSRodney W. Grimes } 121df8bae1dSRodney W. Grimes 122df8bae1dSRodney W. Grimes /* 123df8bae1dSRodney W. Grimes * Allocate (or lookup) pager for a vnode. 124df8bae1dSRodney W. Grimes * Handle is a vnode pointer. 125df8bae1dSRodney W. Grimes */ 12626f9a767SRodney W. Grimes vm_pager_t 12726f9a767SRodney W. Grimes vnode_pager_alloc(handle, size, prot, offset) 128df8bae1dSRodney W. Grimes caddr_t handle; 129df8bae1dSRodney W. Grimes vm_size_t size; 130df8bae1dSRodney W. Grimes vm_prot_t prot; 13126f9a767SRodney W. Grimes vm_offset_t offset; 132df8bae1dSRodney W. Grimes { 133df8bae1dSRodney W. Grimes register vm_pager_t pager; 134df8bae1dSRodney W. Grimes register vn_pager_t vnp; 135df8bae1dSRodney W. Grimes vm_object_t object; 136df8bae1dSRodney W. Grimes struct vattr vattr; 137df8bae1dSRodney W. Grimes struct vnode *vp; 138df8bae1dSRodney W. Grimes struct proc *p = curproc; /* XXX */ 139df8bae1dSRodney W. Grimes 140df8bae1dSRodney W. Grimes /* 141df8bae1dSRodney W. Grimes * Pageout to vnode, no can do yet. 142df8bae1dSRodney W. Grimes */ 143df8bae1dSRodney W. Grimes if (handle == NULL) 144df8bae1dSRodney W. Grimes return (NULL); 145df8bae1dSRodney W. Grimes 146df8bae1dSRodney W. Grimes /* 147bbc0ec52SDavid Greenman * Vnodes keep a pointer to any associated pager so no need to lookup 148bbc0ec52SDavid Greenman * with vm_pager_lookup. 149df8bae1dSRodney W. Grimes */ 150df8bae1dSRodney W. Grimes vp = (struct vnode *) handle; 1518e58bf68SDavid Greenman object = (vm_object_t) vp->v_vmdata; 1528e58bf68SDavid Greenman pager = NULL; 1538e58bf68SDavid Greenman if( object != NULL) 1548e58bf68SDavid Greenman pager = object->pager; 155df8bae1dSRodney W. Grimes if (pager == NULL) { 156bbc0ec52SDavid Greenman 157df8bae1dSRodney W. Grimes /* 158df8bae1dSRodney W. Grimes * Allocate pager structures 159df8bae1dSRodney W. Grimes */ 160df8bae1dSRodney W. Grimes pager = (vm_pager_t) malloc(sizeof *pager, M_VMPAGER, M_WAITOK); 161df8bae1dSRodney W. Grimes if (pager == NULL) 162df8bae1dSRodney W. Grimes return (NULL); 163df8bae1dSRodney W. Grimes vnp = (vn_pager_t) malloc(sizeof *vnp, M_VMPGDATA, M_WAITOK); 164df8bae1dSRodney W. Grimes if (vnp == NULL) { 165df8bae1dSRodney W. Grimes free((caddr_t) pager, M_VMPAGER); 166df8bae1dSRodney W. Grimes return (NULL); 167df8bae1dSRodney W. Grimes } 168bbc0ec52SDavid Greenman 169df8bae1dSRodney W. Grimes /* 170df8bae1dSRodney W. Grimes * And an object of the appropriate size 171df8bae1dSRodney W. Grimes */ 172df8bae1dSRodney W. Grimes if (VOP_GETATTR(vp, &vattr, p->p_ucred, p) == 0) { 173df8bae1dSRodney W. Grimes object = vm_object_allocate(round_page(vattr.va_size)); 174df8bae1dSRodney W. Grimes vm_object_enter(object, pager); 175df8bae1dSRodney W. Grimes vm_object_setpager(object, pager, 0, TRUE); 176df8bae1dSRodney W. Grimes } else { 177df8bae1dSRodney W. Grimes free((caddr_t) vnp, M_VMPGDATA); 178df8bae1dSRodney W. Grimes free((caddr_t) pager, M_VMPAGER); 179df8bae1dSRodney W. Grimes return (NULL); 180df8bae1dSRodney W. Grimes } 181bbc0ec52SDavid Greenman 182df8bae1dSRodney W. Grimes /* 183df8bae1dSRodney W. Grimes * Hold a reference to the vnode and initialize pager data. 184df8bae1dSRodney W. Grimes */ 185df8bae1dSRodney W. Grimes VREF(vp); 186df8bae1dSRodney W. Grimes vnp->vnp_flags = 0; 187df8bae1dSRodney W. Grimes vnp->vnp_vp = vp; 188df8bae1dSRodney W. Grimes vnp->vnp_size = vattr.va_size; 18926f9a767SRodney W. Grimes 190df8bae1dSRodney W. Grimes TAILQ_INSERT_TAIL(&vnode_pager_list, pager, pg_list); 191df8bae1dSRodney W. Grimes pager->pg_handle = handle; 192df8bae1dSRodney W. Grimes pager->pg_type = PG_VNODE; 193df8bae1dSRodney W. Grimes pager->pg_ops = &vnodepagerops; 19426f9a767SRodney W. Grimes pager->pg_data = (caddr_t) vnp; 1958e58bf68SDavid Greenman vp->v_vmdata = (caddr_t) object; 196df8bae1dSRodney W. Grimes } else { 197bbc0ec52SDavid Greenman 198df8bae1dSRodney W. Grimes /* 199bbc0ec52SDavid Greenman * vm_object_lookup() will remove the object from the cache if 200bbc0ec52SDavid Greenman * found and also gain a reference to the object. 201df8bae1dSRodney W. Grimes */ 2028e58bf68SDavid Greenman (void) vm_object_lookup(pager); 203df8bae1dSRodney W. Grimes } 204df8bae1dSRodney W. Grimes return (pager); 205df8bae1dSRodney W. Grimes } 206df8bae1dSRodney W. Grimes 20726f9a767SRodney W. Grimes void 208df8bae1dSRodney W. Grimes vnode_pager_dealloc(pager) 209df8bae1dSRodney W. Grimes vm_pager_t pager; 210df8bae1dSRodney W. Grimes { 211df8bae1dSRodney W. Grimes register vn_pager_t vnp = (vn_pager_t) pager->pg_data; 212df8bae1dSRodney W. Grimes register struct vnode *vp; 213df8bae1dSRodney W. Grimes 21405f0fdd2SPoul-Henning Kamp vp = vnp->vnp_vp; 21505f0fdd2SPoul-Henning Kamp if (vp) { 216df8bae1dSRodney W. Grimes vp->v_vmdata = NULL; 2178e58bf68SDavid Greenman vp->v_flag &= ~(VTEXT|VVMIO); 218df8bae1dSRodney W. Grimes vrele(vp); 219df8bae1dSRodney W. Grimes } 220df8bae1dSRodney W. Grimes TAILQ_REMOVE(&vnode_pager_list, pager, pg_list); 221df8bae1dSRodney W. Grimes free((caddr_t) vnp, M_VMPGDATA); 222df8bae1dSRodney W. Grimes free((caddr_t) pager, M_VMPAGER); 223df8bae1dSRodney W. Grimes } 224df8bae1dSRodney W. Grimes 22526f9a767SRodney W. Grimes int 22626f9a767SRodney W. Grimes vnode_pager_getmulti(pager, m, count, reqpage, sync) 227df8bae1dSRodney W. Grimes vm_pager_t pager; 22826f9a767SRodney W. Grimes vm_page_t *m; 22926f9a767SRodney W. Grimes int count; 23026f9a767SRodney W. Grimes int reqpage; 231df8bae1dSRodney W. Grimes boolean_t sync; 232df8bae1dSRodney W. Grimes { 233df8bae1dSRodney W. Grimes 23426f9a767SRodney W. Grimes return vnode_pager_input((vn_pager_t) pager->pg_data, m, count, reqpage); 235df8bae1dSRodney W. Grimes } 236df8bae1dSRodney W. Grimes 23726f9a767SRodney W. Grimes int 23826f9a767SRodney W. Grimes vnode_pager_getpage(pager, m, sync) 239df8bae1dSRodney W. Grimes vm_pager_t pager; 24026f9a767SRodney W. Grimes vm_page_t m; 24126f9a767SRodney W. Grimes boolean_t sync; 24226f9a767SRodney W. Grimes { 24326f9a767SRodney W. Grimes 24426f9a767SRodney W. Grimes vm_page_t marray[1]; 245bbc0ec52SDavid Greenman 24626f9a767SRodney W. Grimes if (pager == NULL) 24726f9a767SRodney W. Grimes return FALSE; 24826f9a767SRodney W. Grimes marray[0] = m; 24926f9a767SRodney W. Grimes 25026f9a767SRodney W. Grimes return vnode_pager_input((vn_pager_t) pager->pg_data, marray, 1, 0); 25126f9a767SRodney W. Grimes } 25226f9a767SRodney W. Grimes 25326f9a767SRodney W. Grimes boolean_t 25426f9a767SRodney W. Grimes vnode_pager_putpage(pager, m, sync) 25526f9a767SRodney W. Grimes vm_pager_t pager; 25626f9a767SRodney W. Grimes vm_page_t m; 257df8bae1dSRodney W. Grimes boolean_t sync; 258df8bae1dSRodney W. Grimes { 25926f9a767SRodney W. Grimes vm_page_t marray[1]; 26026f9a767SRodney W. Grimes int rtvals[1]; 261df8bae1dSRodney W. Grimes 262df8bae1dSRodney W. Grimes if (pager == NULL) 26326f9a767SRodney W. Grimes return FALSE; 26426f9a767SRodney W. Grimes marray[0] = m; 26526f9a767SRodney W. Grimes vnode_pager_output((vn_pager_t) pager->pg_data, marray, 1, rtvals); 26626f9a767SRodney W. Grimes return rtvals[0]; 267df8bae1dSRodney W. Grimes } 268df8bae1dSRodney W. Grimes 26926f9a767SRodney W. Grimes int 27026f9a767SRodney W. Grimes vnode_pager_putmulti(pager, m, c, sync, rtvals) 27126f9a767SRodney W. Grimes vm_pager_t pager; 27226f9a767SRodney W. Grimes vm_page_t *m; 27326f9a767SRodney W. Grimes int c; 27426f9a767SRodney W. Grimes boolean_t sync; 27526f9a767SRodney W. Grimes int *rtvals; 27626f9a767SRodney W. Grimes { 27726f9a767SRodney W. Grimes return vnode_pager_output((vn_pager_t) pager->pg_data, m, c, rtvals); 27826f9a767SRodney W. Grimes } 27926f9a767SRodney W. Grimes 28026f9a767SRodney W. Grimes 28126f9a767SRodney W. Grimes boolean_t 282df8bae1dSRodney W. Grimes vnode_pager_haspage(pager, offset) 283df8bae1dSRodney W. Grimes vm_pager_t pager; 284df8bae1dSRodney W. Grimes vm_offset_t offset; 285df8bae1dSRodney W. Grimes { 286df8bae1dSRodney W. Grimes register vn_pager_t vnp = (vn_pager_t) pager->pg_data; 287df8bae1dSRodney W. Grimes daddr_t bn; 288df8bae1dSRodney W. Grimes int err; 289df8bae1dSRodney W. Grimes 290df8bae1dSRodney W. Grimes /* 291df8bae1dSRodney W. Grimes * Offset beyond end of file, do not have the page 292df8bae1dSRodney W. Grimes */ 293df8bae1dSRodney W. Grimes if (offset >= vnp->vnp_size) { 294df8bae1dSRodney W. Grimes return (FALSE); 295df8bae1dSRodney W. Grimes } 296df8bae1dSRodney W. Grimes 297df8bae1dSRodney W. Grimes /* 298bbc0ec52SDavid Greenman * Read the index to find the disk block to read from. If there is no 299bbc0ec52SDavid Greenman * block, report that we don't have this data. 300df8bae1dSRodney W. Grimes * 301df8bae1dSRodney W. Grimes * Assumes that the vnode has whole page or nothing. 302df8bae1dSRodney W. Grimes */ 303df8bae1dSRodney W. Grimes err = VOP_BMAP(vnp->vnp_vp, 304df8bae1dSRodney W. Grimes offset / vnp->vnp_vp->v_mount->mnt_stat.f_iosize, 30526f9a767SRodney W. Grimes (struct vnode **) 0, &bn, 0); 3068e58bf68SDavid Greenman /* 3078e58bf68SDavid Greenman printf("vnode_pager_haspage: (%d)0x%x: err: %d, bn: %d\n", 3088e58bf68SDavid Greenman offset, offset, err, bn); 3098e58bf68SDavid Greenman */ 310df8bae1dSRodney W. Grimes if (err) { 311df8bae1dSRodney W. Grimes return (TRUE); 312df8bae1dSRodney W. Grimes } 313df8bae1dSRodney W. Grimes return ((long) bn < 0 ? FALSE : TRUE); 314df8bae1dSRodney W. Grimes } 315df8bae1dSRodney W. Grimes 316df8bae1dSRodney W. Grimes /* 317df8bae1dSRodney W. Grimes * Lets the VM system know about a change in size for a file. 318df8bae1dSRodney W. Grimes * If this vnode is mapped into some address space (i.e. we have a pager 319df8bae1dSRodney W. Grimes * for it) we adjust our own internal size and flush any cached pages in 320df8bae1dSRodney W. Grimes * the associated object that are affected by the size change. 321df8bae1dSRodney W. Grimes * 322df8bae1dSRodney W. Grimes * Note: this routine may be invoked as a result of a pager put 323df8bae1dSRodney W. Grimes * operation (possibly at object termination time), so we must be careful. 324df8bae1dSRodney W. Grimes */ 325df8bae1dSRodney W. Grimes void 326df8bae1dSRodney W. Grimes vnode_pager_setsize(vp, nsize) 327df8bae1dSRodney W. Grimes struct vnode *vp; 328df8bae1dSRodney W. Grimes u_long nsize; 329df8bae1dSRodney W. Grimes { 330df8bae1dSRodney W. Grimes register vn_pager_t vnp; 331df8bae1dSRodney W. Grimes register vm_object_t object; 332df8bae1dSRodney W. Grimes vm_pager_t pager; 333df8bae1dSRodney W. Grimes 334df8bae1dSRodney W. Grimes /* 335df8bae1dSRodney W. Grimes * Not a mapped vnode 336df8bae1dSRodney W. Grimes */ 337df8bae1dSRodney W. Grimes if (vp == NULL || vp->v_type != VREG || vp->v_vmdata == NULL) 338df8bae1dSRodney W. Grimes return; 339bbc0ec52SDavid Greenman 340df8bae1dSRodney W. Grimes /* 341df8bae1dSRodney W. Grimes * Hasn't changed size 342df8bae1dSRodney W. Grimes */ 3438e58bf68SDavid Greenman object = (vm_object_t) vp->v_vmdata; 3448e58bf68SDavid Greenman if( object == NULL) 3458e58bf68SDavid Greenman return; 3468e58bf68SDavid Greenman if( (pager = object->pager) == NULL) 3478e58bf68SDavid Greenman return; 348df8bae1dSRodney W. Grimes vnp = (vn_pager_t) pager->pg_data; 349df8bae1dSRodney W. Grimes if (nsize == vnp->vnp_size) 350df8bae1dSRodney W. Grimes return; 351bbc0ec52SDavid Greenman 352df8bae1dSRodney W. Grimes /* 353bbc0ec52SDavid Greenman * No object. This can happen during object termination since 354bbc0ec52SDavid Greenman * vm_object_page_clean is called after the object has been removed 355bbc0ec52SDavid Greenman * from the hash table, and clean may cause vnode write operations 356bbc0ec52SDavid Greenman * which can wind up back here. 357df8bae1dSRodney W. Grimes */ 358df8bae1dSRodney W. Grimes object = vm_object_lookup(pager); 359df8bae1dSRodney W. Grimes if (object == NULL) 360df8bae1dSRodney W. Grimes return; 361df8bae1dSRodney W. Grimes 362df8bae1dSRodney W. Grimes /* 363bbc0ec52SDavid Greenman * File has shrunk. Toss any cached pages beyond the new EOF. 364df8bae1dSRodney W. Grimes */ 365bbc0ec52SDavid Greenman if (nsize < vnp->vnp_size) { 366df8bae1dSRodney W. Grimes vm_object_lock(object); 367df8bae1dSRodney W. Grimes vm_object_page_remove(object, 368bbc0ec52SDavid Greenman round_page((vm_offset_t) nsize), vnp->vnp_size); 369bbc0ec52SDavid Greenman vm_object_unlock(object); 370bbc0ec52SDavid Greenman 371bbc0ec52SDavid Greenman /* 372bbc0ec52SDavid Greenman * this gets rid of garbage at the end of a page that is now 373bbc0ec52SDavid Greenman * only partially backed by the vnode... 374bbc0ec52SDavid Greenman */ 375bbc0ec52SDavid Greenman if (nsize & PAGE_MASK) { 376bbc0ec52SDavid Greenman vm_offset_t kva; 377bbc0ec52SDavid Greenman vm_page_t m; 378bbc0ec52SDavid Greenman 379bbc0ec52SDavid Greenman m = vm_page_lookup(object, trunc_page((vm_offset_t) nsize)); 380bbc0ec52SDavid Greenman if (m) { 381bbc0ec52SDavid Greenman kva = vm_pager_map_page(m); 382bbc0ec52SDavid Greenman bzero((caddr_t) kva + (nsize & PAGE_MASK), 383bbc0ec52SDavid Greenman round_page(nsize) - nsize); 384bbc0ec52SDavid Greenman vm_pager_unmap_page(kva); 385bbc0ec52SDavid Greenman } 386bbc0ec52SDavid Greenman } 387bbc0ec52SDavid Greenman } else { 388bbc0ec52SDavid Greenman 389bbc0ec52SDavid Greenman /* 390bbc0ec52SDavid Greenman * this allows the filesystem and VM cache to stay in sync if 391bbc0ec52SDavid Greenman * the VM page hasn't been modified... After the page is 392bbc0ec52SDavid Greenman * removed -- it will be faulted back in from the filesystem 393bbc0ec52SDavid Greenman * cache. 394bbc0ec52SDavid Greenman */ 395bbc0ec52SDavid Greenman if (vnp->vnp_size & PAGE_MASK) { 396bbc0ec52SDavid Greenman vm_page_t m; 397bbc0ec52SDavid Greenman 398bbc0ec52SDavid Greenman m = vm_page_lookup(object, trunc_page(vnp->vnp_size)); 399bbc0ec52SDavid Greenman if (m && (m->flags & PG_CLEAN)) { 400bbc0ec52SDavid Greenman vm_object_lock(object); 401bbc0ec52SDavid Greenman vm_object_page_remove(object, 402bbc0ec52SDavid Greenman vnp->vnp_size, vnp->vnp_size); 403df8bae1dSRodney W. Grimes vm_object_unlock(object); 404df8bae1dSRodney W. Grimes } 405bbc0ec52SDavid Greenman } 406bbc0ec52SDavid Greenman } 407df8bae1dSRodney W. Grimes vnp->vnp_size = (vm_offset_t) nsize; 408bbc0ec52SDavid Greenman object->size = round_page(nsize); 409bbc0ec52SDavid Greenman 410df8bae1dSRodney W. Grimes vm_object_deallocate(object); 411df8bae1dSRodney W. Grimes } 412df8bae1dSRodney W. Grimes 413df8bae1dSRodney W. Grimes void 414df8bae1dSRodney W. Grimes vnode_pager_umount(mp) 415df8bae1dSRodney W. Grimes register struct mount *mp; 416df8bae1dSRodney W. Grimes { 417df8bae1dSRodney W. Grimes register vm_pager_t pager, npager; 418df8bae1dSRodney W. Grimes struct vnode *vp; 419df8bae1dSRodney W. Grimes 42026f9a767SRodney W. Grimes pager = vnode_pager_list.tqh_first; 42126f9a767SRodney W. Grimes while (pager) { 422bbc0ec52SDavid Greenman 423df8bae1dSRodney W. Grimes /* 424bbc0ec52SDavid Greenman * Save the next pointer now since uncaching may terminate the 425bbc0ec52SDavid Greenman * object and render pager invalid 426df8bae1dSRodney W. Grimes */ 427df8bae1dSRodney W. Grimes vp = ((vn_pager_t) pager->pg_data)->vnp_vp; 42826f9a767SRodney W. Grimes npager = pager->pg_list.tqe_next; 42926f9a767SRodney W. Grimes if (mp == (struct mount *) 0 || vp->v_mount == mp) 430df8bae1dSRodney W. Grimes (void) vnode_pager_uncache(vp); 43126f9a767SRodney W. Grimes pager = npager; 432df8bae1dSRodney W. Grimes } 433df8bae1dSRodney W. Grimes } 434df8bae1dSRodney W. Grimes 435df8bae1dSRodney W. Grimes /* 436df8bae1dSRodney W. Grimes * Remove vnode associated object from the object cache. 437df8bae1dSRodney W. Grimes * 43826f9a767SRodney W. Grimes * Note: this routine may be invoked as a result of a pager put 43926f9a767SRodney W. Grimes * operation (possibly at object termination time), so we must be careful. 44026f9a767SRodney W. Grimes */ 44126f9a767SRodney W. Grimes boolean_t 44226f9a767SRodney W. Grimes vnode_pager_uncache(vp) 44326f9a767SRodney W. Grimes register struct vnode *vp; 44426f9a767SRodney W. Grimes { 44526f9a767SRodney W. Grimes register vm_object_t object; 44626f9a767SRodney W. Grimes boolean_t uncached, locked; 44726f9a767SRodney W. Grimes vm_pager_t pager; 44826f9a767SRodney W. Grimes 44926f9a767SRodney W. Grimes /* 45026f9a767SRodney W. Grimes * Not a mapped vnode 45126f9a767SRodney W. Grimes */ 4528e58bf68SDavid Greenman object = (vm_object_t) vp->v_vmdata; 4538e58bf68SDavid Greenman if( object == NULL) 4548e58bf68SDavid Greenman return(TRUE); 4558e58bf68SDavid Greenman pager = object->pager; 45626f9a767SRodney W. Grimes if (pager == NULL) 45726f9a767SRodney W. Grimes return (TRUE); 458bbc0ec52SDavid Greenman 45926f9a767SRodney W. Grimes /* 460bbc0ec52SDavid Greenman * Unlock the vnode if it is currently locked. We do this since 461bbc0ec52SDavid Greenman * uncaching the object may result in its destruction which may 462bbc0ec52SDavid Greenman * initiate paging activity which may necessitate locking the vnode. 46326f9a767SRodney W. Grimes */ 46426f9a767SRodney W. Grimes locked = VOP_ISLOCKED(vp); 46526f9a767SRodney W. Grimes if (locked) 46626f9a767SRodney W. Grimes VOP_UNLOCK(vp); 467bbc0ec52SDavid Greenman 46826f9a767SRodney W. Grimes /* 469bbc0ec52SDavid Greenman * Must use vm_object_lookup() as it actually removes the object from 470bbc0ec52SDavid Greenman * the cache list. 47126f9a767SRodney W. Grimes */ 47226f9a767SRodney W. Grimes object = vm_object_lookup(pager); 47326f9a767SRodney W. Grimes if (object) { 47426f9a767SRodney W. Grimes uncached = (object->ref_count <= 1); 47526f9a767SRodney W. Grimes pager_cache(object, FALSE); 47626f9a767SRodney W. Grimes } else 47726f9a767SRodney W. Grimes uncached = TRUE; 47826f9a767SRodney W. Grimes if (locked) 47926f9a767SRodney W. Grimes VOP_LOCK(vp); 48026f9a767SRodney W. Grimes return (uncached); 48126f9a767SRodney W. Grimes } 482df8bae1dSRodney W. Grimes 48326f9a767SRodney W. Grimes 48426f9a767SRodney W. Grimes void 48526f9a767SRodney W. Grimes vnode_pager_freepage(m) 48626f9a767SRodney W. Grimes vm_page_t m; 487df8bae1dSRodney W. Grimes { 48826f9a767SRodney W. Grimes PAGE_WAKEUP(m); 48926f9a767SRodney W. Grimes vm_page_free(m); 49026f9a767SRodney W. Grimes } 49126f9a767SRodney W. Grimes 49226f9a767SRodney W. Grimes /* 49326f9a767SRodney W. Grimes * calculate the linear (byte) disk address of specified virtual 49426f9a767SRodney W. Grimes * file address 49526f9a767SRodney W. Grimes */ 49626f9a767SRodney W. Grimes vm_offset_t 49726f9a767SRodney W. Grimes vnode_pager_addr(vp, address) 49826f9a767SRodney W. Grimes struct vnode *vp; 49926f9a767SRodney W. Grimes vm_offset_t address; 50026f9a767SRodney W. Grimes { 50126f9a767SRodney W. Grimes int rtaddress; 50226f9a767SRodney W. Grimes int bsize; 50326f9a767SRodney W. Grimes vm_offset_t block; 50426f9a767SRodney W. Grimes struct vnode *rtvp; 50526f9a767SRodney W. Grimes int err; 50626f9a767SRodney W. Grimes int vblock, voffset; 50726f9a767SRodney W. Grimes 50826f9a767SRodney W. Grimes bsize = vp->v_mount->mnt_stat.f_iosize; 50926f9a767SRodney W. Grimes vblock = address / bsize; 51026f9a767SRodney W. Grimes voffset = address % bsize; 51126f9a767SRodney W. Grimes 51226f9a767SRodney W. Grimes err = VOP_BMAP(vp, vblock, &rtvp, &block, 0); 51326f9a767SRodney W. Grimes 51426f9a767SRodney W. Grimes if (err) 51526f9a767SRodney W. Grimes rtaddress = -1; 51626f9a767SRodney W. Grimes else 51726f9a767SRodney W. Grimes rtaddress = block * DEV_BSIZE + voffset; 51826f9a767SRodney W. Grimes 51926f9a767SRodney W. Grimes return rtaddress; 52026f9a767SRodney W. Grimes } 52126f9a767SRodney W. Grimes 52226f9a767SRodney W. Grimes /* 52326f9a767SRodney W. Grimes * interrupt routine for I/O completion 52426f9a767SRodney W. Grimes */ 52526f9a767SRodney W. Grimes void 52626f9a767SRodney W. Grimes vnode_pager_iodone(bp) 52726f9a767SRodney W. Grimes struct buf *bp; 52826f9a767SRodney W. Grimes { 52926f9a767SRodney W. Grimes bp->b_flags |= B_DONE; 53026f9a767SRodney W. Grimes wakeup((caddr_t) bp); 53116f62314SDavid Greenman if( bp->b_flags & B_ASYNC) { 53216f62314SDavid Greenman vm_offset_t paddr; 53316f62314SDavid Greenman vm_page_t m; 53416f62314SDavid Greenman vm_object_t obj = 0; 53516f62314SDavid Greenman int i; 53616f62314SDavid Greenman int npages; 53716f62314SDavid Greenman 53816f62314SDavid Greenman paddr = (vm_offset_t) bp->b_data; 53916f62314SDavid Greenman if( bp->b_bufsize != bp->b_bcount) 54016f62314SDavid Greenman bzero( bp->b_data + bp->b_bcount, 54116f62314SDavid Greenman bp->b_bufsize - bp->b_bcount); 54216f62314SDavid Greenman 54316f62314SDavid Greenman npages = (bp->b_bufsize + PAGE_SIZE - 1) / PAGE_SIZE; 544a481f200SDavid Greenman /* 545a481f200SDavid Greenman printf("bcount: %d, bufsize: %d, npages: %d\n", 546a481f200SDavid Greenman bp->b_bcount, bp->b_bufsize, npages); 547a481f200SDavid Greenman */ 54816f62314SDavid Greenman for( i = 0; i < npages; i++) { 54916f62314SDavid Greenman m = PHYS_TO_VM_PAGE(pmap_kextract(paddr + i * PAGE_SIZE)); 55016f62314SDavid Greenman obj = m->object; 55116f62314SDavid Greenman if( m) { 55216f62314SDavid Greenman m->flags |= PG_CLEAN; 55316f62314SDavid Greenman m->flags &= ~(PG_LAUNDRY|PG_FAKE); 55416f62314SDavid Greenman PAGE_WAKEUP(m); 55516f62314SDavid Greenman } else { 55616f62314SDavid Greenman panic("vnode_pager_iodone: page is gone!!!"); 55716f62314SDavid Greenman } 55816f62314SDavid Greenman } 559a481f200SDavid Greenman pmap_qremove( paddr, npages); 56016f62314SDavid Greenman if( obj) { 56116f62314SDavid Greenman --obj->paging_in_progress; 56216f62314SDavid Greenman if( obj->paging_in_progress == 0) 56316f62314SDavid Greenman wakeup((caddr_t) obj); 56416f62314SDavid Greenman } else { 56516f62314SDavid Greenman panic("vnode_pager_iodone: object is gone???"); 56616f62314SDavid Greenman } 56716f62314SDavid Greenman HOLDRELE(bp->b_vp); 56816f62314SDavid Greenman relpbuf(bp); 56916f62314SDavid Greenman } 57026f9a767SRodney W. Grimes } 57126f9a767SRodney W. Grimes 57226f9a767SRodney W. Grimes /* 57326f9a767SRodney W. Grimes * small block file system vnode pager input 57426f9a767SRodney W. Grimes */ 57526f9a767SRodney W. Grimes int 57626f9a767SRodney W. Grimes vnode_pager_input_smlfs(vnp, m) 57726f9a767SRodney W. Grimes vn_pager_t vnp; 57826f9a767SRodney W. Grimes vm_page_t m; 57926f9a767SRodney W. Grimes { 58026f9a767SRodney W. Grimes int i; 58126f9a767SRodney W. Grimes int s; 58226f9a767SRodney W. Grimes vm_offset_t paging_offset; 58326f9a767SRodney W. Grimes struct vnode *dp, *vp; 58426f9a767SRodney W. Grimes struct buf *bp; 58526f9a767SRodney W. Grimes vm_offset_t foff; 58626f9a767SRodney W. Grimes vm_offset_t kva; 58726f9a767SRodney W. Grimes int fileaddr; 58826f9a767SRodney W. Grimes int block; 58926f9a767SRodney W. Grimes vm_offset_t bsize; 59026f9a767SRodney W. Grimes int error = 0; 59126f9a767SRodney W. Grimes 59226f9a767SRodney W. Grimes paging_offset = m->object->paging_offset; 59326f9a767SRodney W. Grimes vp = vnp->vnp_vp; 59426f9a767SRodney W. Grimes bsize = vp->v_mount->mnt_stat.f_iosize; 59526f9a767SRodney W. Grimes foff = m->offset + paging_offset; 59626f9a767SRodney W. Grimes 59726f9a767SRodney W. Grimes VOP_BMAP(vp, foff, &dp, 0, 0); 59826f9a767SRodney W. Grimes 59926f9a767SRodney W. Grimes kva = vm_pager_map_page(m); 60026f9a767SRodney W. Grimes 60126f9a767SRodney W. Grimes for (i = 0; i < PAGE_SIZE / bsize; i++) { 602bbc0ec52SDavid Greenman 60326f9a767SRodney W. Grimes /* 60426f9a767SRodney W. Grimes * calculate logical block and offset 60526f9a767SRodney W. Grimes */ 60626f9a767SRodney W. Grimes block = foff / bsize + i; 60726f9a767SRodney W. Grimes s = splbio(); 60805f0fdd2SPoul-Henning Kamp while ((bp = incore(vp, block)) != 0) { 60926f9a767SRodney W. Grimes int amount; 61026f9a767SRodney W. Grimes 61126f9a767SRodney W. Grimes /* 61226f9a767SRodney W. Grimes * wait until the buffer is avail or gone 61326f9a767SRodney W. Grimes */ 61426f9a767SRodney W. Grimes if (bp->b_flags & B_BUSY) { 61526f9a767SRodney W. Grimes bp->b_flags |= B_WANTED; 61626f9a767SRodney W. Grimes tsleep((caddr_t) bp, PVM, "vnwblk", 0); 61726f9a767SRodney W. Grimes continue; 61826f9a767SRodney W. Grimes } 61926f9a767SRodney W. Grimes amount = bsize; 62026f9a767SRodney W. Grimes if ((foff + bsize) > vnp->vnp_size) 62126f9a767SRodney W. Grimes amount = vnp->vnp_size - foff; 62226f9a767SRodney W. Grimes 62326f9a767SRodney W. Grimes /* 62426f9a767SRodney W. Grimes * make sure that this page is in the buffer 62526f9a767SRodney W. Grimes */ 62626f9a767SRodney W. Grimes if ((amount > 0) && amount <= bp->b_bcount) { 62726f9a767SRodney W. Grimes bp->b_flags |= B_BUSY; 62826f9a767SRodney W. Grimes splx(s); 62926f9a767SRodney W. Grimes 63026f9a767SRodney W. Grimes /* 63126f9a767SRodney W. Grimes * copy the data from the buffer 63226f9a767SRodney W. Grimes */ 63326f9a767SRodney W. Grimes bcopy(bp->b_un.b_addr, (caddr_t) kva + i * bsize, amount); 63426f9a767SRodney W. Grimes if (amount < bsize) { 63526f9a767SRodney W. Grimes bzero((caddr_t) kva + amount, bsize - amount); 63626f9a767SRodney W. Grimes } 63726f9a767SRodney W. Grimes bp->b_flags &= ~B_BUSY; 63826f9a767SRodney W. Grimes wakeup((caddr_t) bp); 63926f9a767SRodney W. Grimes goto nextblock; 64026f9a767SRodney W. Grimes } 64126f9a767SRodney W. Grimes break; 64226f9a767SRodney W. Grimes } 64326f9a767SRodney W. Grimes splx(s); 64426f9a767SRodney W. Grimes fileaddr = vnode_pager_addr(vp, foff + i * bsize); 64526f9a767SRodney W. Grimes if (fileaddr != -1) { 64626f9a767SRodney W. Grimes bp = getpbuf(); 64726f9a767SRodney W. Grimes VHOLD(vp); 64826f9a767SRodney W. Grimes 64926f9a767SRodney W. Grimes /* build a minimal buffer header */ 65026f9a767SRodney W. Grimes bp->b_flags = B_BUSY | B_READ | B_CALL; 65126f9a767SRodney W. Grimes bp->b_iodone = vnode_pager_iodone; 65226f9a767SRodney W. Grimes bp->b_proc = curproc; 65326f9a767SRodney W. Grimes bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred; 65426f9a767SRodney W. Grimes if (bp->b_rcred != NOCRED) 65526f9a767SRodney W. Grimes crhold(bp->b_rcred); 65626f9a767SRodney W. Grimes if (bp->b_wcred != NOCRED) 65726f9a767SRodney W. Grimes crhold(bp->b_wcred); 65826f9a767SRodney W. Grimes bp->b_un.b_addr = (caddr_t) kva + i * bsize; 65926f9a767SRodney W. Grimes bp->b_blkno = fileaddr / DEV_BSIZE; 66026f9a767SRodney W. Grimes bgetvp(dp, bp); 66126f9a767SRodney W. Grimes bp->b_bcount = bsize; 66226f9a767SRodney W. Grimes bp->b_bufsize = bsize; 66326f9a767SRodney W. Grimes 66426f9a767SRodney W. Grimes /* do the input */ 66526f9a767SRodney W. Grimes VOP_STRATEGY(bp); 66626f9a767SRodney W. Grimes 66726f9a767SRodney W. Grimes /* we definitely need to be at splbio here */ 66826f9a767SRodney W. Grimes 66926f9a767SRodney W. Grimes s = splbio(); 67026f9a767SRodney W. Grimes while ((bp->b_flags & B_DONE) == 0) { 67126f9a767SRodney W. Grimes tsleep((caddr_t) bp, PVM, "vnsrd", 0); 67226f9a767SRodney W. Grimes } 67326f9a767SRodney W. Grimes splx(s); 67426f9a767SRodney W. Grimes if ((bp->b_flags & B_ERROR) != 0) 67526f9a767SRodney W. Grimes error = EIO; 67626f9a767SRodney W. Grimes 67726f9a767SRodney W. Grimes /* 67826f9a767SRodney W. Grimes * free the buffer header back to the swap buffer pool 67926f9a767SRodney W. Grimes */ 68026f9a767SRodney W. Grimes relpbuf(bp); 68126f9a767SRodney W. Grimes HOLDRELE(vp); 68226f9a767SRodney W. Grimes if (error) 68326f9a767SRodney W. Grimes break; 68426f9a767SRodney W. Grimes } else { 68526f9a767SRodney W. Grimes bzero((caddr_t) kva + i * bsize, bsize); 68626f9a767SRodney W. Grimes } 68726f9a767SRodney W. Grimes nextblock: 68826f9a767SRodney W. Grimes } 68926f9a767SRodney W. Grimes vm_pager_unmap_page(kva); 69026f9a767SRodney W. Grimes if (error) { 691a83c285cSDavid Greenman return VM_PAGER_ERROR; 69226f9a767SRodney W. Grimes } 69326f9a767SRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(m)); 69426f9a767SRodney W. Grimes m->flags |= PG_CLEAN; 69526f9a767SRodney W. Grimes m->flags &= ~PG_LAUNDRY; 69626f9a767SRodney W. Grimes return VM_PAGER_OK; 69726f9a767SRodney W. Grimes 69826f9a767SRodney W. Grimes } 69926f9a767SRodney W. Grimes 70026f9a767SRodney W. Grimes 70126f9a767SRodney W. Grimes /* 70226f9a767SRodney W. Grimes * old style vnode pager output routine 70326f9a767SRodney W. Grimes */ 70426f9a767SRodney W. Grimes int 70526f9a767SRodney W. Grimes vnode_pager_input_old(vnp, m) 70626f9a767SRodney W. Grimes vn_pager_t vnp; 70726f9a767SRodney W. Grimes vm_page_t m; 70826f9a767SRodney W. Grimes { 709df8bae1dSRodney W. Grimes struct uio auio; 710df8bae1dSRodney W. Grimes struct iovec aiov; 71126f9a767SRodney W. Grimes int error; 71226f9a767SRodney W. Grimes int size; 71326f9a767SRodney W. Grimes vm_offset_t foff; 71426f9a767SRodney W. Grimes vm_offset_t kva; 715df8bae1dSRodney W. Grimes 71626f9a767SRodney W. Grimes error = 0; 717df8bae1dSRodney W. Grimes foff = m->offset + m->object->paging_offset; 718bbc0ec52SDavid Greenman 719df8bae1dSRodney W. Grimes /* 72026f9a767SRodney W. Grimes * Return failure if beyond current EOF 72126f9a767SRodney W. Grimes */ 72226f9a767SRodney W. Grimes if (foff >= vnp->vnp_size) { 72326f9a767SRodney W. Grimes return VM_PAGER_BAD; 72426f9a767SRodney W. Grimes } else { 72526f9a767SRodney W. Grimes size = PAGE_SIZE; 72626f9a767SRodney W. Grimes if (foff + size > vnp->vnp_size) 72726f9a767SRodney W. Grimes size = vnp->vnp_size - foff; 72826f9a767SRodney W. Grimes /* 729df8bae1dSRodney W. Grimes * Allocate a kernel virtual address and initialize so that 730df8bae1dSRodney W. Grimes * we can use VOP_READ/WRITE routines. 731df8bae1dSRodney W. Grimes */ 73226f9a767SRodney W. Grimes kva = vm_pager_map_page(m); 733df8bae1dSRodney W. Grimes aiov.iov_base = (caddr_t) kva; 734df8bae1dSRodney W. Grimes aiov.iov_len = size; 735df8bae1dSRodney W. Grimes auio.uio_iov = &aiov; 736df8bae1dSRodney W. Grimes auio.uio_iovcnt = 1; 737df8bae1dSRodney W. Grimes auio.uio_offset = foff; 738df8bae1dSRodney W. Grimes auio.uio_segflg = UIO_SYSSPACE; 73926f9a767SRodney W. Grimes auio.uio_rw = UIO_READ; 740df8bae1dSRodney W. Grimes auio.uio_resid = size; 741df8bae1dSRodney W. Grimes auio.uio_procp = (struct proc *) 0; 74226f9a767SRodney W. Grimes 74326f9a767SRodney W. Grimes error = VOP_READ(vnp->vnp_vp, &auio, 0, curproc->p_ucred); 744df8bae1dSRodney W. Grimes if (!error) { 745df8bae1dSRodney W. Grimes register int count = size - auio.uio_resid; 746df8bae1dSRodney W. Grimes 747df8bae1dSRodney W. Grimes if (count == 0) 748df8bae1dSRodney W. Grimes error = EINVAL; 74926f9a767SRodney W. Grimes else if (count != PAGE_SIZE) 75026f9a767SRodney W. Grimes bzero((caddr_t) kva + count, PAGE_SIZE - count); 751df8bae1dSRodney W. Grimes } 75226f9a767SRodney W. Grimes vm_pager_unmap_page(kva); 753df8bae1dSRodney W. Grimes } 75426f9a767SRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(m)); 75526f9a767SRodney W. Grimes m->flags |= PG_CLEAN; 75626f9a767SRodney W. Grimes m->flags &= ~PG_LAUNDRY; 757a83c285cSDavid Greenman return error ? VM_PAGER_ERROR : VM_PAGER_OK; 75826f9a767SRodney W. Grimes } 75926f9a767SRodney W. Grimes 76026f9a767SRodney W. Grimes /* 76126f9a767SRodney W. Grimes * generic vnode pager input routine 76226f9a767SRodney W. Grimes */ 76326f9a767SRodney W. Grimes int 76426f9a767SRodney W. Grimes vnode_pager_input(vnp, m, count, reqpage) 76526f9a767SRodney W. Grimes register vn_pager_t vnp; 76626f9a767SRodney W. Grimes vm_page_t *m; 76726f9a767SRodney W. Grimes int count, reqpage; 76826f9a767SRodney W. Grimes { 76905f0fdd2SPoul-Henning Kamp int i; 77026f9a767SRodney W. Grimes vm_offset_t kva, foff; 77116f62314SDavid Greenman int size, sizea; 77226f9a767SRodney W. Grimes vm_object_t object; 77326f9a767SRodney W. Grimes vm_offset_t paging_offset; 77426f9a767SRodney W. Grimes struct vnode *dp, *vp; 77526f9a767SRodney W. Grimes int bsize; 77626f9a767SRodney W. Grimes 77726f9a767SRodney W. Grimes int first, last; 77826f9a767SRodney W. Grimes int reqaddr, firstaddr; 77926f9a767SRodney W. Grimes int block, offset; 78026f9a767SRodney W. Grimes 78116f62314SDavid Greenman struct buf *bp, *bpa; 78216f62314SDavid Greenman int counta; 78326f9a767SRodney W. Grimes int s; 78426f9a767SRodney W. Grimes int failflag; 78526f9a767SRodney W. Grimes 78626f9a767SRodney W. Grimes int error = 0; 78726f9a767SRodney W. Grimes 788bbc0ec52SDavid Greenman object = m[reqpage]->object; /* all vm_page_t items are in same 789bbc0ec52SDavid Greenman * object */ 79026f9a767SRodney W. Grimes paging_offset = object->paging_offset; 79126f9a767SRodney W. Grimes 79226f9a767SRodney W. Grimes vp = vnp->vnp_vp; 79326f9a767SRodney W. Grimes bsize = vp->v_mount->mnt_stat.f_iosize; 79426f9a767SRodney W. Grimes 79526f9a767SRodney W. Grimes /* get the UNDERLYING device for the file with VOP_BMAP() */ 796bbc0ec52SDavid Greenman 79726f9a767SRodney W. Grimes /* 798bbc0ec52SDavid Greenman * originally, we did not check for an error return value -- assuming 799bbc0ec52SDavid Greenman * an fs always has a bmap entry point -- that assumption is wrong!!! 80026f9a767SRodney W. Grimes */ 80126f9a767SRodney W. Grimes foff = m[reqpage]->offset + paging_offset; 802bbc0ec52SDavid Greenman 80326f9a767SRodney W. Grimes /* 80416f62314SDavid Greenman * if we can't bmap, use old VOP code 80526f9a767SRodney W. Grimes */ 80616f62314SDavid Greenman if (VOP_BMAP(vp, foff, &dp, 0, 0)) { 80726f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 80826f9a767SRodney W. Grimes if (i != reqpage) { 80926f9a767SRodney W. Grimes vnode_pager_freepage(m[i]); 81026f9a767SRodney W. Grimes } 81126f9a767SRodney W. Grimes } 812976e77fcSDavid Greenman cnt.v_vnodein++; 813976e77fcSDavid Greenman cnt.v_vnodepgsin++; 81426f9a767SRodney W. Grimes return vnode_pager_input_old(vnp, m[reqpage]); 815bbc0ec52SDavid Greenman 81626f9a767SRodney W. Grimes /* 81726f9a767SRodney W. Grimes * if the blocksize is smaller than a page size, then use 81826f9a767SRodney W. Grimes * special small filesystem code. NFS sometimes has a small 81926f9a767SRodney W. Grimes * blocksize, but it can handle large reads itself. 82026f9a767SRodney W. Grimes */ 82126f9a767SRodney W. Grimes } else if ((PAGE_SIZE / bsize) > 1 && 82226f9a767SRodney W. Grimes (vp->v_mount->mnt_stat.f_type != MOUNT_NFS)) { 82326f9a767SRodney W. Grimes 82426f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 82526f9a767SRodney W. Grimes if (i != reqpage) { 82626f9a767SRodney W. Grimes vnode_pager_freepage(m[i]); 82726f9a767SRodney W. Grimes } 82826f9a767SRodney W. Grimes } 829976e77fcSDavid Greenman cnt.v_vnodein++; 830976e77fcSDavid Greenman cnt.v_vnodepgsin++; 83126f9a767SRodney W. Grimes return vnode_pager_input_smlfs(vnp, m[reqpage]); 83226f9a767SRodney W. Grimes } 83326f9a767SRodney W. Grimes /* 83426f9a767SRodney W. Grimes * here on direct device I/O 83526f9a767SRodney W. Grimes */ 83626f9a767SRodney W. Grimes 83726f9a767SRodney W. Grimes 8388e58bf68SDavid Greenman #ifdef NOTYET 8398e58bf68SDavid Greenman if( (vp->v_flag & VVMIO) == 0) { 8408e58bf68SDavid Greenman #endif 84126f9a767SRodney W. Grimes /* 84226f9a767SRodney W. Grimes * This pathetic hack gets data from the buffer cache, if it's there. 843bbc0ec52SDavid Greenman * I believe that this is not really necessary, and the ends can be 844bbc0ec52SDavid Greenman * gotten by defaulting to the normal vfs read behavior, but this 84526f9a767SRodney W. Grimes * might be more efficient, because the will NOT invoke read-aheads 846bbc0ec52SDavid Greenman * and one of the purposes of this code is to bypass the buffer cache 847bbc0ec52SDavid Greenman * and keep from flushing it by reading in a program. 84826f9a767SRodney W. Grimes */ 849bbc0ec52SDavid Greenman 85026f9a767SRodney W. Grimes /* 85126f9a767SRodney W. Grimes * calculate logical block and offset 85226f9a767SRodney W. Grimes */ 85326f9a767SRodney W. Grimes block = foff / bsize; 85426f9a767SRodney W. Grimes offset = foff % bsize; 85526f9a767SRodney W. Grimes s = splbio(); 85626f9a767SRodney W. Grimes 85726f9a767SRodney W. Grimes /* 85826f9a767SRodney W. Grimes * if we have a buffer in core, then try to use it 85926f9a767SRodney W. Grimes */ 86005f0fdd2SPoul-Henning Kamp while ((bp = incore(vp, block)) != 0) { 86126f9a767SRodney W. Grimes int amount; 86226f9a767SRodney W. Grimes 86326f9a767SRodney W. Grimes /* 86426f9a767SRodney W. Grimes * wait until the buffer is avail or gone 86526f9a767SRodney W. Grimes */ 86626f9a767SRodney W. Grimes if (bp->b_flags & B_BUSY) { 86726f9a767SRodney W. Grimes bp->b_flags |= B_WANTED; 86826f9a767SRodney W. Grimes tsleep((caddr_t) bp, PVM, "vnwblk", 0); 86926f9a767SRodney W. Grimes continue; 87026f9a767SRodney W. Grimes } 87126f9a767SRodney W. Grimes amount = PAGE_SIZE; 87226f9a767SRodney W. Grimes if ((foff + amount) > vnp->vnp_size) 87326f9a767SRodney W. Grimes amount = vnp->vnp_size - foff; 87426f9a767SRodney W. Grimes 87526f9a767SRodney W. Grimes /* 87626f9a767SRodney W. Grimes * make sure that this page is in the buffer 87726f9a767SRodney W. Grimes */ 87826f9a767SRodney W. Grimes if ((amount > 0) && (offset + amount) <= bp->b_bcount) { 87926f9a767SRodney W. Grimes bp->b_flags |= B_BUSY; 88026f9a767SRodney W. Grimes splx(s); 8818e58bf68SDavid Greenman kva = kmem_alloc_wait( pager_map, PAGE_SIZE); 88226f9a767SRodney W. Grimes 88326f9a767SRodney W. Grimes /* 88426f9a767SRodney W. Grimes * map the requested page 88526f9a767SRodney W. Grimes */ 88616f62314SDavid Greenman pmap_qenter(kva, &m[reqpage], 1); 88726f9a767SRodney W. Grimes 88826f9a767SRodney W. Grimes /* 88926f9a767SRodney W. Grimes * copy the data from the buffer 89026f9a767SRodney W. Grimes */ 89126f9a767SRodney W. Grimes bcopy(bp->b_un.b_addr + offset, (caddr_t) kva, amount); 89226f9a767SRodney W. Grimes if (amount < PAGE_SIZE) { 89326f9a767SRodney W. Grimes bzero((caddr_t) kva + amount, PAGE_SIZE - amount); 89426f9a767SRodney W. Grimes } 895bbc0ec52SDavid Greenman 89626f9a767SRodney W. Grimes /* 89726f9a767SRodney W. Grimes * unmap the page and free the kva 89826f9a767SRodney W. Grimes */ 89916f62314SDavid Greenman pmap_qremove( kva, 1); 900a481f200SDavid Greenman kmem_free_wakeup(pager_map, kva, PAGE_SIZE); 901bbc0ec52SDavid Greenman 90226f9a767SRodney W. Grimes /* 90326f9a767SRodney W. Grimes * release the buffer back to the block subsystem 90426f9a767SRodney W. Grimes */ 90526f9a767SRodney W. Grimes bp->b_flags &= ~B_BUSY; 90626f9a767SRodney W. Grimes wakeup((caddr_t) bp); 907bbc0ec52SDavid Greenman 90826f9a767SRodney W. Grimes /* 90926f9a767SRodney W. Grimes * we did not have to do any work to get the requested 91026f9a767SRodney W. Grimes * page, the read behind/ahead does not justify a read 91126f9a767SRodney W. Grimes */ 91226f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 91326f9a767SRodney W. Grimes if (i != reqpage) { 91426f9a767SRodney W. Grimes vnode_pager_freepage(m[i]); 91526f9a767SRodney W. Grimes } 91626f9a767SRodney W. Grimes } 91726f9a767SRodney W. Grimes count = 1; 91826f9a767SRodney W. Grimes reqpage = 0; 91926f9a767SRodney W. Grimes m[0] = m[reqpage]; 92026f9a767SRodney W. Grimes 92126f9a767SRodney W. Grimes /* 92226f9a767SRodney W. Grimes * sorry for the goto 92326f9a767SRodney W. Grimes */ 92426f9a767SRodney W. Grimes goto finishup; 92526f9a767SRodney W. Grimes } 926bbc0ec52SDavid Greenman 92726f9a767SRodney W. Grimes /* 92826f9a767SRodney W. Grimes * buffer is nowhere to be found, read from the disk 92926f9a767SRodney W. Grimes */ 93026f9a767SRodney W. Grimes break; 93126f9a767SRodney W. Grimes } 93226f9a767SRodney W. Grimes splx(s); 9338e58bf68SDavid Greenman #ifdef NOTYET 9348e58bf68SDavid Greenman } 9358e58bf68SDavid Greenman #endif 93626f9a767SRodney W. Grimes 93726f9a767SRodney W. Grimes reqaddr = vnode_pager_addr(vp, foff); 93826f9a767SRodney W. Grimes s = splbio(); 939bbc0ec52SDavid Greenman 94026f9a767SRodney W. Grimes /* 941bbc0ec52SDavid Greenman * Make sure that our I/O request is contiguous. Scan backward and 942bbc0ec52SDavid Greenman * stop for the first discontiguous entry or stop for a page being in 943bbc0ec52SDavid Greenman * buffer cache. 94426f9a767SRodney W. Grimes */ 94526f9a767SRodney W. Grimes failflag = 0; 94626f9a767SRodney W. Grimes first = reqpage; 94726f9a767SRodney W. Grimes for (i = reqpage - 1; i >= 0; --i) { 94826f9a767SRodney W. Grimes if (failflag || 9498e58bf68SDavid Greenman #ifdef NOTYET 9508e58bf68SDavid Greenman ((vp->v_flag & VVMIO) == 0 && incore(vp, (foff + (i - reqpage) * PAGE_SIZE) / bsize)) || 9518e58bf68SDavid Greenman #else 9528e58bf68SDavid Greenman (incore(vp, (foff + (i - reqpage) * PAGE_SIZE) / bsize)) || 9538e58bf68SDavid Greenman #endif 95426f9a767SRodney W. Grimes (vnode_pager_addr(vp, m[i]->offset + paging_offset)) 95526f9a767SRodney W. Grimes != reqaddr + (i - reqpage) * PAGE_SIZE) { 95626f9a767SRodney W. Grimes vnode_pager_freepage(m[i]); 95726f9a767SRodney W. Grimes failflag = 1; 95826f9a767SRodney W. Grimes } else { 95926f9a767SRodney W. Grimes first = i; 96026f9a767SRodney W. Grimes } 96126f9a767SRodney W. Grimes } 96226f9a767SRodney W. Grimes 96326f9a767SRodney W. Grimes /* 964bbc0ec52SDavid Greenman * Scan forward and stop for the first non-contiguous entry or stop 965bbc0ec52SDavid Greenman * for a page being in buffer cache. 96626f9a767SRodney W. Grimes */ 96726f9a767SRodney W. Grimes failflag = 0; 96826f9a767SRodney W. Grimes last = reqpage + 1; 96926f9a767SRodney W. Grimes for (i = reqpage + 1; i < count; i++) { 97026f9a767SRodney W. Grimes if (failflag || 9718e58bf68SDavid Greenman #ifdef NOTYET 9728e58bf68SDavid Greenman ((vp->v_flag & VVMIO) == 0 && incore(vp, (foff + (i - reqpage) * PAGE_SIZE) / bsize)) || 9738e58bf68SDavid Greenman #else 9748e58bf68SDavid Greenman (incore(vp, (foff + (i - reqpage) * PAGE_SIZE) / bsize)) || 9758e58bf68SDavid Greenman #endif 97626f9a767SRodney W. Grimes (vnode_pager_addr(vp, m[i]->offset + paging_offset)) 97726f9a767SRodney W. Grimes != reqaddr + (i - reqpage) * PAGE_SIZE) { 97826f9a767SRodney W. Grimes vnode_pager_freepage(m[i]); 97926f9a767SRodney W. Grimes failflag = 1; 98026f9a767SRodney W. Grimes } else { 98126f9a767SRodney W. Grimes last = i + 1; 98226f9a767SRodney W. Grimes } 98326f9a767SRodney W. Grimes } 98426f9a767SRodney W. Grimes splx(s); 98526f9a767SRodney W. Grimes 98626f9a767SRodney W. Grimes /* 987bbc0ec52SDavid Greenman * the first and last page have been calculated now, move input pages 988bbc0ec52SDavid Greenman * to be zero based... 98926f9a767SRodney W. Grimes */ 99026f9a767SRodney W. Grimes count = last; 99126f9a767SRodney W. Grimes if (first != 0) { 99226f9a767SRodney W. Grimes for (i = first; i < count; i++) { 99326f9a767SRodney W. Grimes m[i - first] = m[i]; 99426f9a767SRodney W. Grimes } 99526f9a767SRodney W. Grimes count -= first; 99626f9a767SRodney W. Grimes reqpage -= first; 99726f9a767SRodney W. Grimes } 99826f9a767SRodney W. Grimes 99926f9a767SRodney W. Grimes /* 100026f9a767SRodney W. Grimes * calculate the file virtual address for the transfer 100126f9a767SRodney W. Grimes */ 100226f9a767SRodney W. Grimes foff = m[0]->offset + paging_offset; 1003bbc0ec52SDavid Greenman 100426f9a767SRodney W. Grimes /* 100526f9a767SRodney W. Grimes * and get the disk physical address (in bytes) 100626f9a767SRodney W. Grimes */ 100726f9a767SRodney W. Grimes firstaddr = vnode_pager_addr(vp, foff); 100826f9a767SRodney W. Grimes 100926f9a767SRodney W. Grimes /* 101026f9a767SRodney W. Grimes * calculate the size of the transfer 101126f9a767SRodney W. Grimes */ 101226f9a767SRodney W. Grimes size = count * PAGE_SIZE; 101326f9a767SRodney W. Grimes if ((foff + size) > vnp->vnp_size) 101426f9a767SRodney W. Grimes size = vnp->vnp_size - foff; 101526f9a767SRodney W. Grimes 101626f9a767SRodney W. Grimes /* 101726f9a767SRodney W. Grimes * round up physical size for real devices 101826f9a767SRodney W. Grimes */ 101926f9a767SRodney W. Grimes if (dp->v_type == VBLK || dp->v_type == VCHR) 102026f9a767SRodney W. Grimes size = (size + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1); 102126f9a767SRodney W. Grimes 102216f62314SDavid Greenman counta = 0; 102316f62314SDavid Greenman if( count*PAGE_SIZE > bsize) 102416f62314SDavid Greenman counta = (count - reqpage) - 1; 102516f62314SDavid Greenman bpa = 0; 102616f62314SDavid Greenman sizea = 0; 102716f62314SDavid Greenman if( counta) { 102816f62314SDavid Greenman bpa = getpbuf(); 102916f62314SDavid Greenman count -= counta; 103016f62314SDavid Greenman sizea = size - count*PAGE_SIZE; 103116f62314SDavid Greenman size = count * PAGE_SIZE; 103216f62314SDavid Greenman } 103316f62314SDavid Greenman 103416f62314SDavid Greenman bp = getpbuf(); 103516f62314SDavid Greenman kva = (vm_offset_t)bp->b_data; 103616f62314SDavid Greenman 103726f9a767SRodney W. Grimes /* 103826f9a767SRodney W. Grimes * and map the pages to be read into the kva 103926f9a767SRodney W. Grimes */ 104016f62314SDavid Greenman pmap_qenter(kva, m, count); 104126f9a767SRodney W. Grimes VHOLD(vp); 104226f9a767SRodney W. Grimes 104326f9a767SRodney W. Grimes /* build a minimal buffer header */ 104426f9a767SRodney W. Grimes bp->b_flags = B_BUSY | B_READ | B_CALL; 104526f9a767SRodney W. Grimes bp->b_iodone = vnode_pager_iodone; 104626f9a767SRodney W. Grimes /* B_PHYS is not set, but it is nice to fill this in */ 104726f9a767SRodney W. Grimes bp->b_proc = curproc; 104826f9a767SRodney W. Grimes bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred; 104926f9a767SRodney W. Grimes if (bp->b_rcred != NOCRED) 105026f9a767SRodney W. Grimes crhold(bp->b_rcred); 105126f9a767SRodney W. Grimes if (bp->b_wcred != NOCRED) 105226f9a767SRodney W. Grimes crhold(bp->b_wcred); 105326f9a767SRodney W. Grimes bp->b_blkno = firstaddr / DEV_BSIZE; 105426f9a767SRodney W. Grimes bgetvp(dp, bp); 105526f9a767SRodney W. Grimes bp->b_bcount = size; 105626f9a767SRodney W. Grimes bp->b_bufsize = size; 105726f9a767SRodney W. Grimes 1058976e77fcSDavid Greenman cnt.v_vnodein++; 1059976e77fcSDavid Greenman cnt.v_vnodepgsin += count; 1060976e77fcSDavid Greenman 106126f9a767SRodney W. Grimes /* do the input */ 106226f9a767SRodney W. Grimes VOP_STRATEGY(bp); 1063976e77fcSDavid Greenman 106416f62314SDavid Greenman if( counta) { 106516f62314SDavid Greenman for(i=0;i<counta;i++) { 106616f62314SDavid Greenman vm_page_deactivate(m[count+i]); 106716f62314SDavid Greenman } 1068c87801feSDavid Greenman pmap_qenter((vm_offset_t)bpa->b_data, &m[count], counta); 106916f62314SDavid Greenman ++m[count]->object->paging_in_progress; 107016f62314SDavid Greenman VHOLD(vp); 107116f62314SDavid Greenman bpa->b_flags = B_BUSY | B_READ | B_CALL | B_ASYNC; 107216f62314SDavid Greenman bpa->b_iodone = vnode_pager_iodone; 107316f62314SDavid Greenman /* B_PHYS is not set, but it is nice to fill this in */ 107416f62314SDavid Greenman bpa->b_proc = curproc; 107516f62314SDavid Greenman bpa->b_rcred = bpa->b_wcred = bpa->b_proc->p_ucred; 107616f62314SDavid Greenman if (bpa->b_rcred != NOCRED) 107716f62314SDavid Greenman crhold(bpa->b_rcred); 107816f62314SDavid Greenman if (bpa->b_wcred != NOCRED) 107916f62314SDavid Greenman crhold(bpa->b_wcred); 108016f62314SDavid Greenman bpa->b_blkno = (firstaddr + count * PAGE_SIZE) / DEV_BSIZE; 108116f62314SDavid Greenman bgetvp(dp, bpa); 108216f62314SDavid Greenman bpa->b_bcount = sizea; 108316f62314SDavid Greenman bpa->b_bufsize = counta*PAGE_SIZE; 108416f62314SDavid Greenman 1085976e77fcSDavid Greenman cnt.v_vnodepgsin += counta; 108616f62314SDavid Greenman VOP_STRATEGY(bpa); 108716f62314SDavid Greenman } 108826f9a767SRodney W. Grimes 108926f9a767SRodney W. Grimes s = splbio(); 109026f9a767SRodney W. Grimes /* we definitely need to be at splbio here */ 109126f9a767SRodney W. Grimes 109226f9a767SRodney W. Grimes while ((bp->b_flags & B_DONE) == 0) { 109326f9a767SRodney W. Grimes tsleep((caddr_t) bp, PVM, "vnread", 0); 109426f9a767SRodney W. Grimes } 109526f9a767SRodney W. Grimes splx(s); 109626f9a767SRodney W. Grimes if ((bp->b_flags & B_ERROR) != 0) 109726f9a767SRodney W. Grimes error = EIO; 109826f9a767SRodney W. Grimes 109926f9a767SRodney W. Grimes if (!error) { 110026f9a767SRodney W. Grimes if (size != count * PAGE_SIZE) 110126f9a767SRodney W. Grimes bzero((caddr_t) kva + size, PAGE_SIZE * count - size); 110226f9a767SRodney W. Grimes } 110316f62314SDavid Greenman pmap_qremove( kva, count); 110426f9a767SRodney W. Grimes 110526f9a767SRodney W. Grimes /* 110626f9a767SRodney W. Grimes * free the buffer header back to the swap buffer pool 110726f9a767SRodney W. Grimes */ 110826f9a767SRodney W. Grimes relpbuf(bp); 110926f9a767SRodney W. Grimes HOLDRELE(vp); 111026f9a767SRodney W. Grimes 111126f9a767SRodney W. Grimes finishup: 111226f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 1113fff93ab6SDavid Greenman pmap_clear_modify(VM_PAGE_TO_PHYS(m[i])); 111426f9a767SRodney W. Grimes m[i]->flags |= PG_CLEAN; 111526f9a767SRodney W. Grimes m[i]->flags &= ~PG_LAUNDRY; 111626f9a767SRodney W. Grimes if (i != reqpage) { 1117bbc0ec52SDavid Greenman 111826f9a767SRodney W. Grimes /* 1119bbc0ec52SDavid Greenman * whether or not to leave the page activated is up in 1120bbc0ec52SDavid Greenman * the air, but we should put the page on a page queue 1121bbc0ec52SDavid Greenman * somewhere. (it already is in the object). Result: 1122bbc0ec52SDavid Greenman * It appears that emperical results show that 1123bbc0ec52SDavid Greenman * deactivating pages is best. 112426f9a767SRodney W. Grimes */ 1125bbc0ec52SDavid Greenman 112626f9a767SRodney W. Grimes /* 1127bbc0ec52SDavid Greenman * just in case someone was asking for this page we 1128bbc0ec52SDavid Greenman * now tell them that it is ok to use 112926f9a767SRodney W. Grimes */ 113026f9a767SRodney W. Grimes if (!error) { 113126f9a767SRodney W. Grimes vm_page_deactivate(m[i]); 113226f9a767SRodney W. Grimes PAGE_WAKEUP(m[i]); 113326f9a767SRodney W. Grimes m[i]->flags &= ~PG_FAKE; 113426f9a767SRodney W. Grimes } else { 113526f9a767SRodney W. Grimes vnode_pager_freepage(m[i]); 113626f9a767SRodney W. Grimes } 113726f9a767SRodney W. Grimes } 113826f9a767SRodney W. Grimes } 113926f9a767SRodney W. Grimes if (error) { 1140a83c285cSDavid Greenman printf("vnode_pager_input: I/O read error\n"); 114126f9a767SRodney W. Grimes } 1142a83c285cSDavid Greenman return (error ? VM_PAGER_ERROR : VM_PAGER_OK); 114326f9a767SRodney W. Grimes } 114426f9a767SRodney W. Grimes 114526f9a767SRodney W. Grimes /* 114626f9a767SRodney W. Grimes * old-style vnode pager output routine 114726f9a767SRodney W. Grimes */ 114826f9a767SRodney W. Grimes int 114926f9a767SRodney W. Grimes vnode_pager_output_old(vnp, m) 115026f9a767SRodney W. Grimes register vn_pager_t vnp; 115126f9a767SRodney W. Grimes vm_page_t m; 115226f9a767SRodney W. Grimes { 115326f9a767SRodney W. Grimes vm_offset_t foff; 115426f9a767SRodney W. Grimes vm_offset_t kva; 115526f9a767SRodney W. Grimes vm_offset_t size; 115626f9a767SRodney W. Grimes struct iovec aiov; 115726f9a767SRodney W. Grimes struct uio auio; 115826f9a767SRodney W. Grimes struct vnode *vp; 115926f9a767SRodney W. Grimes int error; 116026f9a767SRodney W. Grimes 116126f9a767SRodney W. Grimes vp = vnp->vnp_vp; 116226f9a767SRodney W. Grimes foff = m->offset + m->object->paging_offset; 1163bbc0ec52SDavid Greenman 116426f9a767SRodney W. Grimes /* 116526f9a767SRodney W. Grimes * Return failure if beyond current EOF 116626f9a767SRodney W. Grimes */ 116726f9a767SRodney W. Grimes if (foff >= vnp->vnp_size) { 116826f9a767SRodney W. Grimes return VM_PAGER_BAD; 116926f9a767SRodney W. Grimes } else { 117026f9a767SRodney W. Grimes size = PAGE_SIZE; 117126f9a767SRodney W. Grimes if (foff + size > vnp->vnp_size) 117226f9a767SRodney W. Grimes size = vnp->vnp_size - foff; 117326f9a767SRodney W. Grimes /* 117426f9a767SRodney W. Grimes * Allocate a kernel virtual address and initialize so that 117526f9a767SRodney W. Grimes * we can use VOP_WRITE routines. 117626f9a767SRodney W. Grimes */ 117726f9a767SRodney W. Grimes kva = vm_pager_map_page(m); 117826f9a767SRodney W. Grimes aiov.iov_base = (caddr_t) kva; 117926f9a767SRodney W. Grimes aiov.iov_len = size; 118026f9a767SRodney W. Grimes auio.uio_iov = &aiov; 118126f9a767SRodney W. Grimes auio.uio_iovcnt = 1; 118226f9a767SRodney W. Grimes auio.uio_offset = foff; 118326f9a767SRodney W. Grimes auio.uio_segflg = UIO_SYSSPACE; 118426f9a767SRodney W. Grimes auio.uio_rw = UIO_WRITE; 118526f9a767SRodney W. Grimes auio.uio_resid = size; 118626f9a767SRodney W. Grimes auio.uio_procp = (struct proc *) 0; 118726f9a767SRodney W. Grimes 118826f9a767SRodney W. Grimes error = VOP_WRITE(vp, &auio, 0, curproc->p_ucred); 118926f9a767SRodney W. Grimes 119026f9a767SRodney W. Grimes if (!error) { 119126f9a767SRodney W. Grimes if ((size - auio.uio_resid) == 0) { 119226f9a767SRodney W. Grimes error = EINVAL; 119326f9a767SRodney W. Grimes } 119426f9a767SRodney W. Grimes } 119526f9a767SRodney W. Grimes vm_pager_unmap_page(kva); 1196a83c285cSDavid Greenman return error ? VM_PAGER_ERROR: VM_PAGER_OK; 119726f9a767SRodney W. Grimes } 119826f9a767SRodney W. Grimes } 119926f9a767SRodney W. Grimes 120026f9a767SRodney W. Grimes /* 120126f9a767SRodney W. Grimes * vnode pager output on a small-block file system 120226f9a767SRodney W. Grimes */ 120326f9a767SRodney W. Grimes int 120426f9a767SRodney W. Grimes vnode_pager_output_smlfs(vnp, m) 120526f9a767SRodney W. Grimes vn_pager_t vnp; 120626f9a767SRodney W. Grimes vm_page_t m; 120726f9a767SRodney W. Grimes { 120826f9a767SRodney W. Grimes int i; 120926f9a767SRodney W. Grimes int s; 121026f9a767SRodney W. Grimes vm_offset_t paging_offset; 121126f9a767SRodney W. Grimes struct vnode *dp, *vp; 121226f9a767SRodney W. Grimes struct buf *bp; 121326f9a767SRodney W. Grimes vm_offset_t foff; 121426f9a767SRodney W. Grimes vm_offset_t kva; 121526f9a767SRodney W. Grimes int fileaddr; 121626f9a767SRodney W. Grimes vm_offset_t bsize; 121726f9a767SRodney W. Grimes int error = 0; 121826f9a767SRodney W. Grimes 121926f9a767SRodney W. Grimes paging_offset = m->object->paging_offset; 122026f9a767SRodney W. Grimes vp = vnp->vnp_vp; 122126f9a767SRodney W. Grimes bsize = vp->v_mount->mnt_stat.f_iosize; 122226f9a767SRodney W. Grimes foff = m->offset + paging_offset; 122326f9a767SRodney W. Grimes 122426f9a767SRodney W. Grimes VOP_BMAP(vp, foff, &dp, 0, 0); 122526f9a767SRodney W. Grimes kva = vm_pager_map_page(m); 122626f9a767SRodney W. Grimes for (i = 0; !error && i < (PAGE_SIZE / bsize); i++) { 1227bbc0ec52SDavid Greenman 122826f9a767SRodney W. Grimes /* 122926f9a767SRodney W. Grimes * calculate logical block and offset 123026f9a767SRodney W. Grimes */ 123126f9a767SRodney W. Grimes fileaddr = vnode_pager_addr(vp, foff + i * bsize); 123226f9a767SRodney W. Grimes if (fileaddr != -1) { 123326f9a767SRodney W. Grimes s = splbio(); 123405f0fdd2SPoul-Henning Kamp bp = incore(vp, (foff / bsize) + i); 123505f0fdd2SPoul-Henning Kamp if (bp) { 123626f9a767SRodney W. Grimes bp = getblk(vp, (foff / bsize) + i, bp->b_bufsize, 0, 0); 123726f9a767SRodney W. Grimes bp->b_flags |= B_INVAL; 123826f9a767SRodney W. Grimes brelse(bp); 123926f9a767SRodney W. Grimes } 124026f9a767SRodney W. Grimes splx(s); 124126f9a767SRodney W. Grimes 124226f9a767SRodney W. Grimes bp = getpbuf(); 124326f9a767SRodney W. Grimes VHOLD(vp); 124426f9a767SRodney W. Grimes 124526f9a767SRodney W. Grimes /* build a minimal buffer header */ 124626f9a767SRodney W. Grimes bp->b_flags = B_BUSY | B_CALL | B_WRITE; 124726f9a767SRodney W. Grimes bp->b_iodone = vnode_pager_iodone; 124826f9a767SRodney W. Grimes bp->b_proc = curproc; 124926f9a767SRodney W. Grimes bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred; 125026f9a767SRodney W. Grimes if (bp->b_rcred != NOCRED) 125126f9a767SRodney W. Grimes crhold(bp->b_rcred); 125226f9a767SRodney W. Grimes if (bp->b_wcred != NOCRED) 125326f9a767SRodney W. Grimes crhold(bp->b_wcred); 125426f9a767SRodney W. Grimes bp->b_un.b_addr = (caddr_t) kva + i * bsize; 125526f9a767SRodney W. Grimes bp->b_blkno = fileaddr / DEV_BSIZE; 125626f9a767SRodney W. Grimes bgetvp(dp, bp); 125726f9a767SRodney W. Grimes ++dp->v_numoutput; 125826f9a767SRodney W. Grimes /* for NFS */ 125926f9a767SRodney W. Grimes bp->b_dirtyoff = 0; 126026f9a767SRodney W. Grimes bp->b_dirtyend = bsize; 126126f9a767SRodney W. Grimes bp->b_bcount = bsize; 126226f9a767SRodney W. Grimes bp->b_bufsize = bsize; 126326f9a767SRodney W. Grimes 126426f9a767SRodney W. Grimes /* do the input */ 126526f9a767SRodney W. Grimes VOP_STRATEGY(bp); 126626f9a767SRodney W. Grimes 126726f9a767SRodney W. Grimes /* we definitely need to be at splbio here */ 126826f9a767SRodney W. Grimes 126926f9a767SRodney W. Grimes s = splbio(); 127026f9a767SRodney W. Grimes while ((bp->b_flags & B_DONE) == 0) { 127126f9a767SRodney W. Grimes tsleep((caddr_t) bp, PVM, "vnswrt", 0); 127226f9a767SRodney W. Grimes } 127326f9a767SRodney W. Grimes splx(s); 127426f9a767SRodney W. Grimes if ((bp->b_flags & B_ERROR) != 0) 127526f9a767SRodney W. Grimes error = EIO; 127626f9a767SRodney W. Grimes 127726f9a767SRodney W. Grimes /* 127826f9a767SRodney W. Grimes * free the buffer header back to the swap buffer pool 127926f9a767SRodney W. Grimes */ 128026f9a767SRodney W. Grimes relpbuf(bp); 128126f9a767SRodney W. Grimes HOLDRELE(vp); 128226f9a767SRodney W. Grimes } 128326f9a767SRodney W. Grimes } 128426f9a767SRodney W. Grimes vm_pager_unmap_page(kva); 128526f9a767SRodney W. Grimes if (error) 1286a83c285cSDavid Greenman return VM_PAGER_ERROR; 128726f9a767SRodney W. Grimes else 128826f9a767SRodney W. Grimes return VM_PAGER_OK; 128926f9a767SRodney W. Grimes } 129026f9a767SRodney W. Grimes 129126f9a767SRodney W. Grimes /* 129226f9a767SRodney W. Grimes * generic vnode pager output routine 129326f9a767SRodney W. Grimes */ 129426f9a767SRodney W. Grimes int 129526f9a767SRodney W. Grimes vnode_pager_output(vnp, m, count, rtvals) 129626f9a767SRodney W. Grimes vn_pager_t vnp; 129726f9a767SRodney W. Grimes vm_page_t *m; 129826f9a767SRodney W. Grimes int count; 129926f9a767SRodney W. Grimes int *rtvals; 130026f9a767SRodney W. Grimes { 130126f9a767SRodney W. Grimes int i, j; 130226f9a767SRodney W. Grimes vm_offset_t kva, foff; 130326f9a767SRodney W. Grimes int size; 130426f9a767SRodney W. Grimes vm_object_t object; 130526f9a767SRodney W. Grimes vm_offset_t paging_offset; 130626f9a767SRodney W. Grimes struct vnode *dp, *vp; 130726f9a767SRodney W. Grimes struct buf *bp; 130826f9a767SRodney W. Grimes vm_offset_t reqaddr; 130926f9a767SRodney W. Grimes int bsize; 131026f9a767SRodney W. Grimes int s; 131126f9a767SRodney W. Grimes 131226f9a767SRodney W. Grimes int error = 0; 131326f9a767SRodney W. Grimes 131426f9a767SRodney W. Grimes retryoutput: 131526f9a767SRodney W. Grimes object = m[0]->object; /* all vm_page_t items are in same object */ 131626f9a767SRodney W. Grimes paging_offset = object->paging_offset; 131726f9a767SRodney W. Grimes 131826f9a767SRodney W. Grimes vp = vnp->vnp_vp; 131926f9a767SRodney W. Grimes bsize = vp->v_mount->mnt_stat.f_iosize; 132026f9a767SRodney W. Grimes 132126f9a767SRodney W. Grimes for (i = 0; i < count; i++) 132226f9a767SRodney W. Grimes rtvals[i] = VM_PAGER_AGAIN; 132326f9a767SRodney W. Grimes 132426f9a767SRodney W. Grimes /* 1325bbc0ec52SDavid Greenman * if the filesystem does not have a bmap, then use the old code 132626f9a767SRodney W. Grimes */ 132726f9a767SRodney W. Grimes if (VOP_BMAP(vp, m[0]->offset + paging_offset, &dp, 0, 0)) { 132826f9a767SRodney W. Grimes 132926f9a767SRodney W. Grimes rtvals[0] = vnode_pager_output_old(vnp, m[0]); 133026f9a767SRodney W. Grimes 133126f9a767SRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(m[0])); 133226f9a767SRodney W. Grimes m[0]->flags |= PG_CLEAN; 133326f9a767SRodney W. Grimes m[0]->flags &= ~PG_LAUNDRY; 1334976e77fcSDavid Greenman cnt.v_vnodeout++; 1335976e77fcSDavid Greenman cnt.v_vnodepgsout++; 133626f9a767SRodney W. Grimes return rtvals[0]; 133726f9a767SRodney W. Grimes } 133826f9a767SRodney W. Grimes 133926f9a767SRodney W. Grimes /* 1340bbc0ec52SDavid Greenman * if the filesystem has a small blocksize, then use the small block 1341bbc0ec52SDavid Greenman * filesystem output code 134226f9a767SRodney W. Grimes */ 134326f9a767SRodney W. Grimes if ((bsize < PAGE_SIZE) && 134426f9a767SRodney W. Grimes (vp->v_mount->mnt_stat.f_type != MOUNT_NFS)) { 134526f9a767SRodney W. Grimes 134626f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 134726f9a767SRodney W. Grimes rtvals[i] = vnode_pager_output_smlfs(vnp, m[i]); 134826f9a767SRodney W. Grimes if (rtvals[i] == VM_PAGER_OK) { 134926f9a767SRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(m[i])); 135026f9a767SRodney W. Grimes m[i]->flags |= PG_CLEAN; 135126f9a767SRodney W. Grimes m[i]->flags &= ~PG_LAUNDRY; 135226f9a767SRodney W. Grimes } 135326f9a767SRodney W. Grimes } 1354976e77fcSDavid Greenman cnt.v_vnodeout++; 1355976e77fcSDavid Greenman cnt.v_vnodepgsout += count; 135626f9a767SRodney W. Grimes return rtvals[0]; 135726f9a767SRodney W. Grimes } 135826f9a767SRodney W. Grimes 135926f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 136026f9a767SRodney W. Grimes foff = m[i]->offset + paging_offset; 136126f9a767SRodney W. Grimes if (foff >= vnp->vnp_size) { 136226f9a767SRodney W. Grimes for (j = i; j < count; j++) 136326f9a767SRodney W. Grimes rtvals[j] = VM_PAGER_BAD; 136426f9a767SRodney W. Grimes count = i; 136526f9a767SRodney W. Grimes break; 136626f9a767SRodney W. Grimes } 136726f9a767SRodney W. Grimes } 136826f9a767SRodney W. Grimes if (count == 0) { 136926f9a767SRodney W. Grimes return rtvals[0]; 137026f9a767SRodney W. Grimes } 137126f9a767SRodney W. Grimes foff = m[0]->offset + paging_offset; 137226f9a767SRodney W. Grimes reqaddr = vnode_pager_addr(vp, foff); 1373bbc0ec52SDavid Greenman 137426f9a767SRodney W. Grimes /* 1375bbc0ec52SDavid Greenman * Scan forward and stop for the first non-contiguous entry or stop 1376bbc0ec52SDavid Greenman * for a page being in buffer cache. 137726f9a767SRodney W. Grimes */ 137826f9a767SRodney W. Grimes for (i = 1; i < count; i++) { 137926f9a767SRodney W. Grimes if (vnode_pager_addr(vp, m[i]->offset + paging_offset) 138026f9a767SRodney W. Grimes != reqaddr + i * PAGE_SIZE) { 138126f9a767SRodney W. Grimes count = i; 138226f9a767SRodney W. Grimes break; 138326f9a767SRodney W. Grimes } 138426f9a767SRodney W. Grimes } 138526f9a767SRodney W. Grimes 138626f9a767SRodney W. Grimes /* 138726f9a767SRodney W. Grimes * calculate the size of the transfer 138826f9a767SRodney W. Grimes */ 138926f9a767SRodney W. Grimes size = count * PAGE_SIZE; 139026f9a767SRodney W. Grimes if ((foff + size) > vnp->vnp_size) 139126f9a767SRodney W. Grimes size = vnp->vnp_size - foff; 139226f9a767SRodney W. Grimes 139326f9a767SRodney W. Grimes /* 139426f9a767SRodney W. Grimes * round up physical size for real devices 139526f9a767SRodney W. Grimes */ 139626f9a767SRodney W. Grimes if (dp->v_type == VBLK || dp->v_type == VCHR) 139726f9a767SRodney W. Grimes size = (size + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1); 139826f9a767SRodney W. Grimes 139916f62314SDavid Greenman bp = getpbuf(); 140016f62314SDavid Greenman kva = (vm_offset_t)bp->b_data; 140126f9a767SRodney W. Grimes /* 140226f9a767SRodney W. Grimes * and map the pages to be read into the kva 140326f9a767SRodney W. Grimes */ 140416f62314SDavid Greenman pmap_qenter(kva, m, count); 1405db141545SDavid Greenman #if 0 140626f9a767SRodney W. Grimes printf("vnode: writing foff: %d, devoff: %d, size: %d\n", 140726f9a767SRodney W. Grimes foff, reqaddr, size); 1408db141545SDavid Greenman #endif 1409bbc0ec52SDavid Greenman 141026f9a767SRodney W. Grimes /* 141126f9a767SRodney W. Grimes * next invalidate the incore vfs_bio data 141226f9a767SRodney W. Grimes */ 14138e58bf68SDavid Greenman #ifdef NOTYET 14148e58bf68SDavid Greenman if( (vp->v_flag & VVMIO) == 0) { 14158e58bf68SDavid Greenman #endif 141626f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 141726f9a767SRodney W. Grimes int filblock = (foff + i * PAGE_SIZE) / bsize; 141826f9a767SRodney W. Grimes struct buf *fbp; 141926f9a767SRodney W. Grimes 142026f9a767SRodney W. Grimes s = splbio(); 142105f0fdd2SPoul-Henning Kamp fbp = incore(vp, filblock); 142205f0fdd2SPoul-Henning Kamp if (fbp) { 142326f9a767SRodney W. Grimes fbp = getblk(vp, filblock, fbp->b_bufsize, 0, 0); 1424bbc0ec52SDavid Greenman if (fbp->b_flags & B_DELWRI) { 1425bbc0ec52SDavid Greenman if (fbp->b_bufsize <= PAGE_SIZE) 1426bbc0ec52SDavid Greenman fbp->b_flags &= ~B_DELWRI; 1427bbc0ec52SDavid Greenman else { 1428bbc0ec52SDavid Greenman bwrite(fbp); 1429bbc0ec52SDavid Greenman fbp = getblk(vp, filblock, 1430bbc0ec52SDavid Greenman fbp->b_bufsize, 0, 0); 1431bbc0ec52SDavid Greenman } 1432bbc0ec52SDavid Greenman } 143326f9a767SRodney W. Grimes fbp->b_flags |= B_INVAL; 143426f9a767SRodney W. Grimes brelse(fbp); 143526f9a767SRodney W. Grimes } 143626f9a767SRodney W. Grimes splx(s); 143726f9a767SRodney W. Grimes } 14388e58bf68SDavid Greenman #ifdef NOTYET 14398e58bf68SDavid Greenman } 14408e58bf68SDavid Greenman #endif 144126f9a767SRodney W. Grimes 144226f9a767SRodney W. Grimes 144326f9a767SRodney W. Grimes VHOLD(vp); 144426f9a767SRodney W. Grimes /* build a minimal buffer header */ 144526f9a767SRodney W. Grimes bp->b_flags = B_BUSY | B_WRITE | B_CALL; 144626f9a767SRodney W. Grimes bp->b_iodone = vnode_pager_iodone; 144726f9a767SRodney W. Grimes /* B_PHYS is not set, but it is nice to fill this in */ 144826f9a767SRodney W. Grimes bp->b_proc = curproc; 144926f9a767SRodney W. Grimes bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred; 145026f9a767SRodney W. Grimes 145126f9a767SRodney W. Grimes if (bp->b_rcred != NOCRED) 145226f9a767SRodney W. Grimes crhold(bp->b_rcred); 145326f9a767SRodney W. Grimes if (bp->b_wcred != NOCRED) 145426f9a767SRodney W. Grimes crhold(bp->b_wcred); 145526f9a767SRodney W. Grimes bp->b_blkno = reqaddr / DEV_BSIZE; 145626f9a767SRodney W. Grimes bgetvp(dp, bp); 145726f9a767SRodney W. Grimes ++dp->v_numoutput; 145826f9a767SRodney W. Grimes 145926f9a767SRodney W. Grimes /* for NFS */ 146026f9a767SRodney W. Grimes bp->b_dirtyoff = 0; 146126f9a767SRodney W. Grimes bp->b_dirtyend = size; 146226f9a767SRodney W. Grimes 146326f9a767SRodney W. Grimes bp->b_bcount = size; 146426f9a767SRodney W. Grimes bp->b_bufsize = size; 146526f9a767SRodney W. Grimes 1466976e77fcSDavid Greenman cnt.v_vnodeout++; 1467976e77fcSDavid Greenman cnt.v_vnodepgsout += count; 1468976e77fcSDavid Greenman 146926f9a767SRodney W. Grimes /* do the output */ 147026f9a767SRodney W. Grimes VOP_STRATEGY(bp); 147126f9a767SRodney W. Grimes 147226f9a767SRodney W. Grimes s = splbio(); 147326f9a767SRodney W. Grimes 147426f9a767SRodney W. Grimes /* we definitely need to be at splbio here */ 147526f9a767SRodney W. Grimes 147626f9a767SRodney W. Grimes while ((bp->b_flags & B_DONE) == 0) { 147726f9a767SRodney W. Grimes tsleep((caddr_t) bp, PVM, "vnwrite", 0); 147826f9a767SRodney W. Grimes } 147926f9a767SRodney W. Grimes splx(s); 148026f9a767SRodney W. Grimes 148126f9a767SRodney W. Grimes if ((bp->b_flags & B_ERROR) != 0) 148226f9a767SRodney W. Grimes error = EIO; 148326f9a767SRodney W. Grimes 148416f62314SDavid Greenman pmap_qremove( kva, count); 148526f9a767SRodney W. Grimes 148626f9a767SRodney W. Grimes /* 148726f9a767SRodney W. Grimes * free the buffer header back to the swap buffer pool 148826f9a767SRodney W. Grimes */ 148926f9a767SRodney W. Grimes relpbuf(bp); 149026f9a767SRodney W. Grimes HOLDRELE(vp); 149126f9a767SRodney W. Grimes 149226f9a767SRodney W. Grimes if (!error) { 149326f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 149426f9a767SRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(m[i])); 149526f9a767SRodney W. Grimes m[i]->flags |= PG_CLEAN; 149626f9a767SRodney W. Grimes m[i]->flags &= ~PG_LAUNDRY; 149726f9a767SRodney W. Grimes rtvals[i] = VM_PAGER_OK; 149826f9a767SRodney W. Grimes } 149926f9a767SRodney W. Grimes } else if (count != 1) { 150026f9a767SRodney W. Grimes error = 0; 150126f9a767SRodney W. Grimes count = 1; 150226f9a767SRodney W. Grimes goto retryoutput; 150326f9a767SRodney W. Grimes } 150426f9a767SRodney W. Grimes if (error) { 1505a83c285cSDavid Greenman printf("vnode_pager_output: I/O write error\n"); 150626f9a767SRodney W. Grimes } 1507a83c285cSDavid Greenman return (error ? VM_PAGER_ERROR: VM_PAGER_OK); 150826f9a767SRodney W. Grimes } 1509