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 400d94caffSDavid Greenman * $Id: vnode_pager.c,v 1.18 1994/11/24 14:43:22 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> 710d94caffSDavid Greenman #include <sys/kernel.h> 72df8bae1dSRodney W. Grimes #include <sys/proc.h> 73df8bae1dSRodney W. Grimes #include <sys/malloc.h> 74df8bae1dSRodney W. Grimes #include <sys/vnode.h> 75df8bae1dSRodney W. Grimes #include <sys/uio.h> 76df8bae1dSRodney W. Grimes #include <sys/mount.h> 77df8bae1dSRodney W. Grimes 78df8bae1dSRodney W. Grimes #include <vm/vm.h> 79df8bae1dSRodney W. Grimes #include <vm/vm_page.h> 80df8bae1dSRodney W. Grimes #include <vm/vnode_pager.h> 81df8bae1dSRodney W. Grimes 8226f9a767SRodney W. Grimes #include <sys/buf.h> 8326f9a767SRodney W. Grimes #include <miscfs/specfs/specdev.h> 84df8bae1dSRodney W. Grimes 8526f9a767SRodney W. Grimes int vnode_pager_putmulti(); 86df8bae1dSRodney W. Grimes 8726f9a767SRodney W. Grimes void vnode_pager_init(); 8826f9a767SRodney W. Grimes vm_pager_t vnode_pager_alloc(caddr_t, vm_offset_t, vm_prot_t, vm_offset_t); 8926f9a767SRodney W. Grimes void vnode_pager_dealloc(); 9026f9a767SRodney W. Grimes int vnode_pager_getpage(); 9126f9a767SRodney W. Grimes int vnode_pager_getmulti(); 9226f9a767SRodney W. Grimes int vnode_pager_putpage(); 9326f9a767SRodney W. Grimes boolean_t vnode_pager_haspage(); 94df8bae1dSRodney W. Grimes 95df8bae1dSRodney W. Grimes struct pagerops vnodepagerops = { 96df8bae1dSRodney W. Grimes vnode_pager_init, 97df8bae1dSRodney W. Grimes vnode_pager_alloc, 98df8bae1dSRodney W. Grimes vnode_pager_dealloc, 99df8bae1dSRodney W. Grimes vnode_pager_getpage, 10026f9a767SRodney W. Grimes vnode_pager_getmulti, 101df8bae1dSRodney W. Grimes vnode_pager_putpage, 10226f9a767SRodney W. Grimes vnode_pager_putmulti, 10326f9a767SRodney W. Grimes vnode_pager_haspage 104df8bae1dSRodney W. Grimes }; 105df8bae1dSRodney W. Grimes 10616f62314SDavid Greenman 10716f62314SDavid Greenman 10826f9a767SRodney W. Grimes static int vnode_pager_input(vn_pager_t vnp, vm_page_t * m, int count, int reqpage); 10926f9a767SRodney W. Grimes static int vnode_pager_output(vn_pager_t vnp, vm_page_t * m, int count, int *rtvals); 11026f9a767SRodney W. Grimes 11126f9a767SRodney W. Grimes extern vm_map_t pager_map; 11226f9a767SRodney W. Grimes 11326f9a767SRodney W. Grimes struct pagerlst vnode_pager_list; /* list of managed vnodes */ 11426f9a767SRodney W. Grimes 11526f9a767SRodney W. Grimes #define MAXBP (PAGE_SIZE/DEV_BSIZE); 11626f9a767SRodney W. Grimes 11726f9a767SRodney W. Grimes void 118df8bae1dSRodney W. Grimes vnode_pager_init() 119df8bae1dSRodney W. Grimes { 120df8bae1dSRodney W. Grimes TAILQ_INIT(&vnode_pager_list); 121df8bae1dSRodney W. Grimes } 122df8bae1dSRodney W. Grimes 123df8bae1dSRodney W. Grimes /* 124df8bae1dSRodney W. Grimes * Allocate (or lookup) pager for a vnode. 125df8bae1dSRodney W. Grimes * Handle is a vnode pointer. 126df8bae1dSRodney W. Grimes */ 12726f9a767SRodney W. Grimes vm_pager_t 12826f9a767SRodney W. Grimes vnode_pager_alloc(handle, size, prot, offset) 129df8bae1dSRodney W. Grimes caddr_t handle; 130df8bae1dSRodney W. Grimes vm_size_t size; 131df8bae1dSRodney W. Grimes vm_prot_t prot; 13226f9a767SRodney W. Grimes vm_offset_t offset; 133df8bae1dSRodney W. Grimes { 134df8bae1dSRodney W. Grimes register vm_pager_t pager; 135df8bae1dSRodney W. Grimes register vn_pager_t vnp; 1360d94caffSDavid Greenman vm_object_t object, tobject; 137df8bae1dSRodney W. Grimes struct vattr vattr; 138df8bae1dSRodney W. Grimes struct vnode *vp; 139df8bae1dSRodney W. Grimes struct proc *p = curproc; /* XXX */ 1400d94caffSDavid Greenman int rtval; 141df8bae1dSRodney W. Grimes 142df8bae1dSRodney W. Grimes /* 143df8bae1dSRodney W. Grimes * Pageout to vnode, no can do yet. 144df8bae1dSRodney W. Grimes */ 145df8bae1dSRodney W. Grimes if (handle == NULL) 146df8bae1dSRodney W. Grimes return (NULL); 147df8bae1dSRodney W. Grimes 148df8bae1dSRodney W. Grimes /* 149bbc0ec52SDavid Greenman * Vnodes keep a pointer to any associated pager so no need to lookup 150bbc0ec52SDavid Greenman * with vm_pager_lookup. 151df8bae1dSRodney W. Grimes */ 152df8bae1dSRodney W. Grimes vp = (struct vnode *) handle; 1530d94caffSDavid Greenman while ((object = (vm_object_t) vp->v_vmdata) && (object->flags & OBJ_DEAD)) 1540d94caffSDavid Greenman tsleep((caddr_t) object, PVM, "vadead", 0); 1550d94caffSDavid Greenman 1568e58bf68SDavid Greenman pager = NULL; 1578e58bf68SDavid Greenman if (object != NULL) 1588e58bf68SDavid Greenman pager = object->pager; 159df8bae1dSRodney W. Grimes if (pager == NULL) { 160bbc0ec52SDavid Greenman 161df8bae1dSRodney W. Grimes /* 162df8bae1dSRodney W. Grimes * Allocate pager structures 163df8bae1dSRodney W. Grimes */ 164df8bae1dSRodney W. Grimes pager = (vm_pager_t) malloc(sizeof *pager, M_VMPAGER, M_WAITOK); 165df8bae1dSRodney W. Grimes if (pager == NULL) 166df8bae1dSRodney W. Grimes return (NULL); 167df8bae1dSRodney W. Grimes vnp = (vn_pager_t) malloc(sizeof *vnp, M_VMPGDATA, M_WAITOK); 168df8bae1dSRodney W. Grimes if (vnp == NULL) { 169df8bae1dSRodney W. Grimes free((caddr_t) pager, M_VMPAGER); 170df8bae1dSRodney W. Grimes return (NULL); 171df8bae1dSRodney W. Grimes } 172df8bae1dSRodney W. Grimes /* 173df8bae1dSRodney W. Grimes * And an object of the appropriate size 174df8bae1dSRodney W. Grimes */ 1750d94caffSDavid Greenman if ((rtval = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) == 0) { 176df8bae1dSRodney W. Grimes object = vm_object_allocate(round_page(vattr.va_size)); 177df8bae1dSRodney W. Grimes vm_object_enter(object, pager); 178df8bae1dSRodney W. Grimes vm_object_setpager(object, pager, 0, TRUE); 179df8bae1dSRodney W. Grimes } else { 1800d94caffSDavid Greenman printf("Error in getattr: %d\n", rtval); 181df8bae1dSRodney W. Grimes free((caddr_t) vnp, M_VMPGDATA); 182df8bae1dSRodney W. Grimes free((caddr_t) pager, M_VMPAGER); 183df8bae1dSRodney W. Grimes return (NULL); 184df8bae1dSRodney W. Grimes } 185bbc0ec52SDavid Greenman 186df8bae1dSRodney W. Grimes /* 187df8bae1dSRodney W. Grimes * Hold a reference to the vnode and initialize pager data. 188df8bae1dSRodney W. Grimes */ 189df8bae1dSRodney W. Grimes VREF(vp); 190df8bae1dSRodney W. Grimes vnp->vnp_flags = 0; 191df8bae1dSRodney W. Grimes vnp->vnp_vp = vp; 192df8bae1dSRodney W. Grimes vnp->vnp_size = vattr.va_size; 19326f9a767SRodney W. Grimes 194df8bae1dSRodney W. Grimes TAILQ_INSERT_TAIL(&vnode_pager_list, pager, pg_list); 195df8bae1dSRodney W. Grimes pager->pg_handle = handle; 196df8bae1dSRodney W. Grimes pager->pg_type = PG_VNODE; 197df8bae1dSRodney W. Grimes pager->pg_ops = &vnodepagerops; 19826f9a767SRodney W. Grimes pager->pg_data = (caddr_t) vnp; 1998e58bf68SDavid Greenman vp->v_vmdata = (caddr_t) object; 200df8bae1dSRodney W. Grimes } else { 201bbc0ec52SDavid Greenman 202df8bae1dSRodney W. Grimes /* 203bbc0ec52SDavid Greenman * vm_object_lookup() will remove the object from the cache if 204bbc0ec52SDavid Greenman * found and also gain a reference to the object. 205df8bae1dSRodney W. Grimes */ 2068e58bf68SDavid Greenman (void) vm_object_lookup(pager); 207df8bae1dSRodney W. Grimes } 208df8bae1dSRodney W. Grimes return (pager); 209df8bae1dSRodney W. Grimes } 210df8bae1dSRodney W. Grimes 21126f9a767SRodney W. Grimes void 212df8bae1dSRodney W. Grimes vnode_pager_dealloc(pager) 213df8bae1dSRodney W. Grimes vm_pager_t pager; 214df8bae1dSRodney W. Grimes { 215df8bae1dSRodney W. Grimes register vn_pager_t vnp = (vn_pager_t) pager->pg_data; 216df8bae1dSRodney W. Grimes register struct vnode *vp; 2170d94caffSDavid Greenman vm_object_t object; 218df8bae1dSRodney W. Grimes 21905f0fdd2SPoul-Henning Kamp vp = vnp->vnp_vp; 22005f0fdd2SPoul-Henning Kamp if (vp) { 2210d94caffSDavid Greenman int s = splbio(); 2220d94caffSDavid Greenman 2230d94caffSDavid Greenman object = (vm_object_t) vp->v_vmdata; 2240d94caffSDavid Greenman if (object) { 2250d94caffSDavid Greenman while (object->paging_in_progress) { 2260d94caffSDavid Greenman tsleep(object, PVM, "vnpdea", 0); 2270d94caffSDavid Greenman } 2280d94caffSDavid Greenman } 2290d94caffSDavid Greenman splx(s); 2300d94caffSDavid Greenman 231df8bae1dSRodney W. Grimes vp->v_vmdata = NULL; 2328e58bf68SDavid Greenman vp->v_flag &= ~(VTEXT | VVMIO); 233df8bae1dSRodney W. Grimes vrele(vp); 234df8bae1dSRodney W. Grimes } 235df8bae1dSRodney W. Grimes TAILQ_REMOVE(&vnode_pager_list, pager, pg_list); 236df8bae1dSRodney W. Grimes free((caddr_t) vnp, M_VMPGDATA); 237df8bae1dSRodney W. Grimes free((caddr_t) pager, M_VMPAGER); 238df8bae1dSRodney W. Grimes } 239df8bae1dSRodney W. Grimes 24026f9a767SRodney W. Grimes int 24126f9a767SRodney W. Grimes vnode_pager_getmulti(pager, m, count, reqpage, sync) 242df8bae1dSRodney W. Grimes vm_pager_t pager; 24326f9a767SRodney W. Grimes vm_page_t *m; 24426f9a767SRodney W. Grimes int count; 24526f9a767SRodney W. Grimes int reqpage; 246df8bae1dSRodney W. Grimes boolean_t sync; 247df8bae1dSRodney W. Grimes { 248df8bae1dSRodney W. Grimes 24926f9a767SRodney W. Grimes return vnode_pager_input((vn_pager_t) pager->pg_data, m, count, reqpage); 250df8bae1dSRodney W. Grimes } 251df8bae1dSRodney W. Grimes 25226f9a767SRodney W. Grimes int 25326f9a767SRodney W. Grimes vnode_pager_getpage(pager, m, sync) 254df8bae1dSRodney W. Grimes vm_pager_t pager; 25526f9a767SRodney W. Grimes vm_page_t m; 25626f9a767SRodney W. Grimes boolean_t sync; 25726f9a767SRodney W. Grimes { 25826f9a767SRodney W. Grimes 25926f9a767SRodney W. Grimes vm_page_t marray[1]; 260bbc0ec52SDavid Greenman 26126f9a767SRodney W. Grimes if (pager == NULL) 26226f9a767SRodney W. Grimes return FALSE; 26326f9a767SRodney W. Grimes marray[0] = m; 26426f9a767SRodney W. Grimes 26526f9a767SRodney W. Grimes return vnode_pager_input((vn_pager_t) pager->pg_data, marray, 1, 0); 26626f9a767SRodney W. Grimes } 26726f9a767SRodney W. Grimes 26826f9a767SRodney W. Grimes boolean_t 26926f9a767SRodney W. Grimes vnode_pager_putpage(pager, m, sync) 27026f9a767SRodney W. Grimes vm_pager_t pager; 27126f9a767SRodney W. Grimes vm_page_t m; 272df8bae1dSRodney W. Grimes boolean_t sync; 273df8bae1dSRodney W. Grimes { 27426f9a767SRodney W. Grimes vm_page_t marray[1]; 27526f9a767SRodney W. Grimes int rtvals[1]; 276df8bae1dSRodney W. Grimes 277df8bae1dSRodney W. Grimes if (pager == NULL) 27826f9a767SRodney W. Grimes return FALSE; 27926f9a767SRodney W. Grimes marray[0] = m; 28026f9a767SRodney W. Grimes vnode_pager_output((vn_pager_t) pager->pg_data, marray, 1, rtvals); 28126f9a767SRodney W. Grimes return rtvals[0]; 282df8bae1dSRodney W. Grimes } 283df8bae1dSRodney W. Grimes 28426f9a767SRodney W. Grimes int 28526f9a767SRodney W. Grimes vnode_pager_putmulti(pager, m, c, sync, rtvals) 28626f9a767SRodney W. Grimes vm_pager_t pager; 28726f9a767SRodney W. Grimes vm_page_t *m; 28826f9a767SRodney W. Grimes int c; 28926f9a767SRodney W. Grimes boolean_t sync; 29026f9a767SRodney W. Grimes int *rtvals; 29126f9a767SRodney W. Grimes { 29226f9a767SRodney W. Grimes return vnode_pager_output((vn_pager_t) pager->pg_data, m, c, rtvals); 29326f9a767SRodney W. Grimes } 29426f9a767SRodney W. Grimes 29526f9a767SRodney W. Grimes 29626f9a767SRodney W. Grimes boolean_t 297df8bae1dSRodney W. Grimes vnode_pager_haspage(pager, offset) 298df8bae1dSRodney W. Grimes vm_pager_t pager; 299df8bae1dSRodney W. Grimes vm_offset_t offset; 300df8bae1dSRodney W. Grimes { 301df8bae1dSRodney W. Grimes register vn_pager_t vnp = (vn_pager_t) pager->pg_data; 3024abc71c0SDavid Greenman register struct vnode *vp = vnp->vnp_vp; 303df8bae1dSRodney W. Grimes daddr_t bn; 304df8bae1dSRodney W. Grimes int err; 305317205caSDavid Greenman daddr_t block; 306df8bae1dSRodney W. Grimes 307df8bae1dSRodney W. Grimes /* 3080d94caffSDavid Greenman * If filesystem no longer mounted or offset beyond end of file we do 3090d94caffSDavid Greenman * not have the page. 310df8bae1dSRodney W. Grimes */ 3114abc71c0SDavid Greenman if ((vp->v_mount == NULL) || (offset >= vnp->vnp_size)) 3124abc71c0SDavid Greenman return FALSE; 313df8bae1dSRodney W. Grimes 3144abc71c0SDavid Greenman block = offset / vp->v_mount->mnt_stat.f_iosize; 3154abc71c0SDavid Greenman if (incore(vp, block)) 316317205caSDavid Greenman return TRUE; 317df8bae1dSRodney W. Grimes /* 318bbc0ec52SDavid Greenman * Read the index to find the disk block to read from. If there is no 319bbc0ec52SDavid Greenman * block, report that we don't have this data. 320df8bae1dSRodney W. Grimes * 321df8bae1dSRodney W. Grimes * Assumes that the vnode has whole page or nothing. 322df8bae1dSRodney W. Grimes */ 3234abc71c0SDavid Greenman err = VOP_BMAP(vp, block, (struct vnode **) 0, &bn, 0); 3240d94caffSDavid Greenman if (err) 325df8bae1dSRodney W. Grimes return (TRUE); 326df8bae1dSRodney W. Grimes return ((long) bn < 0 ? FALSE : TRUE); 327df8bae1dSRodney W. Grimes } 328df8bae1dSRodney W. Grimes 329df8bae1dSRodney W. Grimes /* 330df8bae1dSRodney W. Grimes * Lets the VM system know about a change in size for a file. 331df8bae1dSRodney W. Grimes * If this vnode is mapped into some address space (i.e. we have a pager 332df8bae1dSRodney W. Grimes * for it) we adjust our own internal size and flush any cached pages in 333df8bae1dSRodney W. Grimes * the associated object that are affected by the size change. 334df8bae1dSRodney W. Grimes * 335df8bae1dSRodney W. Grimes * Note: this routine may be invoked as a result of a pager put 336df8bae1dSRodney W. Grimes * operation (possibly at object termination time), so we must be careful. 337df8bae1dSRodney W. Grimes */ 338df8bae1dSRodney W. Grimes void 339df8bae1dSRodney W. Grimes vnode_pager_setsize(vp, nsize) 340df8bae1dSRodney W. Grimes struct vnode *vp; 341df8bae1dSRodney W. Grimes u_long nsize; 342df8bae1dSRodney W. Grimes { 343df8bae1dSRodney W. Grimes register vn_pager_t vnp; 344df8bae1dSRodney W. Grimes register vm_object_t object; 345df8bae1dSRodney W. Grimes vm_pager_t pager; 346df8bae1dSRodney W. Grimes 347df8bae1dSRodney W. Grimes /* 348df8bae1dSRodney W. Grimes * Not a mapped vnode 349df8bae1dSRodney W. Grimes */ 350df8bae1dSRodney W. Grimes if (vp == NULL || vp->v_type != VREG || vp->v_vmdata == NULL) 351df8bae1dSRodney W. Grimes return; 352bbc0ec52SDavid Greenman 353df8bae1dSRodney W. Grimes /* 354df8bae1dSRodney W. Grimes * Hasn't changed size 355df8bae1dSRodney W. Grimes */ 3568e58bf68SDavid Greenman object = (vm_object_t) vp->v_vmdata; 3578e58bf68SDavid Greenman if (object == NULL) 3588e58bf68SDavid Greenman return; 3598e58bf68SDavid Greenman if ((pager = object->pager) == NULL) 3608e58bf68SDavid Greenman return; 361df8bae1dSRodney W. Grimes vnp = (vn_pager_t) pager->pg_data; 362df8bae1dSRodney W. Grimes if (nsize == vnp->vnp_size) 363df8bae1dSRodney W. Grimes return; 364bbc0ec52SDavid Greenman 365df8bae1dSRodney W. Grimes /* 366bbc0ec52SDavid Greenman * No object. This can happen during object termination since 367bbc0ec52SDavid Greenman * vm_object_page_clean is called after the object has been removed 368bbc0ec52SDavid Greenman * from the hash table, and clean may cause vnode write operations 369bbc0ec52SDavid Greenman * which can wind up back here. 370df8bae1dSRodney W. Grimes */ 371df8bae1dSRodney W. Grimes object = vm_object_lookup(pager); 372df8bae1dSRodney W. Grimes if (object == NULL) 373df8bae1dSRodney W. Grimes return; 374df8bae1dSRodney W. Grimes 375df8bae1dSRodney W. Grimes /* 376bbc0ec52SDavid Greenman * File has shrunk. Toss any cached pages beyond the new EOF. 377df8bae1dSRodney W. Grimes */ 378bbc0ec52SDavid Greenman if (nsize < vnp->vnp_size) { 3790d94caffSDavid Greenman if (round_page((vm_offset_t) nsize) < vnp->vnp_size) { 380df8bae1dSRodney W. Grimes vm_object_lock(object); 381df8bae1dSRodney W. Grimes vm_object_page_remove(object, 382bbc0ec52SDavid Greenman round_page((vm_offset_t) nsize), vnp->vnp_size); 383bbc0ec52SDavid Greenman vm_object_unlock(object); 3840d94caffSDavid Greenman } 385bbc0ec52SDavid Greenman /* 386bbc0ec52SDavid Greenman * this gets rid of garbage at the end of a page that is now 387bbc0ec52SDavid Greenman * only partially backed by the vnode... 388bbc0ec52SDavid Greenman */ 389bbc0ec52SDavid Greenman if (nsize & PAGE_MASK) { 390bbc0ec52SDavid Greenman vm_offset_t kva; 391bbc0ec52SDavid Greenman vm_page_t m; 392bbc0ec52SDavid Greenman 393bbc0ec52SDavid Greenman m = vm_page_lookup(object, trunc_page((vm_offset_t) nsize)); 394bbc0ec52SDavid Greenman if (m) { 395bbc0ec52SDavid Greenman kva = vm_pager_map_page(m); 396bbc0ec52SDavid Greenman bzero((caddr_t) kva + (nsize & PAGE_MASK), 397bbc0ec52SDavid Greenman round_page(nsize) - nsize); 398bbc0ec52SDavid Greenman vm_pager_unmap_page(kva); 399bbc0ec52SDavid Greenman } 400bbc0ec52SDavid Greenman } 401bbc0ec52SDavid Greenman } 402df8bae1dSRodney W. Grimes vnp->vnp_size = (vm_offset_t) nsize; 403bbc0ec52SDavid Greenman object->size = round_page(nsize); 404bbc0ec52SDavid Greenman 405df8bae1dSRodney W. Grimes vm_object_deallocate(object); 406df8bae1dSRodney W. Grimes } 407df8bae1dSRodney W. Grimes 408df8bae1dSRodney W. Grimes void 409df8bae1dSRodney W. Grimes vnode_pager_umount(mp) 410df8bae1dSRodney W. Grimes register struct mount *mp; 411df8bae1dSRodney W. Grimes { 412df8bae1dSRodney W. Grimes register vm_pager_t pager, npager; 413df8bae1dSRodney W. Grimes struct vnode *vp; 414df8bae1dSRodney W. Grimes 41526f9a767SRodney W. Grimes pager = vnode_pager_list.tqh_first; 41626f9a767SRodney W. Grimes while (pager) { 417bbc0ec52SDavid Greenman 418df8bae1dSRodney W. Grimes /* 419bbc0ec52SDavid Greenman * Save the next pointer now since uncaching may terminate the 420bbc0ec52SDavid Greenman * object and render pager invalid 421df8bae1dSRodney W. Grimes */ 422df8bae1dSRodney W. Grimes vp = ((vn_pager_t) pager->pg_data)->vnp_vp; 42326f9a767SRodney W. Grimes npager = pager->pg_list.tqe_next; 42426f9a767SRodney W. Grimes if (mp == (struct mount *) 0 || vp->v_mount == mp) 425df8bae1dSRodney W. Grimes (void) vnode_pager_uncache(vp); 42626f9a767SRodney W. Grimes pager = npager; 427df8bae1dSRodney W. Grimes } 428df8bae1dSRodney W. Grimes } 429df8bae1dSRodney W. Grimes 430df8bae1dSRodney W. Grimes /* 431df8bae1dSRodney W. Grimes * Remove vnode associated object from the object cache. 432df8bae1dSRodney W. Grimes * 43326f9a767SRodney W. Grimes * Note: this routine may be invoked as a result of a pager put 43426f9a767SRodney W. Grimes * operation (possibly at object termination time), so we must be careful. 43526f9a767SRodney W. Grimes */ 43626f9a767SRodney W. Grimes boolean_t 43726f9a767SRodney W. Grimes vnode_pager_uncache(vp) 43826f9a767SRodney W. Grimes register struct vnode *vp; 43926f9a767SRodney W. Grimes { 44026f9a767SRodney W. Grimes register vm_object_t object; 44126f9a767SRodney W. Grimes boolean_t uncached, locked; 44226f9a767SRodney W. Grimes vm_pager_t pager; 44326f9a767SRodney W. Grimes 44426f9a767SRodney W. Grimes /* 44526f9a767SRodney W. Grimes * Not a mapped vnode 44626f9a767SRodney W. Grimes */ 4478e58bf68SDavid Greenman object = (vm_object_t) vp->v_vmdata; 4488e58bf68SDavid Greenman if (object == NULL) 4498e58bf68SDavid Greenman return (TRUE); 4500d94caffSDavid Greenman 4518e58bf68SDavid Greenman pager = object->pager; 45226f9a767SRodney W. Grimes if (pager == NULL) 45326f9a767SRodney W. Grimes return (TRUE); 454bbc0ec52SDavid Greenman 45526f9a767SRodney W. Grimes /* 456bbc0ec52SDavid Greenman * Unlock the vnode if it is currently locked. We do this since 457bbc0ec52SDavid Greenman * uncaching the object may result in its destruction which may 458bbc0ec52SDavid Greenman * initiate paging activity which may necessitate locking the vnode. 45926f9a767SRodney W. Grimes */ 46026f9a767SRodney W. Grimes locked = VOP_ISLOCKED(vp); 46126f9a767SRodney W. Grimes if (locked) 46226f9a767SRodney W. Grimes VOP_UNLOCK(vp); 463bbc0ec52SDavid Greenman 46426f9a767SRodney W. Grimes /* 465bbc0ec52SDavid Greenman * Must use vm_object_lookup() as it actually removes the object from 466bbc0ec52SDavid Greenman * the cache list. 46726f9a767SRodney W. Grimes */ 46826f9a767SRodney W. Grimes object = vm_object_lookup(pager); 46926f9a767SRodney W. Grimes if (object) { 47026f9a767SRodney W. Grimes uncached = (object->ref_count <= 1); 47126f9a767SRodney W. Grimes pager_cache(object, FALSE); 47226f9a767SRodney W. Grimes } else 47326f9a767SRodney W. Grimes uncached = TRUE; 47426f9a767SRodney W. Grimes if (locked) 47526f9a767SRodney W. Grimes VOP_LOCK(vp); 47626f9a767SRodney W. Grimes return (uncached); 47726f9a767SRodney W. Grimes } 478df8bae1dSRodney W. Grimes 47926f9a767SRodney W. Grimes 48026f9a767SRodney W. Grimes void 48126f9a767SRodney W. Grimes vnode_pager_freepage(m) 48226f9a767SRodney W. Grimes vm_page_t m; 483df8bae1dSRodney W. Grimes { 48426f9a767SRodney W. Grimes PAGE_WAKEUP(m); 48526f9a767SRodney W. Grimes vm_page_free(m); 48626f9a767SRodney W. Grimes } 48726f9a767SRodney W. Grimes 48826f9a767SRodney W. Grimes /* 48926f9a767SRodney W. Grimes * calculate the linear (byte) disk address of specified virtual 49026f9a767SRodney W. Grimes * file address 49126f9a767SRodney W. Grimes */ 49226f9a767SRodney W. Grimes vm_offset_t 49326f9a767SRodney W. Grimes vnode_pager_addr(vp, address) 49426f9a767SRodney W. Grimes struct vnode *vp; 49526f9a767SRodney W. Grimes vm_offset_t address; 49626f9a767SRodney W. Grimes { 49726f9a767SRodney W. Grimes int rtaddress; 49826f9a767SRodney W. Grimes int bsize; 49926f9a767SRodney W. Grimes vm_offset_t block; 50026f9a767SRodney W. Grimes struct vnode *rtvp; 50126f9a767SRodney W. Grimes int err; 50226f9a767SRodney W. Grimes int vblock, voffset; 50326f9a767SRodney W. Grimes 5040d94caffSDavid Greenman if ((int) address < 0) 5050d94caffSDavid Greenman return -1; 5060d94caffSDavid Greenman 50726f9a767SRodney W. Grimes bsize = vp->v_mount->mnt_stat.f_iosize; 50826f9a767SRodney W. Grimes vblock = address / bsize; 50926f9a767SRodney W. Grimes voffset = address % bsize; 51026f9a767SRodney W. Grimes 51126f9a767SRodney W. Grimes err = VOP_BMAP(vp, vblock, &rtvp, &block, 0); 51226f9a767SRodney W. Grimes 51326f9a767SRodney W. Grimes if (err) 51426f9a767SRodney W. Grimes rtaddress = -1; 51526f9a767SRodney W. Grimes else 51626f9a767SRodney W. Grimes rtaddress = block * DEV_BSIZE + voffset; 51726f9a767SRodney W. Grimes 51826f9a767SRodney W. Grimes return rtaddress; 51926f9a767SRodney W. Grimes } 52026f9a767SRodney W. Grimes 52126f9a767SRodney W. Grimes /* 52226f9a767SRodney W. Grimes * interrupt routine for I/O completion 52326f9a767SRodney W. Grimes */ 52426f9a767SRodney W. Grimes void 52526f9a767SRodney W. Grimes vnode_pager_iodone(bp) 52626f9a767SRodney W. Grimes struct buf *bp; 52726f9a767SRodney W. Grimes { 52826f9a767SRodney W. Grimes bp->b_flags |= B_DONE; 52926f9a767SRodney W. Grimes wakeup((caddr_t) bp); 53016f62314SDavid Greenman if (bp->b_flags & B_ASYNC) { 53116f62314SDavid Greenman vm_offset_t paddr; 53216f62314SDavid Greenman vm_page_t m; 53316f62314SDavid Greenman vm_object_t obj = 0; 53416f62314SDavid Greenman int i; 53516f62314SDavid Greenman int npages; 53616f62314SDavid Greenman 53716f62314SDavid Greenman paddr = (vm_offset_t) bp->b_data; 53816f62314SDavid Greenman if (bp->b_bufsize != bp->b_bcount) 53916f62314SDavid Greenman bzero(bp->b_data + bp->b_bcount, 54016f62314SDavid Greenman bp->b_bufsize - bp->b_bcount); 54116f62314SDavid Greenman 54216f62314SDavid Greenman npages = (bp->b_bufsize + PAGE_SIZE - 1) / PAGE_SIZE; 54316f62314SDavid Greenman for (i = 0; i < npages; i++) { 54416f62314SDavid Greenman m = PHYS_TO_VM_PAGE(pmap_kextract(paddr + i * PAGE_SIZE)); 54516f62314SDavid Greenman obj = m->object; 54616f62314SDavid Greenman if (m) { 5470d94caffSDavid Greenman m->dirty = 0; 5480d94caffSDavid Greenman m->valid = VM_PAGE_BITS_ALL; 5490d94caffSDavid Greenman if (m->flags & PG_WANTED) 5500d94caffSDavid Greenman m->flags |= PG_REFERENCED; 55116f62314SDavid Greenman PAGE_WAKEUP(m); 55216f62314SDavid Greenman } else { 55316f62314SDavid Greenman panic("vnode_pager_iodone: page is gone!!!"); 55416f62314SDavid Greenman } 55516f62314SDavid Greenman } 556a481f200SDavid Greenman pmap_qremove(paddr, npages); 55716f62314SDavid Greenman if (obj) { 55816f62314SDavid Greenman --obj->paging_in_progress; 55916f62314SDavid Greenman if (obj->paging_in_progress == 0) 56016f62314SDavid Greenman wakeup((caddr_t) obj); 56116f62314SDavid Greenman } else { 56216f62314SDavid Greenman panic("vnode_pager_iodone: object is gone???"); 56316f62314SDavid Greenman } 56416f62314SDavid Greenman relpbuf(bp); 56516f62314SDavid Greenman } 56626f9a767SRodney W. Grimes } 56726f9a767SRodney W. Grimes 56826f9a767SRodney W. Grimes /* 56926f9a767SRodney W. Grimes * small block file system vnode pager input 57026f9a767SRodney W. Grimes */ 57126f9a767SRodney W. Grimes int 57226f9a767SRodney W. Grimes vnode_pager_input_smlfs(vnp, m) 57326f9a767SRodney W. Grimes vn_pager_t vnp; 57426f9a767SRodney W. Grimes vm_page_t m; 57526f9a767SRodney W. Grimes { 57626f9a767SRodney W. Grimes int i; 57726f9a767SRodney W. Grimes int s; 57826f9a767SRodney W. Grimes struct vnode *dp, *vp; 57926f9a767SRodney W. Grimes struct buf *bp; 58026f9a767SRodney W. Grimes vm_offset_t kva; 58126f9a767SRodney W. Grimes int fileaddr; 58226f9a767SRodney W. Grimes int block; 58326f9a767SRodney W. Grimes vm_offset_t bsize; 58426f9a767SRodney W. Grimes int error = 0; 58526f9a767SRodney W. Grimes 58626f9a767SRodney W. Grimes vp = vnp->vnp_vp; 58726f9a767SRodney W. Grimes bsize = vp->v_mount->mnt_stat.f_iosize; 58826f9a767SRodney W. Grimes 5890d94caffSDavid Greenman VOP_BMAP(vp, 0, &dp, 0, 0); 59026f9a767SRodney W. Grimes 59126f9a767SRodney W. Grimes kva = vm_pager_map_page(m); 59226f9a767SRodney W. Grimes 59326f9a767SRodney W. Grimes for (i = 0; i < PAGE_SIZE / bsize; i++) { 594bbc0ec52SDavid Greenman 5950d94caffSDavid Greenman if ((vm_page_bits(m->offset + i * bsize, bsize) & m->valid)) 59626f9a767SRodney W. Grimes continue; 59726f9a767SRodney W. Grimes 5980d94caffSDavid Greenman fileaddr = vnode_pager_addr(vp, m->offset + i * bsize); 59926f9a767SRodney W. Grimes if (fileaddr != -1) { 60026f9a767SRodney W. Grimes bp = getpbuf(); 60126f9a767SRodney W. Grimes 60226f9a767SRodney W. Grimes /* build a minimal buffer header */ 60326f9a767SRodney W. Grimes bp->b_flags = B_BUSY | B_READ | B_CALL; 60426f9a767SRodney W. Grimes bp->b_iodone = vnode_pager_iodone; 60526f9a767SRodney W. Grimes bp->b_proc = curproc; 60626f9a767SRodney W. Grimes bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred; 60726f9a767SRodney W. Grimes if (bp->b_rcred != NOCRED) 60826f9a767SRodney W. Grimes crhold(bp->b_rcred); 60926f9a767SRodney W. Grimes if (bp->b_wcred != NOCRED) 61026f9a767SRodney W. Grimes crhold(bp->b_wcred); 61126f9a767SRodney W. Grimes bp->b_un.b_addr = (caddr_t) kva + i * bsize; 61226f9a767SRodney W. Grimes bp->b_blkno = fileaddr / DEV_BSIZE; 6130d94caffSDavid Greenman pbgetvp(dp, bp); 61426f9a767SRodney W. Grimes bp->b_bcount = bsize; 61526f9a767SRodney W. Grimes bp->b_bufsize = bsize; 61626f9a767SRodney W. Grimes 61726f9a767SRodney W. Grimes /* do the input */ 61826f9a767SRodney W. Grimes VOP_STRATEGY(bp); 61926f9a767SRodney W. Grimes 62026f9a767SRodney W. Grimes /* we definitely need to be at splbio here */ 62126f9a767SRodney W. Grimes 62226f9a767SRodney W. Grimes s = splbio(); 62326f9a767SRodney W. Grimes while ((bp->b_flags & B_DONE) == 0) { 62426f9a767SRodney W. Grimes tsleep((caddr_t) bp, PVM, "vnsrd", 0); 62526f9a767SRodney W. Grimes } 62626f9a767SRodney W. Grimes splx(s); 62726f9a767SRodney W. Grimes if ((bp->b_flags & B_ERROR) != 0) 62826f9a767SRodney W. Grimes error = EIO; 62926f9a767SRodney W. Grimes 63026f9a767SRodney W. Grimes /* 63126f9a767SRodney W. Grimes * free the buffer header back to the swap buffer pool 63226f9a767SRodney W. Grimes */ 63326f9a767SRodney W. Grimes relpbuf(bp); 63426f9a767SRodney W. Grimes HOLDRELE(vp); 63526f9a767SRodney W. Grimes if (error) 63626f9a767SRodney W. Grimes break; 6370d94caffSDavid Greenman 6380d94caffSDavid Greenman vm_page_set_clean(m, i * bsize, bsize); 6390d94caffSDavid Greenman vm_page_set_valid(m, i * bsize, bsize); 64026f9a767SRodney W. Grimes } else { 6410d94caffSDavid Greenman vm_page_set_clean(m, i * bsize, bsize); 64226f9a767SRodney W. Grimes bzero((caddr_t) kva + i * bsize, bsize); 64326f9a767SRodney W. Grimes } 64426f9a767SRodney W. Grimes nextblock: 64526f9a767SRodney W. Grimes } 64626f9a767SRodney W. Grimes vm_pager_unmap_page(kva); 6470d94caffSDavid Greenman pmap_clear_modify(VM_PAGE_TO_PHYS(m)); 64826f9a767SRodney W. Grimes if (error) { 649a83c285cSDavid Greenman return VM_PAGER_ERROR; 65026f9a767SRodney W. Grimes } 65126f9a767SRodney W. Grimes return VM_PAGER_OK; 65226f9a767SRodney W. Grimes 65326f9a767SRodney W. Grimes } 65426f9a767SRodney W. Grimes 65526f9a767SRodney W. Grimes 65626f9a767SRodney W. Grimes /* 65726f9a767SRodney W. Grimes * old style vnode pager output routine 65826f9a767SRodney W. Grimes */ 65926f9a767SRodney W. Grimes int 66026f9a767SRodney W. Grimes vnode_pager_input_old(vnp, m) 66126f9a767SRodney W. Grimes vn_pager_t vnp; 66226f9a767SRodney W. Grimes vm_page_t m; 66326f9a767SRodney W. Grimes { 664df8bae1dSRodney W. Grimes struct uio auio; 665df8bae1dSRodney W. Grimes struct iovec aiov; 66626f9a767SRodney W. Grimes int error; 66726f9a767SRodney W. Grimes int size; 66826f9a767SRodney W. Grimes vm_offset_t kva; 669df8bae1dSRodney W. Grimes 67026f9a767SRodney W. Grimes error = 0; 671bbc0ec52SDavid Greenman 672df8bae1dSRodney W. Grimes /* 67326f9a767SRodney W. Grimes * Return failure if beyond current EOF 67426f9a767SRodney W. Grimes */ 6750d94caffSDavid Greenman if (m->offset >= vnp->vnp_size) { 67626f9a767SRodney W. Grimes return VM_PAGER_BAD; 67726f9a767SRodney W. Grimes } else { 67826f9a767SRodney W. Grimes size = PAGE_SIZE; 6790d94caffSDavid Greenman if (m->offset + size > vnp->vnp_size) 6800d94caffSDavid Greenman size = vnp->vnp_size - m->offset; 68126f9a767SRodney W. Grimes /* 682df8bae1dSRodney W. Grimes * Allocate a kernel virtual address and initialize so that 683df8bae1dSRodney W. Grimes * we can use VOP_READ/WRITE routines. 684df8bae1dSRodney W. Grimes */ 68526f9a767SRodney W. Grimes kva = vm_pager_map_page(m); 686df8bae1dSRodney W. Grimes aiov.iov_base = (caddr_t) kva; 687df8bae1dSRodney W. Grimes aiov.iov_len = size; 688df8bae1dSRodney W. Grimes auio.uio_iov = &aiov; 689df8bae1dSRodney W. Grimes auio.uio_iovcnt = 1; 6900d94caffSDavid Greenman auio.uio_offset = m->offset; 691df8bae1dSRodney W. Grimes auio.uio_segflg = UIO_SYSSPACE; 69226f9a767SRodney W. Grimes auio.uio_rw = UIO_READ; 693df8bae1dSRodney W. Grimes auio.uio_resid = size; 694df8bae1dSRodney W. Grimes auio.uio_procp = (struct proc *) 0; 69526f9a767SRodney W. Grimes 69626f9a767SRodney W. Grimes error = VOP_READ(vnp->vnp_vp, &auio, 0, curproc->p_ucred); 697df8bae1dSRodney W. Grimes if (!error) { 698df8bae1dSRodney W. Grimes register int count = size - auio.uio_resid; 699df8bae1dSRodney W. Grimes 700df8bae1dSRodney W. Grimes if (count == 0) 701df8bae1dSRodney W. Grimes error = EINVAL; 70226f9a767SRodney W. Grimes else if (count != PAGE_SIZE) 70326f9a767SRodney W. Grimes bzero((caddr_t) kva + count, PAGE_SIZE - count); 704df8bae1dSRodney W. Grimes } 70526f9a767SRodney W. Grimes vm_pager_unmap_page(kva); 706df8bae1dSRodney W. Grimes } 70726f9a767SRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(m)); 7080d94caffSDavid Greenman m->dirty = 0; 709a83c285cSDavid Greenman return error ? VM_PAGER_ERROR : VM_PAGER_OK; 71026f9a767SRodney W. Grimes } 71126f9a767SRodney W. Grimes 71226f9a767SRodney W. Grimes /* 71326f9a767SRodney W. Grimes * generic vnode pager input routine 71426f9a767SRodney W. Grimes */ 71526f9a767SRodney W. Grimes int 71626f9a767SRodney W. Grimes vnode_pager_input(vnp, m, count, reqpage) 71726f9a767SRodney W. Grimes register vn_pager_t vnp; 71826f9a767SRodney W. Grimes vm_page_t *m; 71926f9a767SRodney W. Grimes int count, reqpage; 72026f9a767SRodney W. Grimes { 72105f0fdd2SPoul-Henning Kamp int i; 72226f9a767SRodney W. Grimes vm_offset_t kva, foff; 72316f62314SDavid Greenman int size, sizea; 72426f9a767SRodney W. Grimes vm_object_t object; 72526f9a767SRodney W. Grimes struct vnode *dp, *vp; 72626f9a767SRodney W. Grimes int bsize; 72726f9a767SRodney W. Grimes 72826f9a767SRodney W. Grimes int first, last; 72926f9a767SRodney W. Grimes int reqaddr, firstaddr; 73026f9a767SRodney W. Grimes int block, offset; 73126f9a767SRodney W. Grimes 73216f62314SDavid Greenman struct buf *bp, *bpa; 73316f62314SDavid Greenman int counta; 73426f9a767SRodney W. Grimes int s; 73526f9a767SRodney W. Grimes int failflag; 73626f9a767SRodney W. Grimes 73726f9a767SRodney W. Grimes int error = 0; 73826f9a767SRodney W. Grimes 739bbc0ec52SDavid Greenman object = m[reqpage]->object; /* all vm_page_t items are in same 740bbc0ec52SDavid Greenman * object */ 74126f9a767SRodney W. Grimes 74226f9a767SRodney W. Grimes vp = vnp->vnp_vp; 74326f9a767SRodney W. Grimes bsize = vp->v_mount->mnt_stat.f_iosize; 74426f9a767SRodney W. Grimes 74526f9a767SRodney W. Grimes /* get the UNDERLYING device for the file with VOP_BMAP() */ 746bbc0ec52SDavid Greenman 74726f9a767SRodney W. Grimes /* 748bbc0ec52SDavid Greenman * originally, we did not check for an error return value -- assuming 749bbc0ec52SDavid Greenman * an fs always has a bmap entry point -- that assumption is wrong!!! 75026f9a767SRodney W. Grimes */ 7510d94caffSDavid Greenman foff = m[reqpage]->offset; 752bbc0ec52SDavid Greenman 75326f9a767SRodney W. Grimes /* 75416f62314SDavid Greenman * if we can't bmap, use old VOP code 75526f9a767SRodney W. Grimes */ 7560d94caffSDavid Greenman if (VOP_BMAP(vp, 0, &dp, 0, 0)) { 75726f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 75826f9a767SRodney W. Grimes if (i != reqpage) { 75926f9a767SRodney W. Grimes vnode_pager_freepage(m[i]); 76026f9a767SRodney W. Grimes } 76126f9a767SRodney W. Grimes } 762976e77fcSDavid Greenman cnt.v_vnodein++; 763976e77fcSDavid Greenman cnt.v_vnodepgsin++; 76426f9a767SRodney W. Grimes return vnode_pager_input_old(vnp, m[reqpage]); 765bbc0ec52SDavid Greenman 76626f9a767SRodney W. Grimes /* 76726f9a767SRodney W. Grimes * if the blocksize is smaller than a page size, then use 76826f9a767SRodney W. Grimes * special small filesystem code. NFS sometimes has a small 76926f9a767SRodney W. Grimes * blocksize, but it can handle large reads itself. 77026f9a767SRodney W. Grimes */ 77126f9a767SRodney W. Grimes } else if ((PAGE_SIZE / bsize) > 1 && 77226f9a767SRodney W. Grimes (vp->v_mount->mnt_stat.f_type != MOUNT_NFS)) { 77326f9a767SRodney W. Grimes 77426f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 77526f9a767SRodney W. Grimes if (i != reqpage) { 77626f9a767SRodney W. Grimes vnode_pager_freepage(m[i]); 77726f9a767SRodney W. Grimes } 77826f9a767SRodney W. Grimes } 779976e77fcSDavid Greenman cnt.v_vnodein++; 780976e77fcSDavid Greenman cnt.v_vnodepgsin++; 78126f9a767SRodney W. Grimes return vnode_pager_input_smlfs(vnp, m[reqpage]); 78226f9a767SRodney W. Grimes } 78326f9a767SRodney W. Grimes /* 7840d94caffSDavid Greenman * if ANY DEV_BSIZE blocks are valid on a large filesystem block 7850d94caffSDavid Greenman * then, the entire page is valid -- 7860d94caffSDavid Greenman */ 7870d94caffSDavid Greenman if (m[reqpage]->valid) { 7880d94caffSDavid Greenman m[reqpage]->valid = VM_PAGE_BITS_ALL; 7890d94caffSDavid Greenman for (i = 0; i < count; i++) { 7900d94caffSDavid Greenman if (i != reqpage) 7910d94caffSDavid Greenman vnode_pager_freepage(m[i]); 7920d94caffSDavid Greenman } 7930d94caffSDavid Greenman return VM_PAGER_OK; 7940d94caffSDavid Greenman } 7950d94caffSDavid Greenman /* 79626f9a767SRodney W. Grimes * here on direct device I/O 79726f9a767SRodney W. Grimes */ 79826f9a767SRodney W. Grimes 79926f9a767SRodney W. Grimes reqaddr = vnode_pager_addr(vp, foff); 8000d94caffSDavid Greenman if (reqaddr == -1 && foff < vnp->vnp_size) { 8010d94caffSDavid Greenman printf("reqaddr: %d, foff: %d, vnp_size: %d\n", 8020d94caffSDavid Greenman reqaddr, foff, vnp->vnp_size); 8030d94caffSDavid Greenman Debugger(""); 8040d94caffSDavid Greenman } 80526f9a767SRodney W. Grimes s = splbio(); 806bbc0ec52SDavid Greenman 80726f9a767SRodney W. Grimes /* 808bbc0ec52SDavid Greenman * Make sure that our I/O request is contiguous. Scan backward and 809bbc0ec52SDavid Greenman * stop for the first discontiguous entry or stop for a page being in 810bbc0ec52SDavid Greenman * buffer cache. 81126f9a767SRodney W. Grimes */ 81226f9a767SRodney W. Grimes failflag = 0; 81326f9a767SRodney W. Grimes first = reqpage; 81426f9a767SRodney W. Grimes for (i = reqpage - 1; i >= 0; --i) { 81526f9a767SRodney W. Grimes if (failflag || 8160d94caffSDavid Greenman (vnode_pager_addr(vp, m[i]->offset)) 81726f9a767SRodney W. Grimes != reqaddr + (i - reqpage) * PAGE_SIZE) { 81826f9a767SRodney W. Grimes vnode_pager_freepage(m[i]); 81926f9a767SRodney W. Grimes failflag = 1; 82026f9a767SRodney W. Grimes } else { 82126f9a767SRodney W. Grimes first = i; 82226f9a767SRodney W. Grimes } 82326f9a767SRodney W. Grimes } 82426f9a767SRodney W. Grimes 82526f9a767SRodney W. Grimes /* 826bbc0ec52SDavid Greenman * Scan forward and stop for the first non-contiguous entry or stop 827bbc0ec52SDavid Greenman * for a page being in buffer cache. 82826f9a767SRodney W. Grimes */ 82926f9a767SRodney W. Grimes failflag = 0; 83026f9a767SRodney W. Grimes last = reqpage + 1; 83126f9a767SRodney W. Grimes for (i = reqpage + 1; i < count; i++) { 83226f9a767SRodney W. Grimes if (failflag || 8330d94caffSDavid Greenman (vnode_pager_addr(vp, m[i]->offset)) 83426f9a767SRodney W. Grimes != reqaddr + (i - reqpage) * PAGE_SIZE) { 83526f9a767SRodney W. Grimes vnode_pager_freepage(m[i]); 83626f9a767SRodney W. Grimes failflag = 1; 83726f9a767SRodney W. Grimes } else { 83826f9a767SRodney W. Grimes last = i + 1; 83926f9a767SRodney W. Grimes } 84026f9a767SRodney W. Grimes } 84126f9a767SRodney W. Grimes splx(s); 84226f9a767SRodney W. Grimes 84326f9a767SRodney W. Grimes /* 844bbc0ec52SDavid Greenman * the first and last page have been calculated now, move input pages 845bbc0ec52SDavid Greenman * to be zero based... 84626f9a767SRodney W. Grimes */ 84726f9a767SRodney W. Grimes count = last; 84826f9a767SRodney W. Grimes if (first != 0) { 84926f9a767SRodney W. Grimes for (i = first; i < count; i++) { 85026f9a767SRodney W. Grimes m[i - first] = m[i]; 85126f9a767SRodney W. Grimes } 85226f9a767SRodney W. Grimes count -= first; 85326f9a767SRodney W. Grimes reqpage -= first; 85426f9a767SRodney W. Grimes } 85526f9a767SRodney W. Grimes /* 85626f9a767SRodney W. Grimes * calculate the file virtual address for the transfer 85726f9a767SRodney W. Grimes */ 8580d94caffSDavid Greenman foff = m[0]->offset; 859bbc0ec52SDavid Greenman 86026f9a767SRodney W. Grimes /* 86126f9a767SRodney W. Grimes * and get the disk physical address (in bytes) 86226f9a767SRodney W. Grimes */ 86326f9a767SRodney W. Grimes firstaddr = vnode_pager_addr(vp, foff); 86426f9a767SRodney W. Grimes 86526f9a767SRodney W. Grimes /* 86626f9a767SRodney W. Grimes * calculate the size of the transfer 86726f9a767SRodney W. Grimes */ 86826f9a767SRodney W. Grimes size = count * PAGE_SIZE; 86926f9a767SRodney W. Grimes if ((foff + size) > vnp->vnp_size) 87026f9a767SRodney W. Grimes size = vnp->vnp_size - foff; 87126f9a767SRodney W. Grimes 87226f9a767SRodney W. Grimes /* 87326f9a767SRodney W. Grimes * round up physical size for real devices 87426f9a767SRodney W. Grimes */ 87526f9a767SRodney W. Grimes if (dp->v_type == VBLK || dp->v_type == VCHR) 87626f9a767SRodney W. Grimes size = (size + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1); 87726f9a767SRodney W. Grimes 87816f62314SDavid Greenman counta = 0; 87916f62314SDavid Greenman if (count * PAGE_SIZE > bsize) 88016f62314SDavid Greenman counta = (count - reqpage) - 1; 88116f62314SDavid Greenman bpa = 0; 88216f62314SDavid Greenman sizea = 0; 88316f62314SDavid Greenman if (counta) { 88416f62314SDavid Greenman bpa = getpbuf(); 88516f62314SDavid Greenman count -= counta; 88616f62314SDavid Greenman sizea = size - count * PAGE_SIZE; 88716f62314SDavid Greenman size = count * PAGE_SIZE; 88816f62314SDavid Greenman } 88916f62314SDavid Greenman bp = getpbuf(); 89016f62314SDavid Greenman kva = (vm_offset_t) bp->b_data; 89116f62314SDavid Greenman 89226f9a767SRodney W. Grimes /* 89326f9a767SRodney W. Grimes * and map the pages to be read into the kva 89426f9a767SRodney W. Grimes */ 89516f62314SDavid Greenman pmap_qenter(kva, m, count); 89626f9a767SRodney W. Grimes 89726f9a767SRodney W. Grimes /* build a minimal buffer header */ 89826f9a767SRodney W. Grimes bp->b_flags = B_BUSY | B_READ | B_CALL; 89926f9a767SRodney W. Grimes bp->b_iodone = vnode_pager_iodone; 90026f9a767SRodney W. Grimes /* B_PHYS is not set, but it is nice to fill this in */ 90126f9a767SRodney W. Grimes bp->b_proc = curproc; 90226f9a767SRodney W. Grimes bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred; 90326f9a767SRodney W. Grimes if (bp->b_rcred != NOCRED) 90426f9a767SRodney W. Grimes crhold(bp->b_rcred); 90526f9a767SRodney W. Grimes if (bp->b_wcred != NOCRED) 90626f9a767SRodney W. Grimes crhold(bp->b_wcred); 90726f9a767SRodney W. Grimes bp->b_blkno = firstaddr / DEV_BSIZE; 9080d94caffSDavid Greenman pbgetvp(dp, bp); 90926f9a767SRodney W. Grimes bp->b_bcount = size; 91026f9a767SRodney W. Grimes bp->b_bufsize = size; 91126f9a767SRodney W. Grimes 912976e77fcSDavid Greenman cnt.v_vnodein++; 913976e77fcSDavid Greenman cnt.v_vnodepgsin += count; 914976e77fcSDavid Greenman 91526f9a767SRodney W. Grimes /* do the input */ 91626f9a767SRodney W. Grimes VOP_STRATEGY(bp); 917976e77fcSDavid Greenman 91816f62314SDavid Greenman if (counta) { 91916f62314SDavid Greenman for (i = 0; i < counta; i++) { 92016f62314SDavid Greenman vm_page_deactivate(m[count + i]); 92116f62314SDavid Greenman } 922c87801feSDavid Greenman pmap_qenter((vm_offset_t) bpa->b_data, &m[count], counta); 92316f62314SDavid Greenman ++m[count]->object->paging_in_progress; 92416f62314SDavid Greenman bpa->b_flags = B_BUSY | B_READ | B_CALL | B_ASYNC; 92516f62314SDavid Greenman bpa->b_iodone = vnode_pager_iodone; 92616f62314SDavid Greenman /* B_PHYS is not set, but it is nice to fill this in */ 92716f62314SDavid Greenman bpa->b_proc = curproc; 92816f62314SDavid Greenman bpa->b_rcred = bpa->b_wcred = bpa->b_proc->p_ucred; 92916f62314SDavid Greenman if (bpa->b_rcred != NOCRED) 93016f62314SDavid Greenman crhold(bpa->b_rcred); 93116f62314SDavid Greenman if (bpa->b_wcred != NOCRED) 93216f62314SDavid Greenman crhold(bpa->b_wcred); 93316f62314SDavid Greenman bpa->b_blkno = (firstaddr + count * PAGE_SIZE) / DEV_BSIZE; 9340d94caffSDavid Greenman pbgetvp(dp, bpa); 93516f62314SDavid Greenman bpa->b_bcount = sizea; 93616f62314SDavid Greenman bpa->b_bufsize = counta * PAGE_SIZE; 93716f62314SDavid Greenman 938976e77fcSDavid Greenman cnt.v_vnodepgsin += counta; 93916f62314SDavid Greenman VOP_STRATEGY(bpa); 94016f62314SDavid Greenman } 94126f9a767SRodney W. Grimes s = splbio(); 94226f9a767SRodney W. Grimes /* we definitely need to be at splbio here */ 94326f9a767SRodney W. Grimes 94426f9a767SRodney W. Grimes while ((bp->b_flags & B_DONE) == 0) { 94526f9a767SRodney W. Grimes tsleep((caddr_t) bp, PVM, "vnread", 0); 94626f9a767SRodney W. Grimes } 94726f9a767SRodney W. Grimes splx(s); 94826f9a767SRodney W. Grimes if ((bp->b_flags & B_ERROR) != 0) 94926f9a767SRodney W. Grimes error = EIO; 95026f9a767SRodney W. Grimes 95126f9a767SRodney W. Grimes if (!error) { 95226f9a767SRodney W. Grimes if (size != count * PAGE_SIZE) 95326f9a767SRodney W. Grimes bzero((caddr_t) kva + size, PAGE_SIZE * count - size); 95426f9a767SRodney W. Grimes } 95516f62314SDavid Greenman pmap_qremove(kva, count); 95626f9a767SRodney W. Grimes 95726f9a767SRodney W. Grimes /* 95826f9a767SRodney W. Grimes * free the buffer header back to the swap buffer pool 95926f9a767SRodney W. Grimes */ 96026f9a767SRodney W. Grimes relpbuf(bp); 96126f9a767SRodney W. Grimes HOLDRELE(vp); 96226f9a767SRodney W. Grimes 96326f9a767SRodney W. Grimes finishup: 96426f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 965fff93ab6SDavid Greenman pmap_clear_modify(VM_PAGE_TO_PHYS(m[i])); 9660d94caffSDavid Greenman m[i]->dirty = 0; 9670d94caffSDavid Greenman m[i]->valid = VM_PAGE_BITS_ALL; 96826f9a767SRodney W. Grimes if (i != reqpage) { 969bbc0ec52SDavid Greenman 97026f9a767SRodney W. Grimes /* 971bbc0ec52SDavid Greenman * whether or not to leave the page activated is up in 972bbc0ec52SDavid Greenman * the air, but we should put the page on a page queue 973bbc0ec52SDavid Greenman * somewhere. (it already is in the object). Result: 974bbc0ec52SDavid Greenman * It appears that emperical results show that 975bbc0ec52SDavid Greenman * deactivating pages is best. 97626f9a767SRodney W. Grimes */ 977bbc0ec52SDavid Greenman 97826f9a767SRodney W. Grimes /* 979bbc0ec52SDavid Greenman * just in case someone was asking for this page we 980bbc0ec52SDavid Greenman * now tell them that it is ok to use 98126f9a767SRodney W. Grimes */ 98226f9a767SRodney W. Grimes if (!error) { 9830d94caffSDavid Greenman if (i != reqpage - 1) 98426f9a767SRodney W. Grimes vm_page_deactivate(m[i]); 9850d94caffSDavid Greenman else 9860d94caffSDavid Greenman vm_page_activate(m[i]); 98726f9a767SRodney W. Grimes PAGE_WAKEUP(m[i]); 98826f9a767SRodney W. Grimes } else { 98926f9a767SRodney W. Grimes vnode_pager_freepage(m[i]); 99026f9a767SRodney W. Grimes } 99126f9a767SRodney W. Grimes } 99226f9a767SRodney W. Grimes } 99326f9a767SRodney W. Grimes if (error) { 994a83c285cSDavid Greenman printf("vnode_pager_input: I/O read error\n"); 99526f9a767SRodney W. Grimes } 996a83c285cSDavid Greenman return (error ? VM_PAGER_ERROR : VM_PAGER_OK); 99726f9a767SRodney W. Grimes } 99826f9a767SRodney W. Grimes 99926f9a767SRodney W. Grimes /* 100026f9a767SRodney W. Grimes * old-style vnode pager output routine 100126f9a767SRodney W. Grimes */ 100226f9a767SRodney W. Grimes int 100326f9a767SRodney W. Grimes vnode_pager_output_old(vnp, m) 100426f9a767SRodney W. Grimes register vn_pager_t vnp; 100526f9a767SRodney W. Grimes vm_page_t m; 100626f9a767SRodney W. Grimes { 10070d94caffSDavid Greenman vm_offset_t kva, kva2; 100826f9a767SRodney W. Grimes vm_offset_t size; 100926f9a767SRodney W. Grimes struct iovec aiov; 101026f9a767SRodney W. Grimes struct uio auio; 101126f9a767SRodney W. Grimes struct vnode *vp; 101226f9a767SRodney W. Grimes int error; 101326f9a767SRodney W. Grimes 101426f9a767SRodney W. Grimes vp = vnp->vnp_vp; 1015bbc0ec52SDavid Greenman 101626f9a767SRodney W. Grimes /* 10170d94caffSDavid Greenman * Dont return failure if beyond current EOF placate the VM system. 101826f9a767SRodney W. Grimes */ 10190d94caffSDavid Greenman if (m->offset >= vnp->vnp_size) { 10200d94caffSDavid Greenman return VM_PAGER_OK; 102126f9a767SRodney W. Grimes } else { 102226f9a767SRodney W. Grimes size = PAGE_SIZE; 10230d94caffSDavid Greenman if (m->offset + size > vnp->vnp_size) 10240d94caffSDavid Greenman size = vnp->vnp_size - m->offset; 10250d94caffSDavid Greenman 10260d94caffSDavid Greenman kva2 = kmem_alloc(pager_map, PAGE_SIZE); 102726f9a767SRodney W. Grimes /* 102826f9a767SRodney W. Grimes * Allocate a kernel virtual address and initialize so that 102926f9a767SRodney W. Grimes * we can use VOP_WRITE routines. 103026f9a767SRodney W. Grimes */ 103126f9a767SRodney W. Grimes kva = vm_pager_map_page(m); 10320d94caffSDavid Greenman bcopy((caddr_t) kva, (caddr_t) kva2, size); 10330d94caffSDavid Greenman vm_pager_unmap_page(kva); 10340d94caffSDavid Greenman pmap_clear_modify(VM_PAGE_TO_PHYS(m)); 10350d94caffSDavid Greenman PAGE_WAKEUP(m); 10360d94caffSDavid Greenman 10370d94caffSDavid Greenman aiov.iov_base = (caddr_t) kva2; 103826f9a767SRodney W. Grimes aiov.iov_len = size; 103926f9a767SRodney W. Grimes auio.uio_iov = &aiov; 104026f9a767SRodney W. Grimes auio.uio_iovcnt = 1; 10410d94caffSDavid Greenman auio.uio_offset = m->offset; 104226f9a767SRodney W. Grimes auio.uio_segflg = UIO_SYSSPACE; 104326f9a767SRodney W. Grimes auio.uio_rw = UIO_WRITE; 104426f9a767SRodney W. Grimes auio.uio_resid = size; 104526f9a767SRodney W. Grimes auio.uio_procp = (struct proc *) 0; 104626f9a767SRodney W. Grimes 104726f9a767SRodney W. Grimes error = VOP_WRITE(vp, &auio, 0, curproc->p_ucred); 104826f9a767SRodney W. Grimes 10490d94caffSDavid Greenman kmem_free_wakeup(pager_map, kva2, PAGE_SIZE); 105026f9a767SRodney W. Grimes if (!error) { 105126f9a767SRodney W. Grimes if ((size - auio.uio_resid) == 0) { 105226f9a767SRodney W. Grimes error = EINVAL; 105326f9a767SRodney W. Grimes } 105426f9a767SRodney W. Grimes } 1055a83c285cSDavid Greenman return error ? VM_PAGER_ERROR : VM_PAGER_OK; 105626f9a767SRodney W. Grimes } 105726f9a767SRodney W. Grimes } 105826f9a767SRodney W. Grimes 105926f9a767SRodney W. Grimes /* 106026f9a767SRodney W. Grimes * vnode pager output on a small-block file system 106126f9a767SRodney W. Grimes */ 106226f9a767SRodney W. Grimes int 106326f9a767SRodney W. Grimes vnode_pager_output_smlfs(vnp, m) 106426f9a767SRodney W. Grimes vn_pager_t vnp; 106526f9a767SRodney W. Grimes vm_page_t m; 106626f9a767SRodney W. Grimes { 106726f9a767SRodney W. Grimes int i; 106826f9a767SRodney W. Grimes int s; 106926f9a767SRodney W. Grimes struct vnode *dp, *vp; 107026f9a767SRodney W. Grimes struct buf *bp; 107126f9a767SRodney W. Grimes vm_offset_t kva; 107226f9a767SRodney W. Grimes int fileaddr; 107326f9a767SRodney W. Grimes vm_offset_t bsize; 107426f9a767SRodney W. Grimes int error = 0; 107526f9a767SRodney W. Grimes 107626f9a767SRodney W. Grimes vp = vnp->vnp_vp; 107726f9a767SRodney W. Grimes bsize = vp->v_mount->mnt_stat.f_iosize; 107826f9a767SRodney W. Grimes 10790d94caffSDavid Greenman VOP_BMAP(vp, 0, &dp, 0, 0); 108026f9a767SRodney W. Grimes kva = vm_pager_map_page(m); 108126f9a767SRodney W. Grimes for (i = 0; !error && i < (PAGE_SIZE / bsize); i++) { 1082bbc0ec52SDavid Greenman 10830d94caffSDavid Greenman if ((vm_page_bits(m->offset + i * bsize, bsize) & m->valid & m->dirty) == 0) 10840d94caffSDavid Greenman continue; 108526f9a767SRodney W. Grimes /* 108626f9a767SRodney W. Grimes * calculate logical block and offset 108726f9a767SRodney W. Grimes */ 10880d94caffSDavid Greenman fileaddr = vnode_pager_addr(vp, m->offset + i * bsize); 108926f9a767SRodney W. Grimes if (fileaddr != -1) { 109026f9a767SRodney W. Grimes 109126f9a767SRodney W. Grimes bp = getpbuf(); 109226f9a767SRodney W. Grimes 109326f9a767SRodney W. Grimes /* build a minimal buffer header */ 109426f9a767SRodney W. Grimes bp->b_flags = B_BUSY | B_CALL | B_WRITE; 109526f9a767SRodney W. Grimes bp->b_iodone = vnode_pager_iodone; 109626f9a767SRodney W. Grimes bp->b_proc = curproc; 109726f9a767SRodney W. Grimes bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred; 109826f9a767SRodney W. Grimes if (bp->b_rcred != NOCRED) 109926f9a767SRodney W. Grimes crhold(bp->b_rcred); 110026f9a767SRodney W. Grimes if (bp->b_wcred != NOCRED) 110126f9a767SRodney W. Grimes crhold(bp->b_wcred); 110226f9a767SRodney W. Grimes bp->b_un.b_addr = (caddr_t) kva + i * bsize; 110326f9a767SRodney W. Grimes bp->b_blkno = fileaddr / DEV_BSIZE; 11040d94caffSDavid Greenman pbgetvp(dp, bp); 110526f9a767SRodney W. Grimes ++dp->v_numoutput; 110626f9a767SRodney W. Grimes /* for NFS */ 110726f9a767SRodney W. Grimes bp->b_dirtyoff = 0; 110826f9a767SRodney W. Grimes bp->b_dirtyend = bsize; 110926f9a767SRodney W. Grimes bp->b_bcount = bsize; 111026f9a767SRodney W. Grimes bp->b_bufsize = bsize; 111126f9a767SRodney W. Grimes 111226f9a767SRodney W. Grimes /* do the input */ 111326f9a767SRodney W. Grimes VOP_STRATEGY(bp); 111426f9a767SRodney W. Grimes 111526f9a767SRodney W. Grimes /* we definitely need to be at splbio here */ 111626f9a767SRodney W. Grimes 111726f9a767SRodney W. Grimes s = splbio(); 111826f9a767SRodney W. Grimes while ((bp->b_flags & B_DONE) == 0) { 111926f9a767SRodney W. Grimes tsleep((caddr_t) bp, PVM, "vnswrt", 0); 112026f9a767SRodney W. Grimes } 112126f9a767SRodney W. Grimes splx(s); 112226f9a767SRodney W. Grimes if ((bp->b_flags & B_ERROR) != 0) 112326f9a767SRodney W. Grimes error = EIO; 112426f9a767SRodney W. Grimes 11250d94caffSDavid Greenman vm_page_set_clean(m, i * bsize, bsize); 112626f9a767SRodney W. Grimes /* 112726f9a767SRodney W. Grimes * free the buffer header back to the swap buffer pool 112826f9a767SRodney W. Grimes */ 112926f9a767SRodney W. Grimes relpbuf(bp); 113026f9a767SRodney W. Grimes HOLDRELE(vp); 113126f9a767SRodney W. Grimes } 113226f9a767SRodney W. Grimes } 113326f9a767SRodney W. Grimes vm_pager_unmap_page(kva); 113426f9a767SRodney W. Grimes if (error) 1135a83c285cSDavid Greenman return VM_PAGER_ERROR; 113626f9a767SRodney W. Grimes else 113726f9a767SRodney W. Grimes return VM_PAGER_OK; 113826f9a767SRodney W. Grimes } 113926f9a767SRodney W. Grimes 114026f9a767SRodney W. Grimes /* 114126f9a767SRodney W. Grimes * generic vnode pager output routine 114226f9a767SRodney W. Grimes */ 114326f9a767SRodney W. Grimes int 114426f9a767SRodney W. Grimes vnode_pager_output(vnp, m, count, rtvals) 114526f9a767SRodney W. Grimes vn_pager_t vnp; 114626f9a767SRodney W. Grimes vm_page_t *m; 114726f9a767SRodney W. Grimes int count; 114826f9a767SRodney W. Grimes int *rtvals; 114926f9a767SRodney W. Grimes { 115026f9a767SRodney W. Grimes int i, j; 115126f9a767SRodney W. Grimes vm_offset_t kva, foff; 115226f9a767SRodney W. Grimes int size; 115326f9a767SRodney W. Grimes vm_object_t object; 115426f9a767SRodney W. Grimes struct vnode *dp, *vp; 115526f9a767SRodney W. Grimes struct buf *bp; 115626f9a767SRodney W. Grimes vm_offset_t reqaddr; 115726f9a767SRodney W. Grimes int bsize; 115826f9a767SRodney W. Grimes int s; 11590d94caffSDavid Greenman daddr_t block; 11600d94caffSDavid Greenman struct timeval tv; 116126f9a767SRodney W. Grimes 116226f9a767SRodney W. Grimes int error = 0; 116326f9a767SRodney W. Grimes 116426f9a767SRodney W. Grimes retryoutput: 116526f9a767SRodney W. Grimes object = m[0]->object; /* all vm_page_t items are in same object */ 116626f9a767SRodney W. Grimes 116726f9a767SRodney W. Grimes vp = vnp->vnp_vp; 11684abc71c0SDavid Greenman 11694abc71c0SDavid Greenman /* 11704abc71c0SDavid Greenman * Make sure underlying filesystem is still mounted. 11714abc71c0SDavid Greenman */ 11724abc71c0SDavid Greenman if (vp->v_mount == NULL) 11734abc71c0SDavid Greenman return VM_PAGER_FAIL; 11744abc71c0SDavid Greenman 117526f9a767SRodney W. Grimes bsize = vp->v_mount->mnt_stat.f_iosize; 117626f9a767SRodney W. Grimes 117726f9a767SRodney W. Grimes for (i = 0; i < count; i++) 117826f9a767SRodney W. Grimes rtvals[i] = VM_PAGER_AGAIN; 117926f9a767SRodney W. Grimes 11800d94caffSDavid Greenman if ((int) m[0]->offset < 0) { 11810d94caffSDavid Greenman printf("vnode_pager_output: attempt to write meta-data!!! -- 0x%x\n", m[0]->offset); 11820d94caffSDavid Greenman m[0]->dirty = 0; 11830d94caffSDavid Greenman rtvals[0] = VM_PAGER_OK; 11840d94caffSDavid Greenman return VM_PAGER_OK; 11850d94caffSDavid Greenman } 118626f9a767SRodney W. Grimes /* 1187bbc0ec52SDavid Greenman * if the filesystem does not have a bmap, then use the old code 118826f9a767SRodney W. Grimes */ 11890d94caffSDavid Greenman if (VOP_BMAP(vp, (m[0]->offset / bsize), &dp, &block, 0) || 11900d94caffSDavid Greenman (block == -1)) { 119126f9a767SRodney W. Grimes 119226f9a767SRodney W. Grimes rtvals[0] = vnode_pager_output_old(vnp, m[0]); 119326f9a767SRodney W. Grimes 11940d94caffSDavid Greenman m[0]->dirty = 0; 1195976e77fcSDavid Greenman cnt.v_vnodeout++; 1196976e77fcSDavid Greenman cnt.v_vnodepgsout++; 119726f9a767SRodney W. Grimes return rtvals[0]; 119826f9a767SRodney W. Grimes } 11990d94caffSDavid Greenman tv = time; 12000d94caffSDavid Greenman VOP_UPDATE(vp, &tv, &tv, 0); 120126f9a767SRodney W. Grimes 120226f9a767SRodney W. Grimes /* 1203bbc0ec52SDavid Greenman * if the filesystem has a small blocksize, then use the small block 1204bbc0ec52SDavid Greenman * filesystem output code 120526f9a767SRodney W. Grimes */ 120626f9a767SRodney W. Grimes if ((bsize < PAGE_SIZE) && 120726f9a767SRodney W. Grimes (vp->v_mount->mnt_stat.f_type != MOUNT_NFS)) { 120826f9a767SRodney W. Grimes 120926f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 121026f9a767SRodney W. Grimes rtvals[i] = vnode_pager_output_smlfs(vnp, m[i]); 121126f9a767SRodney W. Grimes if (rtvals[i] == VM_PAGER_OK) { 121226f9a767SRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(m[i])); 121326f9a767SRodney W. Grimes } 121426f9a767SRodney W. Grimes } 1215976e77fcSDavid Greenman cnt.v_vnodeout++; 1216976e77fcSDavid Greenman cnt.v_vnodepgsout += count; 121726f9a767SRodney W. Grimes return rtvals[0]; 121826f9a767SRodney W. Grimes } 121926f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 12200d94caffSDavid Greenman foff = m[i]->offset; 122126f9a767SRodney W. Grimes if (foff >= vnp->vnp_size) { 122226f9a767SRodney W. Grimes for (j = i; j < count; j++) 122326f9a767SRodney W. Grimes rtvals[j] = VM_PAGER_BAD; 122426f9a767SRodney W. Grimes count = i; 122526f9a767SRodney W. Grimes break; 122626f9a767SRodney W. Grimes } 122726f9a767SRodney W. Grimes } 122826f9a767SRodney W. Grimes if (count == 0) { 122926f9a767SRodney W. Grimes return rtvals[0]; 123026f9a767SRodney W. Grimes } 12310d94caffSDavid Greenman foff = m[0]->offset; 123226f9a767SRodney W. Grimes reqaddr = vnode_pager_addr(vp, foff); 1233bbc0ec52SDavid Greenman 123426f9a767SRodney W. Grimes /* 1235bbc0ec52SDavid Greenman * Scan forward and stop for the first non-contiguous entry or stop 1236bbc0ec52SDavid Greenman * for a page being in buffer cache. 123726f9a767SRodney W. Grimes */ 123826f9a767SRodney W. Grimes for (i = 1; i < count; i++) { 12390d94caffSDavid Greenman if (vnode_pager_addr(vp, m[i]->offset) 124026f9a767SRodney W. Grimes != reqaddr + i * PAGE_SIZE) { 124126f9a767SRodney W. Grimes count = i; 124226f9a767SRodney W. Grimes break; 124326f9a767SRodney W. Grimes } 124426f9a767SRodney W. Grimes } 124526f9a767SRodney W. Grimes 124626f9a767SRodney W. Grimes /* 124726f9a767SRodney W. Grimes * calculate the size of the transfer 124826f9a767SRodney W. Grimes */ 124926f9a767SRodney W. Grimes size = count * PAGE_SIZE; 125026f9a767SRodney W. Grimes if ((foff + size) > vnp->vnp_size) 125126f9a767SRodney W. Grimes size = vnp->vnp_size - foff; 125226f9a767SRodney W. Grimes 125326f9a767SRodney W. Grimes /* 125426f9a767SRodney W. Grimes * round up physical size for real devices 125526f9a767SRodney W. Grimes */ 125626f9a767SRodney W. Grimes if (dp->v_type == VBLK || dp->v_type == VCHR) 125726f9a767SRodney W. Grimes size = (size + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1); 125826f9a767SRodney W. Grimes 125916f62314SDavid Greenman bp = getpbuf(); 126016f62314SDavid Greenman kva = (vm_offset_t) bp->b_data; 126126f9a767SRodney W. Grimes /* 126226f9a767SRodney W. Grimes * and map the pages to be read into the kva 126326f9a767SRodney W. Grimes */ 126416f62314SDavid Greenman pmap_qenter(kva, m, count); 1265bbc0ec52SDavid Greenman 126626f9a767SRodney W. Grimes /* build a minimal buffer header */ 126726f9a767SRodney W. Grimes bp->b_flags = B_BUSY | B_WRITE | B_CALL; 126826f9a767SRodney W. Grimes bp->b_iodone = vnode_pager_iodone; 126926f9a767SRodney W. Grimes /* B_PHYS is not set, but it is nice to fill this in */ 127026f9a767SRodney W. Grimes bp->b_proc = curproc; 127126f9a767SRodney W. Grimes bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred; 127226f9a767SRodney W. Grimes 127326f9a767SRodney W. Grimes if (bp->b_rcred != NOCRED) 127426f9a767SRodney W. Grimes crhold(bp->b_rcred); 127526f9a767SRodney W. Grimes if (bp->b_wcred != NOCRED) 127626f9a767SRodney W. Grimes crhold(bp->b_wcred); 127726f9a767SRodney W. Grimes bp->b_blkno = reqaddr / DEV_BSIZE; 12780d94caffSDavid Greenman pbgetvp(dp, bp); 127926f9a767SRodney W. Grimes ++dp->v_numoutput; 128026f9a767SRodney W. Grimes 128126f9a767SRodney W. Grimes /* for NFS */ 128226f9a767SRodney W. Grimes bp->b_dirtyoff = 0; 128326f9a767SRodney W. Grimes bp->b_dirtyend = size; 128426f9a767SRodney W. Grimes 128526f9a767SRodney W. Grimes bp->b_bcount = size; 128626f9a767SRodney W. Grimes bp->b_bufsize = size; 128726f9a767SRodney W. Grimes 1288976e77fcSDavid Greenman cnt.v_vnodeout++; 1289976e77fcSDavid Greenman cnt.v_vnodepgsout += count; 1290976e77fcSDavid Greenman 129126f9a767SRodney W. Grimes /* do the output */ 129226f9a767SRodney W. Grimes VOP_STRATEGY(bp); 129326f9a767SRodney W. Grimes 129426f9a767SRodney W. Grimes s = splbio(); 129526f9a767SRodney W. Grimes 129626f9a767SRodney W. Grimes /* we definitely need to be at splbio here */ 129726f9a767SRodney W. Grimes 129826f9a767SRodney W. Grimes while ((bp->b_flags & B_DONE) == 0) { 129926f9a767SRodney W. Grimes tsleep((caddr_t) bp, PVM, "vnwrite", 0); 130026f9a767SRodney W. Grimes } 130126f9a767SRodney W. Grimes splx(s); 130226f9a767SRodney W. Grimes 130326f9a767SRodney W. Grimes if ((bp->b_flags & B_ERROR) != 0) 130426f9a767SRodney W. Grimes error = EIO; 130526f9a767SRodney W. Grimes 130616f62314SDavid Greenman pmap_qremove(kva, count); 130726f9a767SRodney W. Grimes 130826f9a767SRodney W. Grimes /* 130926f9a767SRodney W. Grimes * free the buffer header back to the swap buffer pool 131026f9a767SRodney W. Grimes */ 131126f9a767SRodney W. Grimes relpbuf(bp); 131226f9a767SRodney W. Grimes HOLDRELE(vp); 131326f9a767SRodney W. Grimes 131426f9a767SRodney W. Grimes if (!error) { 131526f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 131626f9a767SRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(m[i])); 13170d94caffSDavid Greenman m[i]->dirty = 0; 131826f9a767SRodney W. Grimes rtvals[i] = VM_PAGER_OK; 131926f9a767SRodney W. Grimes } 132026f9a767SRodney W. Grimes } else if (count != 1) { 132126f9a767SRodney W. Grimes error = 0; 132226f9a767SRodney W. Grimes count = 1; 132326f9a767SRodney W. Grimes goto retryoutput; 132426f9a767SRodney W. Grimes } 132526f9a767SRodney W. Grimes if (error) { 1326a83c285cSDavid Greenman printf("vnode_pager_output: I/O write error\n"); 132726f9a767SRodney W. Grimes } 1328a83c285cSDavid Greenman return (error ? VM_PAGER_ERROR : VM_PAGER_OK); 132926f9a767SRodney W. Grimes } 1330