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 404abc71c0SDavid Greenman * $Id: vnode_pager.c,v 1.17 1994/11/17 01:22:45 gibbs 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; 2874abc71c0SDavid Greenman register struct vnode *vp = vnp->vnp_vp; 288df8bae1dSRodney W. Grimes daddr_t bn; 289df8bae1dSRodney W. Grimes int err; 290317205caSDavid Greenman daddr_t block; 291df8bae1dSRodney W. Grimes 292df8bae1dSRodney W. Grimes /* 2934abc71c0SDavid Greenman * If filesystem no longer mounted or offset beyond end of 2944abc71c0SDavid Greenman * file we do not have the page. 295df8bae1dSRodney W. Grimes */ 2964abc71c0SDavid Greenman if ((vp->v_mount == NULL) || (offset >= vnp->vnp_size)) 2974abc71c0SDavid Greenman return FALSE; 298df8bae1dSRodney W. Grimes 2994abc71c0SDavid Greenman block = offset / vp->v_mount->mnt_stat.f_iosize; 3004abc71c0SDavid Greenman if (incore(vp, block)) 301317205caSDavid Greenman return TRUE; 302df8bae1dSRodney W. Grimes /* 303bbc0ec52SDavid Greenman * Read the index to find the disk block to read from. If there is no 304bbc0ec52SDavid Greenman * block, report that we don't have this data. 305df8bae1dSRodney W. Grimes * 306df8bae1dSRodney W. Grimes * Assumes that the vnode has whole page or nothing. 307df8bae1dSRodney W. Grimes */ 3084abc71c0SDavid Greenman err = VOP_BMAP(vp, block, (struct vnode **) 0, &bn, 0); 3098e58bf68SDavid Greenman /* 3108e58bf68SDavid Greenman printf("vnode_pager_haspage: (%d)0x%x: err: %d, bn: %d\n", 3118e58bf68SDavid Greenman offset, offset, err, bn); 3128e58bf68SDavid Greenman */ 313df8bae1dSRodney W. Grimes if (err) { 314df8bae1dSRodney W. Grimes return (TRUE); 315df8bae1dSRodney W. Grimes } 316df8bae1dSRodney W. Grimes return ((long) bn < 0 ? FALSE : TRUE); 317df8bae1dSRodney W. Grimes } 318df8bae1dSRodney W. Grimes 319df8bae1dSRodney W. Grimes /* 320df8bae1dSRodney W. Grimes * Lets the VM system know about a change in size for a file. 321df8bae1dSRodney W. Grimes * If this vnode is mapped into some address space (i.e. we have a pager 322df8bae1dSRodney W. Grimes * for it) we adjust our own internal size and flush any cached pages in 323df8bae1dSRodney W. Grimes * the associated object that are affected by the size change. 324df8bae1dSRodney W. Grimes * 325df8bae1dSRodney W. Grimes * Note: this routine may be invoked as a result of a pager put 326df8bae1dSRodney W. Grimes * operation (possibly at object termination time), so we must be careful. 327df8bae1dSRodney W. Grimes */ 328df8bae1dSRodney W. Grimes void 329df8bae1dSRodney W. Grimes vnode_pager_setsize(vp, nsize) 330df8bae1dSRodney W. Grimes struct vnode *vp; 331df8bae1dSRodney W. Grimes u_long nsize; 332df8bae1dSRodney W. Grimes { 333df8bae1dSRodney W. Grimes register vn_pager_t vnp; 334df8bae1dSRodney W. Grimes register vm_object_t object; 335df8bae1dSRodney W. Grimes vm_pager_t pager; 336df8bae1dSRodney W. Grimes 337df8bae1dSRodney W. Grimes /* 338df8bae1dSRodney W. Grimes * Not a mapped vnode 339df8bae1dSRodney W. Grimes */ 340df8bae1dSRodney W. Grimes if (vp == NULL || vp->v_type != VREG || vp->v_vmdata == NULL) 341df8bae1dSRodney W. Grimes return; 342bbc0ec52SDavid Greenman 343df8bae1dSRodney W. Grimes /* 344df8bae1dSRodney W. Grimes * Hasn't changed size 345df8bae1dSRodney W. Grimes */ 3468e58bf68SDavid Greenman object = (vm_object_t) vp->v_vmdata; 3478e58bf68SDavid Greenman if( object == NULL) 3488e58bf68SDavid Greenman return; 3498e58bf68SDavid Greenman if( (pager = object->pager) == NULL) 3508e58bf68SDavid Greenman return; 351df8bae1dSRodney W. Grimes vnp = (vn_pager_t) pager->pg_data; 352df8bae1dSRodney W. Grimes if (nsize == vnp->vnp_size) 353df8bae1dSRodney W. Grimes return; 354bbc0ec52SDavid Greenman 355df8bae1dSRodney W. Grimes /* 356bbc0ec52SDavid Greenman * No object. This can happen during object termination since 357bbc0ec52SDavid Greenman * vm_object_page_clean is called after the object has been removed 358bbc0ec52SDavid Greenman * from the hash table, and clean may cause vnode write operations 359bbc0ec52SDavid Greenman * which can wind up back here. 360df8bae1dSRodney W. Grimes */ 361df8bae1dSRodney W. Grimes object = vm_object_lookup(pager); 362df8bae1dSRodney W. Grimes if (object == NULL) 363df8bae1dSRodney W. Grimes return; 364df8bae1dSRodney W. Grimes 365df8bae1dSRodney W. Grimes /* 366bbc0ec52SDavid Greenman * File has shrunk. Toss any cached pages beyond the new EOF. 367df8bae1dSRodney W. Grimes */ 368bbc0ec52SDavid Greenman if (nsize < vnp->vnp_size) { 369df8bae1dSRodney W. Grimes vm_object_lock(object); 370df8bae1dSRodney W. Grimes vm_object_page_remove(object, 371bbc0ec52SDavid Greenman round_page((vm_offset_t) nsize), vnp->vnp_size); 372bbc0ec52SDavid Greenman vm_object_unlock(object); 373bbc0ec52SDavid Greenman 374bbc0ec52SDavid Greenman /* 375bbc0ec52SDavid Greenman * this gets rid of garbage at the end of a page that is now 376bbc0ec52SDavid Greenman * only partially backed by the vnode... 377bbc0ec52SDavid Greenman */ 378bbc0ec52SDavid Greenman if (nsize & PAGE_MASK) { 379bbc0ec52SDavid Greenman vm_offset_t kva; 380bbc0ec52SDavid Greenman vm_page_t m; 381bbc0ec52SDavid Greenman 382bbc0ec52SDavid Greenman m = vm_page_lookup(object, trunc_page((vm_offset_t) nsize)); 383bbc0ec52SDavid Greenman if (m) { 384bbc0ec52SDavid Greenman kva = vm_pager_map_page(m); 385bbc0ec52SDavid Greenman bzero((caddr_t) kva + (nsize & PAGE_MASK), 386bbc0ec52SDavid Greenman round_page(nsize) - nsize); 387bbc0ec52SDavid Greenman vm_pager_unmap_page(kva); 388bbc0ec52SDavid Greenman } 389bbc0ec52SDavid Greenman } 390bbc0ec52SDavid Greenman } else { 391bbc0ec52SDavid Greenman 392bbc0ec52SDavid Greenman /* 393bbc0ec52SDavid Greenman * this allows the filesystem and VM cache to stay in sync if 394bbc0ec52SDavid Greenman * the VM page hasn't been modified... After the page is 395bbc0ec52SDavid Greenman * removed -- it will be faulted back in from the filesystem 396bbc0ec52SDavid Greenman * cache. 397bbc0ec52SDavid Greenman */ 398bbc0ec52SDavid Greenman if (vnp->vnp_size & PAGE_MASK) { 399bbc0ec52SDavid Greenman vm_page_t m; 400bbc0ec52SDavid Greenman 401bbc0ec52SDavid Greenman m = vm_page_lookup(object, trunc_page(vnp->vnp_size)); 402bbc0ec52SDavid Greenman if (m && (m->flags & PG_CLEAN)) { 403bbc0ec52SDavid Greenman vm_object_lock(object); 404bbc0ec52SDavid Greenman vm_object_page_remove(object, 405bbc0ec52SDavid Greenman vnp->vnp_size, vnp->vnp_size); 406df8bae1dSRodney W. Grimes vm_object_unlock(object); 407df8bae1dSRodney W. Grimes } 408bbc0ec52SDavid Greenman } 409bbc0ec52SDavid Greenman } 410df8bae1dSRodney W. Grimes vnp->vnp_size = (vm_offset_t) nsize; 411bbc0ec52SDavid Greenman object->size = round_page(nsize); 412bbc0ec52SDavid Greenman 413df8bae1dSRodney W. Grimes vm_object_deallocate(object); 414df8bae1dSRodney W. Grimes } 415df8bae1dSRodney W. Grimes 416df8bae1dSRodney W. Grimes void 417df8bae1dSRodney W. Grimes vnode_pager_umount(mp) 418df8bae1dSRodney W. Grimes register struct mount *mp; 419df8bae1dSRodney W. Grimes { 420df8bae1dSRodney W. Grimes register vm_pager_t pager, npager; 421df8bae1dSRodney W. Grimes struct vnode *vp; 422df8bae1dSRodney W. Grimes 42326f9a767SRodney W. Grimes pager = vnode_pager_list.tqh_first; 42426f9a767SRodney W. Grimes while (pager) { 425bbc0ec52SDavid Greenman 426df8bae1dSRodney W. Grimes /* 427bbc0ec52SDavid Greenman * Save the next pointer now since uncaching may terminate the 428bbc0ec52SDavid Greenman * object and render pager invalid 429df8bae1dSRodney W. Grimes */ 430df8bae1dSRodney W. Grimes vp = ((vn_pager_t) pager->pg_data)->vnp_vp; 43126f9a767SRodney W. Grimes npager = pager->pg_list.tqe_next; 43226f9a767SRodney W. Grimes if (mp == (struct mount *) 0 || vp->v_mount == mp) 433df8bae1dSRodney W. Grimes (void) vnode_pager_uncache(vp); 43426f9a767SRodney W. Grimes pager = npager; 435df8bae1dSRodney W. Grimes } 436df8bae1dSRodney W. Grimes } 437df8bae1dSRodney W. Grimes 438df8bae1dSRodney W. Grimes /* 439df8bae1dSRodney W. Grimes * Remove vnode associated object from the object cache. 440df8bae1dSRodney W. Grimes * 44126f9a767SRodney W. Grimes * Note: this routine may be invoked as a result of a pager put 44226f9a767SRodney W. Grimes * operation (possibly at object termination time), so we must be careful. 44326f9a767SRodney W. Grimes */ 44426f9a767SRodney W. Grimes boolean_t 44526f9a767SRodney W. Grimes vnode_pager_uncache(vp) 44626f9a767SRodney W. Grimes register struct vnode *vp; 44726f9a767SRodney W. Grimes { 44826f9a767SRodney W. Grimes register vm_object_t object; 44926f9a767SRodney W. Grimes boolean_t uncached, locked; 45026f9a767SRodney W. Grimes vm_pager_t pager; 45126f9a767SRodney W. Grimes 45226f9a767SRodney W. Grimes /* 45326f9a767SRodney W. Grimes * Not a mapped vnode 45426f9a767SRodney W. Grimes */ 4558e58bf68SDavid Greenman object = (vm_object_t) vp->v_vmdata; 4568e58bf68SDavid Greenman if( object == NULL) 4578e58bf68SDavid Greenman return(TRUE); 4588e58bf68SDavid Greenman pager = object->pager; 45926f9a767SRodney W. Grimes if (pager == NULL) 46026f9a767SRodney W. Grimes return (TRUE); 461bbc0ec52SDavid Greenman 46226f9a767SRodney W. Grimes /* 463bbc0ec52SDavid Greenman * Unlock the vnode if it is currently locked. We do this since 464bbc0ec52SDavid Greenman * uncaching the object may result in its destruction which may 465bbc0ec52SDavid Greenman * initiate paging activity which may necessitate locking the vnode. 46626f9a767SRodney W. Grimes */ 46726f9a767SRodney W. Grimes locked = VOP_ISLOCKED(vp); 46826f9a767SRodney W. Grimes if (locked) 46926f9a767SRodney W. Grimes VOP_UNLOCK(vp); 470bbc0ec52SDavid Greenman 47126f9a767SRodney W. Grimes /* 472bbc0ec52SDavid Greenman * Must use vm_object_lookup() as it actually removes the object from 473bbc0ec52SDavid Greenman * the cache list. 47426f9a767SRodney W. Grimes */ 47526f9a767SRodney W. Grimes object = vm_object_lookup(pager); 47626f9a767SRodney W. Grimes if (object) { 47726f9a767SRodney W. Grimes uncached = (object->ref_count <= 1); 47826f9a767SRodney W. Grimes pager_cache(object, FALSE); 47926f9a767SRodney W. Grimes } else 48026f9a767SRodney W. Grimes uncached = TRUE; 48126f9a767SRodney W. Grimes if (locked) 48226f9a767SRodney W. Grimes VOP_LOCK(vp); 48326f9a767SRodney W. Grimes return (uncached); 48426f9a767SRodney W. Grimes } 485df8bae1dSRodney W. Grimes 48626f9a767SRodney W. Grimes 48726f9a767SRodney W. Grimes void 48826f9a767SRodney W. Grimes vnode_pager_freepage(m) 48926f9a767SRodney W. Grimes vm_page_t m; 490df8bae1dSRodney W. Grimes { 49126f9a767SRodney W. Grimes PAGE_WAKEUP(m); 49226f9a767SRodney W. Grimes vm_page_free(m); 49326f9a767SRodney W. Grimes } 49426f9a767SRodney W. Grimes 49526f9a767SRodney W. Grimes /* 49626f9a767SRodney W. Grimes * calculate the linear (byte) disk address of specified virtual 49726f9a767SRodney W. Grimes * file address 49826f9a767SRodney W. Grimes */ 49926f9a767SRodney W. Grimes vm_offset_t 50026f9a767SRodney W. Grimes vnode_pager_addr(vp, address) 50126f9a767SRodney W. Grimes struct vnode *vp; 50226f9a767SRodney W. Grimes vm_offset_t address; 50326f9a767SRodney W. Grimes { 50426f9a767SRodney W. Grimes int rtaddress; 50526f9a767SRodney W. Grimes int bsize; 50626f9a767SRodney W. Grimes vm_offset_t block; 50726f9a767SRodney W. Grimes struct vnode *rtvp; 50826f9a767SRodney W. Grimes int err; 50926f9a767SRodney W. Grimes int vblock, voffset; 51026f9a767SRodney W. Grimes 51126f9a767SRodney W. Grimes bsize = vp->v_mount->mnt_stat.f_iosize; 51226f9a767SRodney W. Grimes vblock = address / bsize; 51326f9a767SRodney W. Grimes voffset = address % bsize; 51426f9a767SRodney W. Grimes 51526f9a767SRodney W. Grimes err = VOP_BMAP(vp, vblock, &rtvp, &block, 0); 51626f9a767SRodney W. Grimes 51726f9a767SRodney W. Grimes if (err) 51826f9a767SRodney W. Grimes rtaddress = -1; 51926f9a767SRodney W. Grimes else 52026f9a767SRodney W. Grimes rtaddress = block * DEV_BSIZE + voffset; 52126f9a767SRodney W. Grimes 52226f9a767SRodney W. Grimes return rtaddress; 52326f9a767SRodney W. Grimes } 52426f9a767SRodney W. Grimes 52526f9a767SRodney W. Grimes /* 52626f9a767SRodney W. Grimes * interrupt routine for I/O completion 52726f9a767SRodney W. Grimes */ 52826f9a767SRodney W. Grimes void 52926f9a767SRodney W. Grimes vnode_pager_iodone(bp) 53026f9a767SRodney W. Grimes struct buf *bp; 53126f9a767SRodney W. Grimes { 53226f9a767SRodney W. Grimes bp->b_flags |= B_DONE; 53326f9a767SRodney W. Grimes wakeup((caddr_t) bp); 53416f62314SDavid Greenman if( bp->b_flags & B_ASYNC) { 53516f62314SDavid Greenman vm_offset_t paddr; 53616f62314SDavid Greenman vm_page_t m; 53716f62314SDavid Greenman vm_object_t obj = 0; 53816f62314SDavid Greenman int i; 53916f62314SDavid Greenman int npages; 54016f62314SDavid Greenman 54116f62314SDavid Greenman paddr = (vm_offset_t) bp->b_data; 54216f62314SDavid Greenman if( bp->b_bufsize != bp->b_bcount) 54316f62314SDavid Greenman bzero( bp->b_data + bp->b_bcount, 54416f62314SDavid Greenman bp->b_bufsize - bp->b_bcount); 54516f62314SDavid Greenman 54616f62314SDavid Greenman npages = (bp->b_bufsize + PAGE_SIZE - 1) / PAGE_SIZE; 547a481f200SDavid Greenman /* 548a481f200SDavid Greenman printf("bcount: %d, bufsize: %d, npages: %d\n", 549a481f200SDavid Greenman bp->b_bcount, bp->b_bufsize, npages); 550a481f200SDavid Greenman */ 55116f62314SDavid Greenman for( i = 0; i < npages; i++) { 55216f62314SDavid Greenman m = PHYS_TO_VM_PAGE(pmap_kextract(paddr + i * PAGE_SIZE)); 55316f62314SDavid Greenman obj = m->object; 55416f62314SDavid Greenman if( m) { 55516f62314SDavid Greenman m->flags |= PG_CLEAN; 55616f62314SDavid Greenman m->flags &= ~(PG_LAUNDRY|PG_FAKE); 55716f62314SDavid Greenman PAGE_WAKEUP(m); 55816f62314SDavid Greenman } else { 55916f62314SDavid Greenman panic("vnode_pager_iodone: page is gone!!!"); 56016f62314SDavid Greenman } 56116f62314SDavid Greenman } 562a481f200SDavid Greenman pmap_qremove( paddr, npages); 56316f62314SDavid Greenman if( obj) { 56416f62314SDavid Greenman --obj->paging_in_progress; 56516f62314SDavid Greenman if( obj->paging_in_progress == 0) 56616f62314SDavid Greenman wakeup((caddr_t) obj); 56716f62314SDavid Greenman } else { 56816f62314SDavid Greenman panic("vnode_pager_iodone: object is gone???"); 56916f62314SDavid Greenman } 57016f62314SDavid Greenman HOLDRELE(bp->b_vp); 57116f62314SDavid Greenman relpbuf(bp); 57216f62314SDavid Greenman } 57326f9a767SRodney W. Grimes } 57426f9a767SRodney W. Grimes 57526f9a767SRodney W. Grimes /* 57626f9a767SRodney W. Grimes * small block file system vnode pager input 57726f9a767SRodney W. Grimes */ 57826f9a767SRodney W. Grimes int 57926f9a767SRodney W. Grimes vnode_pager_input_smlfs(vnp, m) 58026f9a767SRodney W. Grimes vn_pager_t vnp; 58126f9a767SRodney W. Grimes vm_page_t m; 58226f9a767SRodney W. Grimes { 58326f9a767SRodney W. Grimes int i; 58426f9a767SRodney W. Grimes int s; 58526f9a767SRodney W. Grimes vm_offset_t paging_offset; 58626f9a767SRodney W. Grimes struct vnode *dp, *vp; 58726f9a767SRodney W. Grimes struct buf *bp; 58826f9a767SRodney W. Grimes vm_offset_t foff; 58926f9a767SRodney W. Grimes vm_offset_t kva; 59026f9a767SRodney W. Grimes int fileaddr; 59126f9a767SRodney W. Grimes int block; 59226f9a767SRodney W. Grimes vm_offset_t bsize; 59326f9a767SRodney W. Grimes int error = 0; 59426f9a767SRodney W. Grimes 59526f9a767SRodney W. Grimes paging_offset = m->object->paging_offset; 59626f9a767SRodney W. Grimes vp = vnp->vnp_vp; 59726f9a767SRodney W. Grimes bsize = vp->v_mount->mnt_stat.f_iosize; 59826f9a767SRodney W. Grimes foff = m->offset + paging_offset; 59926f9a767SRodney W. Grimes 60026f9a767SRodney W. Grimes VOP_BMAP(vp, foff, &dp, 0, 0); 60126f9a767SRodney W. Grimes 60226f9a767SRodney W. Grimes kva = vm_pager_map_page(m); 60326f9a767SRodney W. Grimes 60426f9a767SRodney W. Grimes for (i = 0; i < PAGE_SIZE / bsize; i++) { 605bbc0ec52SDavid Greenman 60626f9a767SRodney W. Grimes /* 60726f9a767SRodney W. Grimes * calculate logical block and offset 60826f9a767SRodney W. Grimes */ 60926f9a767SRodney W. Grimes block = foff / bsize + i; 61026f9a767SRodney W. Grimes s = splbio(); 61105f0fdd2SPoul-Henning Kamp while ((bp = incore(vp, block)) != 0) { 61226f9a767SRodney W. Grimes int amount; 61326f9a767SRodney W. Grimes 61426f9a767SRodney W. Grimes /* 61526f9a767SRodney W. Grimes * wait until the buffer is avail or gone 61626f9a767SRodney W. Grimes */ 61726f9a767SRodney W. Grimes if (bp->b_flags & B_BUSY) { 61826f9a767SRodney W. Grimes bp->b_flags |= B_WANTED; 61926f9a767SRodney W. Grimes tsleep((caddr_t) bp, PVM, "vnwblk", 0); 62026f9a767SRodney W. Grimes continue; 62126f9a767SRodney W. Grimes } 62226f9a767SRodney W. Grimes amount = bsize; 62326f9a767SRodney W. Grimes if ((foff + bsize) > vnp->vnp_size) 62426f9a767SRodney W. Grimes amount = vnp->vnp_size - foff; 62526f9a767SRodney W. Grimes 62626f9a767SRodney W. Grimes /* 62726f9a767SRodney W. Grimes * make sure that this page is in the buffer 62826f9a767SRodney W. Grimes */ 62926f9a767SRodney W. Grimes if ((amount > 0) && amount <= bp->b_bcount) { 63026f9a767SRodney W. Grimes bp->b_flags |= B_BUSY; 63126f9a767SRodney W. Grimes splx(s); 63226f9a767SRodney W. Grimes 63326f9a767SRodney W. Grimes /* 63426f9a767SRodney W. Grimes * copy the data from the buffer 63526f9a767SRodney W. Grimes */ 63626f9a767SRodney W. Grimes bcopy(bp->b_un.b_addr, (caddr_t) kva + i * bsize, amount); 63726f9a767SRodney W. Grimes if (amount < bsize) { 63826f9a767SRodney W. Grimes bzero((caddr_t) kva + amount, bsize - amount); 63926f9a767SRodney W. Grimes } 64026f9a767SRodney W. Grimes bp->b_flags &= ~B_BUSY; 64126f9a767SRodney W. Grimes wakeup((caddr_t) bp); 64226f9a767SRodney W. Grimes goto nextblock; 64326f9a767SRodney W. Grimes } 64426f9a767SRodney W. Grimes break; 64526f9a767SRodney W. Grimes } 64626f9a767SRodney W. Grimes splx(s); 64726f9a767SRodney W. Grimes fileaddr = vnode_pager_addr(vp, foff + i * bsize); 64826f9a767SRodney W. Grimes if (fileaddr != -1) { 64926f9a767SRodney W. Grimes bp = getpbuf(); 65026f9a767SRodney W. Grimes VHOLD(vp); 65126f9a767SRodney W. Grimes 65226f9a767SRodney W. Grimes /* build a minimal buffer header */ 65326f9a767SRodney W. Grimes bp->b_flags = B_BUSY | B_READ | B_CALL; 65426f9a767SRodney W. Grimes bp->b_iodone = vnode_pager_iodone; 65526f9a767SRodney W. Grimes bp->b_proc = curproc; 65626f9a767SRodney W. Grimes bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred; 65726f9a767SRodney W. Grimes if (bp->b_rcred != NOCRED) 65826f9a767SRodney W. Grimes crhold(bp->b_rcred); 65926f9a767SRodney W. Grimes if (bp->b_wcred != NOCRED) 66026f9a767SRodney W. Grimes crhold(bp->b_wcred); 66126f9a767SRodney W. Grimes bp->b_un.b_addr = (caddr_t) kva + i * bsize; 66226f9a767SRodney W. Grimes bp->b_blkno = fileaddr / DEV_BSIZE; 66326f9a767SRodney W. Grimes bgetvp(dp, bp); 66426f9a767SRodney W. Grimes bp->b_bcount = bsize; 66526f9a767SRodney W. Grimes bp->b_bufsize = bsize; 66626f9a767SRodney W. Grimes 66726f9a767SRodney W. Grimes /* do the input */ 66826f9a767SRodney W. Grimes VOP_STRATEGY(bp); 66926f9a767SRodney W. Grimes 67026f9a767SRodney W. Grimes /* we definitely need to be at splbio here */ 67126f9a767SRodney W. Grimes 67226f9a767SRodney W. Grimes s = splbio(); 67326f9a767SRodney W. Grimes while ((bp->b_flags & B_DONE) == 0) { 67426f9a767SRodney W. Grimes tsleep((caddr_t) bp, PVM, "vnsrd", 0); 67526f9a767SRodney W. Grimes } 67626f9a767SRodney W. Grimes splx(s); 67726f9a767SRodney W. Grimes if ((bp->b_flags & B_ERROR) != 0) 67826f9a767SRodney W. Grimes error = EIO; 67926f9a767SRodney W. Grimes 68026f9a767SRodney W. Grimes /* 68126f9a767SRodney W. Grimes * free the buffer header back to the swap buffer pool 68226f9a767SRodney W. Grimes */ 68326f9a767SRodney W. Grimes relpbuf(bp); 68426f9a767SRodney W. Grimes HOLDRELE(vp); 68526f9a767SRodney W. Grimes if (error) 68626f9a767SRodney W. Grimes break; 68726f9a767SRodney W. Grimes } else { 68826f9a767SRodney W. Grimes bzero((caddr_t) kva + i * bsize, bsize); 68926f9a767SRodney W. Grimes } 69026f9a767SRodney W. Grimes nextblock: 69126f9a767SRodney W. Grimes } 69226f9a767SRodney W. Grimes vm_pager_unmap_page(kva); 69326f9a767SRodney W. Grimes if (error) { 694a83c285cSDavid Greenman return VM_PAGER_ERROR; 69526f9a767SRodney W. Grimes } 69626f9a767SRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(m)); 69726f9a767SRodney W. Grimes m->flags |= PG_CLEAN; 69826f9a767SRodney W. Grimes m->flags &= ~PG_LAUNDRY; 69926f9a767SRodney W. Grimes return VM_PAGER_OK; 70026f9a767SRodney W. Grimes 70126f9a767SRodney W. Grimes } 70226f9a767SRodney W. Grimes 70326f9a767SRodney W. Grimes 70426f9a767SRodney W. Grimes /* 70526f9a767SRodney W. Grimes * old style vnode pager output routine 70626f9a767SRodney W. Grimes */ 70726f9a767SRodney W. Grimes int 70826f9a767SRodney W. Grimes vnode_pager_input_old(vnp, m) 70926f9a767SRodney W. Grimes vn_pager_t vnp; 71026f9a767SRodney W. Grimes vm_page_t m; 71126f9a767SRodney W. Grimes { 712df8bae1dSRodney W. Grimes struct uio auio; 713df8bae1dSRodney W. Grimes struct iovec aiov; 71426f9a767SRodney W. Grimes int error; 71526f9a767SRodney W. Grimes int size; 71626f9a767SRodney W. Grimes vm_offset_t foff; 71726f9a767SRodney W. Grimes vm_offset_t kva; 718df8bae1dSRodney W. Grimes 71926f9a767SRodney W. Grimes error = 0; 720df8bae1dSRodney W. Grimes foff = m->offset + m->object->paging_offset; 721bbc0ec52SDavid Greenman 722df8bae1dSRodney W. Grimes /* 72326f9a767SRodney W. Grimes * Return failure if beyond current EOF 72426f9a767SRodney W. Grimes */ 72526f9a767SRodney W. Grimes if (foff >= vnp->vnp_size) { 72626f9a767SRodney W. Grimes return VM_PAGER_BAD; 72726f9a767SRodney W. Grimes } else { 72826f9a767SRodney W. Grimes size = PAGE_SIZE; 72926f9a767SRodney W. Grimes if (foff + size > vnp->vnp_size) 73026f9a767SRodney W. Grimes size = vnp->vnp_size - foff; 73126f9a767SRodney W. Grimes /* 732df8bae1dSRodney W. Grimes * Allocate a kernel virtual address and initialize so that 733df8bae1dSRodney W. Grimes * we can use VOP_READ/WRITE routines. 734df8bae1dSRodney W. Grimes */ 73526f9a767SRodney W. Grimes kva = vm_pager_map_page(m); 736df8bae1dSRodney W. Grimes aiov.iov_base = (caddr_t) kva; 737df8bae1dSRodney W. Grimes aiov.iov_len = size; 738df8bae1dSRodney W. Grimes auio.uio_iov = &aiov; 739df8bae1dSRodney W. Grimes auio.uio_iovcnt = 1; 740df8bae1dSRodney W. Grimes auio.uio_offset = foff; 741df8bae1dSRodney W. Grimes auio.uio_segflg = UIO_SYSSPACE; 74226f9a767SRodney W. Grimes auio.uio_rw = UIO_READ; 743df8bae1dSRodney W. Grimes auio.uio_resid = size; 744df8bae1dSRodney W. Grimes auio.uio_procp = (struct proc *) 0; 74526f9a767SRodney W. Grimes 74626f9a767SRodney W. Grimes error = VOP_READ(vnp->vnp_vp, &auio, 0, curproc->p_ucred); 747df8bae1dSRodney W. Grimes if (!error) { 748df8bae1dSRodney W. Grimes register int count = size - auio.uio_resid; 749df8bae1dSRodney W. Grimes 750df8bae1dSRodney W. Grimes if (count == 0) 751df8bae1dSRodney W. Grimes error = EINVAL; 75226f9a767SRodney W. Grimes else if (count != PAGE_SIZE) 75326f9a767SRodney W. Grimes bzero((caddr_t) kva + count, PAGE_SIZE - count); 754df8bae1dSRodney W. Grimes } 75526f9a767SRodney W. Grimes vm_pager_unmap_page(kva); 756df8bae1dSRodney W. Grimes } 75726f9a767SRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(m)); 75826f9a767SRodney W. Grimes m->flags |= PG_CLEAN; 75926f9a767SRodney W. Grimes m->flags &= ~PG_LAUNDRY; 760a83c285cSDavid Greenman return error ? VM_PAGER_ERROR : VM_PAGER_OK; 76126f9a767SRodney W. Grimes } 76226f9a767SRodney W. Grimes 76326f9a767SRodney W. Grimes /* 76426f9a767SRodney W. Grimes * generic vnode pager input routine 76526f9a767SRodney W. Grimes */ 76626f9a767SRodney W. Grimes int 76726f9a767SRodney W. Grimes vnode_pager_input(vnp, m, count, reqpage) 76826f9a767SRodney W. Grimes register vn_pager_t vnp; 76926f9a767SRodney W. Grimes vm_page_t *m; 77026f9a767SRodney W. Grimes int count, reqpage; 77126f9a767SRodney W. Grimes { 77205f0fdd2SPoul-Henning Kamp int i; 77326f9a767SRodney W. Grimes vm_offset_t kva, foff; 77416f62314SDavid Greenman int size, sizea; 77526f9a767SRodney W. Grimes vm_object_t object; 77626f9a767SRodney W. Grimes vm_offset_t paging_offset; 77726f9a767SRodney W. Grimes struct vnode *dp, *vp; 77826f9a767SRodney W. Grimes int bsize; 77926f9a767SRodney W. Grimes 78026f9a767SRodney W. Grimes int first, last; 78126f9a767SRodney W. Grimes int reqaddr, firstaddr; 78226f9a767SRodney W. Grimes int block, offset; 78326f9a767SRodney W. Grimes 78416f62314SDavid Greenman struct buf *bp, *bpa; 78516f62314SDavid Greenman int counta; 78626f9a767SRodney W. Grimes int s; 78726f9a767SRodney W. Grimes int failflag; 78826f9a767SRodney W. Grimes 78926f9a767SRodney W. Grimes int error = 0; 79026f9a767SRodney W. Grimes 791bbc0ec52SDavid Greenman object = m[reqpage]->object; /* all vm_page_t items are in same 792bbc0ec52SDavid Greenman * object */ 79326f9a767SRodney W. Grimes paging_offset = object->paging_offset; 79426f9a767SRodney W. Grimes 79526f9a767SRodney W. Grimes vp = vnp->vnp_vp; 7964abc71c0SDavid Greenman 7974abc71c0SDavid Greenman /* 7984abc71c0SDavid Greenman * Make sure underlying filesystem is still mounted. 7994abc71c0SDavid Greenman */ 8004abc71c0SDavid Greenman if (vp->v_mount == NULL) 8014abc71c0SDavid Greenman return VM_PAGER_FAIL; 8024abc71c0SDavid Greenman 80326f9a767SRodney W. Grimes bsize = vp->v_mount->mnt_stat.f_iosize; 80426f9a767SRodney W. Grimes 80526f9a767SRodney W. Grimes /* get the UNDERLYING device for the file with VOP_BMAP() */ 806bbc0ec52SDavid Greenman 80726f9a767SRodney W. Grimes /* 808bbc0ec52SDavid Greenman * originally, we did not check for an error return value -- assuming 809bbc0ec52SDavid Greenman * an fs always has a bmap entry point -- that assumption is wrong!!! 81026f9a767SRodney W. Grimes */ 81126f9a767SRodney W. Grimes foff = m[reqpage]->offset + paging_offset; 812bbc0ec52SDavid Greenman 81326f9a767SRodney W. Grimes /* 81416f62314SDavid Greenman * if we can't bmap, use old VOP code 81526f9a767SRodney W. Grimes */ 816bf556a16SJustin T. Gibbs if (VOP_BMAP(vp, foff, &dp, 0, 0)) { 81726f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 81826f9a767SRodney W. Grimes if (i != reqpage) { 81926f9a767SRodney W. Grimes vnode_pager_freepage(m[i]); 82026f9a767SRodney W. Grimes } 82126f9a767SRodney W. Grimes } 822976e77fcSDavid Greenman cnt.v_vnodein++; 823976e77fcSDavid Greenman cnt.v_vnodepgsin++; 82426f9a767SRodney W. Grimes return vnode_pager_input_old(vnp, m[reqpage]); 825bbc0ec52SDavid Greenman 82626f9a767SRodney W. Grimes /* 82726f9a767SRodney W. Grimes * if the blocksize is smaller than a page size, then use 82826f9a767SRodney W. Grimes * special small filesystem code. NFS sometimes has a small 82926f9a767SRodney W. Grimes * blocksize, but it can handle large reads itself. 83026f9a767SRodney W. Grimes */ 83126f9a767SRodney W. Grimes } else if ((PAGE_SIZE / bsize) > 1 && 83226f9a767SRodney W. Grimes (vp->v_mount->mnt_stat.f_type != MOUNT_NFS)) { 83326f9a767SRodney W. Grimes 83426f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 83526f9a767SRodney W. Grimes if (i != reqpage) { 83626f9a767SRodney W. Grimes vnode_pager_freepage(m[i]); 83726f9a767SRodney W. Grimes } 83826f9a767SRodney W. Grimes } 839976e77fcSDavid Greenman cnt.v_vnodein++; 840976e77fcSDavid Greenman cnt.v_vnodepgsin++; 84126f9a767SRodney W. Grimes return vnode_pager_input_smlfs(vnp, m[reqpage]); 84226f9a767SRodney W. Grimes } 84326f9a767SRodney W. Grimes /* 84426f9a767SRodney W. Grimes * here on direct device I/O 84526f9a767SRodney W. Grimes */ 84626f9a767SRodney W. Grimes 84726f9a767SRodney W. Grimes 8488e58bf68SDavid Greenman #ifdef NOTYET 8498e58bf68SDavid Greenman if( (vp->v_flag & VVMIO) == 0) { 8508e58bf68SDavid Greenman #endif 85126f9a767SRodney W. Grimes /* 85226f9a767SRodney W. Grimes * This pathetic hack gets data from the buffer cache, if it's there. 853bbc0ec52SDavid Greenman * I believe that this is not really necessary, and the ends can be 854bbc0ec52SDavid Greenman * gotten by defaulting to the normal vfs read behavior, but this 85526f9a767SRodney W. Grimes * might be more efficient, because the will NOT invoke read-aheads 856bbc0ec52SDavid Greenman * and one of the purposes of this code is to bypass the buffer cache 857bbc0ec52SDavid Greenman * and keep from flushing it by reading in a program. 85826f9a767SRodney W. Grimes */ 859bbc0ec52SDavid Greenman 86026f9a767SRodney W. Grimes /* 86126f9a767SRodney W. Grimes * calculate logical block and offset 86226f9a767SRodney W. Grimes */ 86326f9a767SRodney W. Grimes block = foff / bsize; 86426f9a767SRodney W. Grimes offset = foff % bsize; 86526f9a767SRodney W. Grimes s = splbio(); 86626f9a767SRodney W. Grimes 86726f9a767SRodney W. Grimes /* 86826f9a767SRodney W. Grimes * if we have a buffer in core, then try to use it 86926f9a767SRodney W. Grimes */ 87005f0fdd2SPoul-Henning Kamp while ((bp = incore(vp, block)) != 0) { 87126f9a767SRodney W. Grimes int amount; 87226f9a767SRodney W. Grimes 87326f9a767SRodney W. Grimes /* 87426f9a767SRodney W. Grimes * wait until the buffer is avail or gone 87526f9a767SRodney W. Grimes */ 87626f9a767SRodney W. Grimes if (bp->b_flags & B_BUSY) { 87726f9a767SRodney W. Grimes bp->b_flags |= B_WANTED; 87826f9a767SRodney W. Grimes tsleep((caddr_t) bp, PVM, "vnwblk", 0); 87926f9a767SRodney W. Grimes continue; 88026f9a767SRodney W. Grimes } 88126f9a767SRodney W. Grimes amount = PAGE_SIZE; 88226f9a767SRodney W. Grimes if ((foff + amount) > vnp->vnp_size) 88326f9a767SRodney W. Grimes amount = vnp->vnp_size - foff; 88426f9a767SRodney W. Grimes 88526f9a767SRodney W. Grimes /* 88626f9a767SRodney W. Grimes * make sure that this page is in the buffer 88726f9a767SRodney W. Grimes */ 88826f9a767SRodney W. Grimes if ((amount > 0) && (offset + amount) <= bp->b_bcount) { 88926f9a767SRodney W. Grimes bp->b_flags |= B_BUSY; 89026f9a767SRodney W. Grimes splx(s); 8918e58bf68SDavid Greenman kva = kmem_alloc_wait( pager_map, PAGE_SIZE); 89226f9a767SRodney W. Grimes 89326f9a767SRodney W. Grimes /* 89426f9a767SRodney W. Grimes * map the requested page 89526f9a767SRodney W. Grimes */ 89616f62314SDavid Greenman pmap_qenter(kva, &m[reqpage], 1); 89726f9a767SRodney W. Grimes 89826f9a767SRodney W. Grimes /* 89926f9a767SRodney W. Grimes * copy the data from the buffer 90026f9a767SRodney W. Grimes */ 90126f9a767SRodney W. Grimes bcopy(bp->b_un.b_addr + offset, (caddr_t) kva, amount); 90226f9a767SRodney W. Grimes if (amount < PAGE_SIZE) { 90326f9a767SRodney W. Grimes bzero((caddr_t) kva + amount, PAGE_SIZE - amount); 90426f9a767SRodney W. Grimes } 905bbc0ec52SDavid Greenman 90626f9a767SRodney W. Grimes /* 90726f9a767SRodney W. Grimes * unmap the page and free the kva 90826f9a767SRodney W. Grimes */ 90916f62314SDavid Greenman pmap_qremove( kva, 1); 910a481f200SDavid Greenman kmem_free_wakeup(pager_map, kva, PAGE_SIZE); 911bbc0ec52SDavid Greenman 91226f9a767SRodney W. Grimes /* 91326f9a767SRodney W. Grimes * release the buffer back to the block subsystem 91426f9a767SRodney W. Grimes */ 91526f9a767SRodney W. Grimes bp->b_flags &= ~B_BUSY; 91626f9a767SRodney W. Grimes wakeup((caddr_t) bp); 917bbc0ec52SDavid Greenman 91826f9a767SRodney W. Grimes /* 91926f9a767SRodney W. Grimes * we did not have to do any work to get the requested 92026f9a767SRodney W. Grimes * page, the read behind/ahead does not justify a read 92126f9a767SRodney W. Grimes */ 92226f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 92326f9a767SRodney W. Grimes if (i != reqpage) { 92426f9a767SRodney W. Grimes vnode_pager_freepage(m[i]); 92526f9a767SRodney W. Grimes } 92626f9a767SRodney W. Grimes } 92726f9a767SRodney W. Grimes count = 1; 92826f9a767SRodney W. Grimes reqpage = 0; 92926f9a767SRodney W. Grimes m[0] = m[reqpage]; 93026f9a767SRodney W. Grimes 93126f9a767SRodney W. Grimes /* 93226f9a767SRodney W. Grimes * sorry for the goto 93326f9a767SRodney W. Grimes */ 93426f9a767SRodney W. Grimes goto finishup; 93526f9a767SRodney W. Grimes } 936bbc0ec52SDavid Greenman 93726f9a767SRodney W. Grimes /* 93826f9a767SRodney W. Grimes * buffer is nowhere to be found, read from the disk 93926f9a767SRodney W. Grimes */ 94026f9a767SRodney W. Grimes break; 94126f9a767SRodney W. Grimes } 94226f9a767SRodney W. Grimes splx(s); 9438e58bf68SDavid Greenman #ifdef NOTYET 9448e58bf68SDavid Greenman } 9458e58bf68SDavid Greenman #endif 94626f9a767SRodney W. Grimes 94726f9a767SRodney W. Grimes reqaddr = vnode_pager_addr(vp, foff); 94826f9a767SRodney W. Grimes s = splbio(); 949bbc0ec52SDavid Greenman 95026f9a767SRodney W. Grimes /* 951bbc0ec52SDavid Greenman * Make sure that our I/O request is contiguous. Scan backward and 952bbc0ec52SDavid Greenman * stop for the first discontiguous entry or stop for a page being in 953bbc0ec52SDavid Greenman * buffer cache. 95426f9a767SRodney W. Grimes */ 95526f9a767SRodney W. Grimes failflag = 0; 95626f9a767SRodney W. Grimes first = reqpage; 95726f9a767SRodney W. Grimes for (i = reqpage - 1; i >= 0; --i) { 95826f9a767SRodney W. Grimes if (failflag || 9598e58bf68SDavid Greenman #ifdef NOTYET 9608e58bf68SDavid Greenman ((vp->v_flag & VVMIO) == 0 && incore(vp, (foff + (i - reqpage) * PAGE_SIZE) / bsize)) || 9618e58bf68SDavid Greenman #else 9628e58bf68SDavid Greenman (incore(vp, (foff + (i - reqpage) * PAGE_SIZE) / bsize)) || 9638e58bf68SDavid Greenman #endif 96426f9a767SRodney W. Grimes (vnode_pager_addr(vp, m[i]->offset + paging_offset)) 96526f9a767SRodney W. Grimes != reqaddr + (i - reqpage) * PAGE_SIZE) { 96626f9a767SRodney W. Grimes vnode_pager_freepage(m[i]); 96726f9a767SRodney W. Grimes failflag = 1; 96826f9a767SRodney W. Grimes } else { 96926f9a767SRodney W. Grimes first = i; 97026f9a767SRodney W. Grimes } 97126f9a767SRodney W. Grimes } 97226f9a767SRodney W. Grimes 97326f9a767SRodney W. Grimes /* 974bbc0ec52SDavid Greenman * Scan forward and stop for the first non-contiguous entry or stop 975bbc0ec52SDavid Greenman * for a page being in buffer cache. 97626f9a767SRodney W. Grimes */ 97726f9a767SRodney W. Grimes failflag = 0; 97826f9a767SRodney W. Grimes last = reqpage + 1; 97926f9a767SRodney W. Grimes for (i = reqpage + 1; i < count; i++) { 98026f9a767SRodney W. Grimes if (failflag || 9818e58bf68SDavid Greenman #ifdef NOTYET 9828e58bf68SDavid Greenman ((vp->v_flag & VVMIO) == 0 && incore(vp, (foff + (i - reqpage) * PAGE_SIZE) / bsize)) || 9838e58bf68SDavid Greenman #else 9848e58bf68SDavid Greenman (incore(vp, (foff + (i - reqpage) * PAGE_SIZE) / bsize)) || 9858e58bf68SDavid Greenman #endif 98626f9a767SRodney W. Grimes (vnode_pager_addr(vp, m[i]->offset + paging_offset)) 98726f9a767SRodney W. Grimes != reqaddr + (i - reqpage) * PAGE_SIZE) { 98826f9a767SRodney W. Grimes vnode_pager_freepage(m[i]); 98926f9a767SRodney W. Grimes failflag = 1; 99026f9a767SRodney W. Grimes } else { 99126f9a767SRodney W. Grimes last = i + 1; 99226f9a767SRodney W. Grimes } 99326f9a767SRodney W. Grimes } 99426f9a767SRodney W. Grimes splx(s); 99526f9a767SRodney W. Grimes 99626f9a767SRodney W. Grimes /* 997bbc0ec52SDavid Greenman * the first and last page have been calculated now, move input pages 998bbc0ec52SDavid Greenman * to be zero based... 99926f9a767SRodney W. Grimes */ 100026f9a767SRodney W. Grimes count = last; 100126f9a767SRodney W. Grimes if (first != 0) { 100226f9a767SRodney W. Grimes for (i = first; i < count; i++) { 100326f9a767SRodney W. Grimes m[i - first] = m[i]; 100426f9a767SRodney W. Grimes } 100526f9a767SRodney W. Grimes count -= first; 100626f9a767SRodney W. Grimes reqpage -= first; 100726f9a767SRodney W. Grimes } 100826f9a767SRodney W. Grimes 100926f9a767SRodney W. Grimes /* 101026f9a767SRodney W. Grimes * calculate the file virtual address for the transfer 101126f9a767SRodney W. Grimes */ 101226f9a767SRodney W. Grimes foff = m[0]->offset + paging_offset; 1013bbc0ec52SDavid Greenman 101426f9a767SRodney W. Grimes /* 101526f9a767SRodney W. Grimes * and get the disk physical address (in bytes) 101626f9a767SRodney W. Grimes */ 101726f9a767SRodney W. Grimes firstaddr = vnode_pager_addr(vp, foff); 101826f9a767SRodney W. Grimes 101926f9a767SRodney W. Grimes /* 102026f9a767SRodney W. Grimes * calculate the size of the transfer 102126f9a767SRodney W. Grimes */ 102226f9a767SRodney W. Grimes size = count * PAGE_SIZE; 102326f9a767SRodney W. Grimes if ((foff + size) > vnp->vnp_size) 102426f9a767SRodney W. Grimes size = vnp->vnp_size - foff; 102526f9a767SRodney W. Grimes 102626f9a767SRodney W. Grimes /* 102726f9a767SRodney W. Grimes * round up physical size for real devices 102826f9a767SRodney W. Grimes */ 102926f9a767SRodney W. Grimes if (dp->v_type == VBLK || dp->v_type == VCHR) 103026f9a767SRodney W. Grimes size = (size + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1); 103126f9a767SRodney W. Grimes 103216f62314SDavid Greenman counta = 0; 103316f62314SDavid Greenman if( count*PAGE_SIZE > bsize) 103416f62314SDavid Greenman counta = (count - reqpage) - 1; 103516f62314SDavid Greenman bpa = 0; 103616f62314SDavid Greenman sizea = 0; 103716f62314SDavid Greenman if( counta) { 103816f62314SDavid Greenman bpa = getpbuf(); 103916f62314SDavid Greenman count -= counta; 104016f62314SDavid Greenman sizea = size - count*PAGE_SIZE; 104116f62314SDavid Greenman size = count * PAGE_SIZE; 104216f62314SDavid Greenman } 104316f62314SDavid Greenman 104416f62314SDavid Greenman bp = getpbuf(); 104516f62314SDavid Greenman kva = (vm_offset_t)bp->b_data; 104616f62314SDavid Greenman 104726f9a767SRodney W. Grimes /* 104826f9a767SRodney W. Grimes * and map the pages to be read into the kva 104926f9a767SRodney W. Grimes */ 105016f62314SDavid Greenman pmap_qenter(kva, m, count); 105126f9a767SRodney W. Grimes VHOLD(vp); 105226f9a767SRodney W. Grimes 105326f9a767SRodney W. Grimes /* build a minimal buffer header */ 105426f9a767SRodney W. Grimes bp->b_flags = B_BUSY | B_READ | B_CALL; 105526f9a767SRodney W. Grimes bp->b_iodone = vnode_pager_iodone; 105626f9a767SRodney W. Grimes /* B_PHYS is not set, but it is nice to fill this in */ 105726f9a767SRodney W. Grimes bp->b_proc = curproc; 105826f9a767SRodney W. Grimes bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred; 105926f9a767SRodney W. Grimes if (bp->b_rcred != NOCRED) 106026f9a767SRodney W. Grimes crhold(bp->b_rcred); 106126f9a767SRodney W. Grimes if (bp->b_wcred != NOCRED) 106226f9a767SRodney W. Grimes crhold(bp->b_wcred); 106326f9a767SRodney W. Grimes bp->b_blkno = firstaddr / DEV_BSIZE; 106426f9a767SRodney W. Grimes bgetvp(dp, bp); 106526f9a767SRodney W. Grimes bp->b_bcount = size; 106626f9a767SRodney W. Grimes bp->b_bufsize = size; 106726f9a767SRodney W. Grimes 1068976e77fcSDavid Greenman cnt.v_vnodein++; 1069976e77fcSDavid Greenman cnt.v_vnodepgsin += count; 1070976e77fcSDavid Greenman 107126f9a767SRodney W. Grimes /* do the input */ 107226f9a767SRodney W. Grimes VOP_STRATEGY(bp); 1073976e77fcSDavid Greenman 107416f62314SDavid Greenman if( counta) { 107516f62314SDavid Greenman for(i=0;i<counta;i++) { 107616f62314SDavid Greenman vm_page_deactivate(m[count+i]); 107716f62314SDavid Greenman } 1078c87801feSDavid Greenman pmap_qenter((vm_offset_t)bpa->b_data, &m[count], counta); 107916f62314SDavid Greenman ++m[count]->object->paging_in_progress; 108016f62314SDavid Greenman VHOLD(vp); 108116f62314SDavid Greenman bpa->b_flags = B_BUSY | B_READ | B_CALL | B_ASYNC; 108216f62314SDavid Greenman bpa->b_iodone = vnode_pager_iodone; 108316f62314SDavid Greenman /* B_PHYS is not set, but it is nice to fill this in */ 108416f62314SDavid Greenman bpa->b_proc = curproc; 108516f62314SDavid Greenman bpa->b_rcred = bpa->b_wcred = bpa->b_proc->p_ucred; 108616f62314SDavid Greenman if (bpa->b_rcred != NOCRED) 108716f62314SDavid Greenman crhold(bpa->b_rcred); 108816f62314SDavid Greenman if (bpa->b_wcred != NOCRED) 108916f62314SDavid Greenman crhold(bpa->b_wcred); 109016f62314SDavid Greenman bpa->b_blkno = (firstaddr + count * PAGE_SIZE) / DEV_BSIZE; 109116f62314SDavid Greenman bgetvp(dp, bpa); 109216f62314SDavid Greenman bpa->b_bcount = sizea; 109316f62314SDavid Greenman bpa->b_bufsize = counta*PAGE_SIZE; 109416f62314SDavid Greenman 1095976e77fcSDavid Greenman cnt.v_vnodepgsin += counta; 109616f62314SDavid Greenman VOP_STRATEGY(bpa); 109716f62314SDavid Greenman } 109826f9a767SRodney W. Grimes 109926f9a767SRodney W. Grimes s = splbio(); 110026f9a767SRodney W. Grimes /* we definitely need to be at splbio here */ 110126f9a767SRodney W. Grimes 110226f9a767SRodney W. Grimes while ((bp->b_flags & B_DONE) == 0) { 110326f9a767SRodney W. Grimes tsleep((caddr_t) bp, PVM, "vnread", 0); 110426f9a767SRodney W. Grimes } 110526f9a767SRodney W. Grimes splx(s); 110626f9a767SRodney W. Grimes if ((bp->b_flags & B_ERROR) != 0) 110726f9a767SRodney W. Grimes error = EIO; 110826f9a767SRodney W. Grimes 110926f9a767SRodney W. Grimes if (!error) { 111026f9a767SRodney W. Grimes if (size != count * PAGE_SIZE) 111126f9a767SRodney W. Grimes bzero((caddr_t) kva + size, PAGE_SIZE * count - size); 111226f9a767SRodney W. Grimes } 111316f62314SDavid Greenman pmap_qremove( kva, count); 111426f9a767SRodney W. Grimes 111526f9a767SRodney W. Grimes /* 111626f9a767SRodney W. Grimes * free the buffer header back to the swap buffer pool 111726f9a767SRodney W. Grimes */ 111826f9a767SRodney W. Grimes relpbuf(bp); 111926f9a767SRodney W. Grimes HOLDRELE(vp); 112026f9a767SRodney W. Grimes 112126f9a767SRodney W. Grimes finishup: 112226f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 1123fff93ab6SDavid Greenman pmap_clear_modify(VM_PAGE_TO_PHYS(m[i])); 112426f9a767SRodney W. Grimes m[i]->flags |= PG_CLEAN; 112526f9a767SRodney W. Grimes m[i]->flags &= ~PG_LAUNDRY; 112626f9a767SRodney W. Grimes if (i != reqpage) { 1127bbc0ec52SDavid Greenman 112826f9a767SRodney W. Grimes /* 1129bbc0ec52SDavid Greenman * whether or not to leave the page activated is up in 1130bbc0ec52SDavid Greenman * the air, but we should put the page on a page queue 1131bbc0ec52SDavid Greenman * somewhere. (it already is in the object). Result: 1132bbc0ec52SDavid Greenman * It appears that emperical results show that 1133bbc0ec52SDavid Greenman * deactivating pages is best. 113426f9a767SRodney W. Grimes */ 1135bbc0ec52SDavid Greenman 113626f9a767SRodney W. Grimes /* 1137bbc0ec52SDavid Greenman * just in case someone was asking for this page we 1138bbc0ec52SDavid Greenman * now tell them that it is ok to use 113926f9a767SRodney W. Grimes */ 114026f9a767SRodney W. Grimes if (!error) { 114126f9a767SRodney W. Grimes vm_page_deactivate(m[i]); 114226f9a767SRodney W. Grimes PAGE_WAKEUP(m[i]); 114326f9a767SRodney W. Grimes m[i]->flags &= ~PG_FAKE; 114426f9a767SRodney W. Grimes } else { 114526f9a767SRodney W. Grimes vnode_pager_freepage(m[i]); 114626f9a767SRodney W. Grimes } 114726f9a767SRodney W. Grimes } 114826f9a767SRodney W. Grimes } 114926f9a767SRodney W. Grimes if (error) { 1150a83c285cSDavid Greenman printf("vnode_pager_input: I/O read error\n"); 115126f9a767SRodney W. Grimes } 1152a83c285cSDavid Greenman return (error ? VM_PAGER_ERROR : VM_PAGER_OK); 115326f9a767SRodney W. Grimes } 115426f9a767SRodney W. Grimes 115526f9a767SRodney W. Grimes /* 115626f9a767SRodney W. Grimes * old-style vnode pager output routine 115726f9a767SRodney W. Grimes */ 115826f9a767SRodney W. Grimes int 115926f9a767SRodney W. Grimes vnode_pager_output_old(vnp, m) 116026f9a767SRodney W. Grimes register vn_pager_t vnp; 116126f9a767SRodney W. Grimes vm_page_t m; 116226f9a767SRodney W. Grimes { 116326f9a767SRodney W. Grimes vm_offset_t foff; 116426f9a767SRodney W. Grimes vm_offset_t kva; 116526f9a767SRodney W. Grimes vm_offset_t size; 116626f9a767SRodney W. Grimes struct iovec aiov; 116726f9a767SRodney W. Grimes struct uio auio; 116826f9a767SRodney W. Grimes struct vnode *vp; 116926f9a767SRodney W. Grimes int error; 117026f9a767SRodney W. Grimes 117126f9a767SRodney W. Grimes vp = vnp->vnp_vp; 117226f9a767SRodney W. Grimes foff = m->offset + m->object->paging_offset; 1173bbc0ec52SDavid Greenman 117426f9a767SRodney W. Grimes /* 117526f9a767SRodney W. Grimes * Return failure if beyond current EOF 117626f9a767SRodney W. Grimes */ 117726f9a767SRodney W. Grimes if (foff >= vnp->vnp_size) { 117826f9a767SRodney W. Grimes return VM_PAGER_BAD; 117926f9a767SRodney W. Grimes } else { 118026f9a767SRodney W. Grimes size = PAGE_SIZE; 118126f9a767SRodney W. Grimes if (foff + size > vnp->vnp_size) 118226f9a767SRodney W. Grimes size = vnp->vnp_size - foff; 118326f9a767SRodney W. Grimes /* 118426f9a767SRodney W. Grimes * Allocate a kernel virtual address and initialize so that 118526f9a767SRodney W. Grimes * we can use VOP_WRITE routines. 118626f9a767SRodney W. Grimes */ 118726f9a767SRodney W. Grimes kva = vm_pager_map_page(m); 118826f9a767SRodney W. Grimes aiov.iov_base = (caddr_t) kva; 118926f9a767SRodney W. Grimes aiov.iov_len = size; 119026f9a767SRodney W. Grimes auio.uio_iov = &aiov; 119126f9a767SRodney W. Grimes auio.uio_iovcnt = 1; 119226f9a767SRodney W. Grimes auio.uio_offset = foff; 119326f9a767SRodney W. Grimes auio.uio_segflg = UIO_SYSSPACE; 119426f9a767SRodney W. Grimes auio.uio_rw = UIO_WRITE; 119526f9a767SRodney W. Grimes auio.uio_resid = size; 119626f9a767SRodney W. Grimes auio.uio_procp = (struct proc *) 0; 119726f9a767SRodney W. Grimes 119826f9a767SRodney W. Grimes error = VOP_WRITE(vp, &auio, 0, curproc->p_ucred); 119926f9a767SRodney W. Grimes 120026f9a767SRodney W. Grimes if (!error) { 120126f9a767SRodney W. Grimes if ((size - auio.uio_resid) == 0) { 120226f9a767SRodney W. Grimes error = EINVAL; 120326f9a767SRodney W. Grimes } 120426f9a767SRodney W. Grimes } 120526f9a767SRodney W. Grimes vm_pager_unmap_page(kva); 1206a83c285cSDavid Greenman return error ? VM_PAGER_ERROR: VM_PAGER_OK; 120726f9a767SRodney W. Grimes } 120826f9a767SRodney W. Grimes } 120926f9a767SRodney W. Grimes 121026f9a767SRodney W. Grimes /* 121126f9a767SRodney W. Grimes * vnode pager output on a small-block file system 121226f9a767SRodney W. Grimes */ 121326f9a767SRodney W. Grimes int 121426f9a767SRodney W. Grimes vnode_pager_output_smlfs(vnp, m) 121526f9a767SRodney W. Grimes vn_pager_t vnp; 121626f9a767SRodney W. Grimes vm_page_t m; 121726f9a767SRodney W. Grimes { 121826f9a767SRodney W. Grimes int i; 121926f9a767SRodney W. Grimes int s; 122026f9a767SRodney W. Grimes vm_offset_t paging_offset; 122126f9a767SRodney W. Grimes struct vnode *dp, *vp; 122226f9a767SRodney W. Grimes struct buf *bp; 122326f9a767SRodney W. Grimes vm_offset_t foff; 122426f9a767SRodney W. Grimes vm_offset_t kva; 122526f9a767SRodney W. Grimes int fileaddr; 122626f9a767SRodney W. Grimes vm_offset_t bsize; 122726f9a767SRodney W. Grimes int error = 0; 122826f9a767SRodney W. Grimes 122926f9a767SRodney W. Grimes paging_offset = m->object->paging_offset; 123026f9a767SRodney W. Grimes vp = vnp->vnp_vp; 123126f9a767SRodney W. Grimes bsize = vp->v_mount->mnt_stat.f_iosize; 123226f9a767SRodney W. Grimes foff = m->offset + paging_offset; 123326f9a767SRodney W. Grimes 123426f9a767SRodney W. Grimes VOP_BMAP(vp, foff, &dp, 0, 0); 123526f9a767SRodney W. Grimes kva = vm_pager_map_page(m); 123626f9a767SRodney W. Grimes for (i = 0; !error && i < (PAGE_SIZE / bsize); i++) { 1237bbc0ec52SDavid Greenman 123826f9a767SRodney W. Grimes /* 123926f9a767SRodney W. Grimes * calculate logical block and offset 124026f9a767SRodney W. Grimes */ 124126f9a767SRodney W. Grimes fileaddr = vnode_pager_addr(vp, foff + i * bsize); 124226f9a767SRodney W. Grimes if (fileaddr != -1) { 124326f9a767SRodney W. Grimes s = splbio(); 124405f0fdd2SPoul-Henning Kamp bp = incore(vp, (foff / bsize) + i); 124505f0fdd2SPoul-Henning Kamp if (bp) { 124626f9a767SRodney W. Grimes bp = getblk(vp, (foff / bsize) + i, bp->b_bufsize, 0, 0); 124726f9a767SRodney W. Grimes bp->b_flags |= B_INVAL; 124826f9a767SRodney W. Grimes brelse(bp); 124926f9a767SRodney W. Grimes } 125026f9a767SRodney W. Grimes splx(s); 125126f9a767SRodney W. Grimes 125226f9a767SRodney W. Grimes bp = getpbuf(); 125326f9a767SRodney W. Grimes VHOLD(vp); 125426f9a767SRodney W. Grimes 125526f9a767SRodney W. Grimes /* build a minimal buffer header */ 125626f9a767SRodney W. Grimes bp->b_flags = B_BUSY | B_CALL | B_WRITE; 125726f9a767SRodney W. Grimes bp->b_iodone = vnode_pager_iodone; 125826f9a767SRodney W. Grimes bp->b_proc = curproc; 125926f9a767SRodney W. Grimes bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred; 126026f9a767SRodney W. Grimes if (bp->b_rcred != NOCRED) 126126f9a767SRodney W. Grimes crhold(bp->b_rcred); 126226f9a767SRodney W. Grimes if (bp->b_wcred != NOCRED) 126326f9a767SRodney W. Grimes crhold(bp->b_wcred); 126426f9a767SRodney W. Grimes bp->b_un.b_addr = (caddr_t) kva + i * bsize; 126526f9a767SRodney W. Grimes bp->b_blkno = fileaddr / DEV_BSIZE; 126626f9a767SRodney W. Grimes bgetvp(dp, bp); 126726f9a767SRodney W. Grimes ++dp->v_numoutput; 126826f9a767SRodney W. Grimes /* for NFS */ 126926f9a767SRodney W. Grimes bp->b_dirtyoff = 0; 127026f9a767SRodney W. Grimes bp->b_dirtyend = bsize; 127126f9a767SRodney W. Grimes bp->b_bcount = bsize; 127226f9a767SRodney W. Grimes bp->b_bufsize = bsize; 127326f9a767SRodney W. Grimes 127426f9a767SRodney W. Grimes /* do the input */ 127526f9a767SRodney W. Grimes VOP_STRATEGY(bp); 127626f9a767SRodney W. Grimes 127726f9a767SRodney W. Grimes /* we definitely need to be at splbio here */ 127826f9a767SRodney W. Grimes 127926f9a767SRodney W. Grimes s = splbio(); 128026f9a767SRodney W. Grimes while ((bp->b_flags & B_DONE) == 0) { 128126f9a767SRodney W. Grimes tsleep((caddr_t) bp, PVM, "vnswrt", 0); 128226f9a767SRodney W. Grimes } 128326f9a767SRodney W. Grimes splx(s); 128426f9a767SRodney W. Grimes if ((bp->b_flags & B_ERROR) != 0) 128526f9a767SRodney W. Grimes error = EIO; 128626f9a767SRodney W. Grimes 128726f9a767SRodney W. Grimes /* 128826f9a767SRodney W. Grimes * free the buffer header back to the swap buffer pool 128926f9a767SRodney W. Grimes */ 129026f9a767SRodney W. Grimes relpbuf(bp); 129126f9a767SRodney W. Grimes HOLDRELE(vp); 129226f9a767SRodney W. Grimes } 129326f9a767SRodney W. Grimes } 129426f9a767SRodney W. Grimes vm_pager_unmap_page(kva); 129526f9a767SRodney W. Grimes if (error) 1296a83c285cSDavid Greenman return VM_PAGER_ERROR; 129726f9a767SRodney W. Grimes else 129826f9a767SRodney W. Grimes return VM_PAGER_OK; 129926f9a767SRodney W. Grimes } 130026f9a767SRodney W. Grimes 130126f9a767SRodney W. Grimes /* 130226f9a767SRodney W. Grimes * generic vnode pager output routine 130326f9a767SRodney W. Grimes */ 130426f9a767SRodney W. Grimes int 130526f9a767SRodney W. Grimes vnode_pager_output(vnp, m, count, rtvals) 130626f9a767SRodney W. Grimes vn_pager_t vnp; 130726f9a767SRodney W. Grimes vm_page_t *m; 130826f9a767SRodney W. Grimes int count; 130926f9a767SRodney W. Grimes int *rtvals; 131026f9a767SRodney W. Grimes { 131126f9a767SRodney W. Grimes int i, j; 131226f9a767SRodney W. Grimes vm_offset_t kva, foff; 131326f9a767SRodney W. Grimes int size; 131426f9a767SRodney W. Grimes vm_object_t object; 131526f9a767SRodney W. Grimes vm_offset_t paging_offset; 131626f9a767SRodney W. Grimes struct vnode *dp, *vp; 131726f9a767SRodney W. Grimes struct buf *bp; 131826f9a767SRodney W. Grimes vm_offset_t reqaddr; 131926f9a767SRodney W. Grimes int bsize; 132026f9a767SRodney W. Grimes int s; 132126f9a767SRodney W. Grimes 132226f9a767SRodney W. Grimes int error = 0; 132326f9a767SRodney W. Grimes 132426f9a767SRodney W. Grimes retryoutput: 132526f9a767SRodney W. Grimes object = m[0]->object; /* all vm_page_t items are in same object */ 132626f9a767SRodney W. Grimes paging_offset = object->paging_offset; 132726f9a767SRodney W. Grimes 132826f9a767SRodney W. Grimes vp = vnp->vnp_vp; 13294abc71c0SDavid Greenman 13304abc71c0SDavid Greenman /* 13314abc71c0SDavid Greenman * Make sure underlying filesystem is still mounted. 13324abc71c0SDavid Greenman */ 13334abc71c0SDavid Greenman if (vp->v_mount == NULL) 13344abc71c0SDavid Greenman return VM_PAGER_FAIL; 13354abc71c0SDavid Greenman 133626f9a767SRodney W. Grimes bsize = vp->v_mount->mnt_stat.f_iosize; 133726f9a767SRodney W. Grimes 133826f9a767SRodney W. Grimes for (i = 0; i < count; i++) 133926f9a767SRodney W. Grimes rtvals[i] = VM_PAGER_AGAIN; 134026f9a767SRodney W. Grimes 134126f9a767SRodney W. Grimes /* 1342bbc0ec52SDavid Greenman * if the filesystem does not have a bmap, then use the old code 134326f9a767SRodney W. Grimes */ 134426f9a767SRodney W. Grimes if (VOP_BMAP(vp, m[0]->offset + paging_offset, &dp, 0, 0)) { 134526f9a767SRodney W. Grimes 134626f9a767SRodney W. Grimes rtvals[0] = vnode_pager_output_old(vnp, m[0]); 134726f9a767SRodney W. Grimes 134826f9a767SRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(m[0])); 134926f9a767SRodney W. Grimes m[0]->flags |= PG_CLEAN; 135026f9a767SRodney W. Grimes m[0]->flags &= ~PG_LAUNDRY; 1351976e77fcSDavid Greenman cnt.v_vnodeout++; 1352976e77fcSDavid Greenman cnt.v_vnodepgsout++; 135326f9a767SRodney W. Grimes return rtvals[0]; 135426f9a767SRodney W. Grimes } 135526f9a767SRodney W. Grimes 135626f9a767SRodney W. Grimes /* 1357bbc0ec52SDavid Greenman * if the filesystem has a small blocksize, then use the small block 1358bbc0ec52SDavid Greenman * filesystem output code 135926f9a767SRodney W. Grimes */ 136026f9a767SRodney W. Grimes if ((bsize < PAGE_SIZE) && 136126f9a767SRodney W. Grimes (vp->v_mount->mnt_stat.f_type != MOUNT_NFS)) { 136226f9a767SRodney W. Grimes 136326f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 136426f9a767SRodney W. Grimes rtvals[i] = vnode_pager_output_smlfs(vnp, m[i]); 136526f9a767SRodney W. Grimes if (rtvals[i] == VM_PAGER_OK) { 136626f9a767SRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(m[i])); 136726f9a767SRodney W. Grimes m[i]->flags |= PG_CLEAN; 136826f9a767SRodney W. Grimes m[i]->flags &= ~PG_LAUNDRY; 136926f9a767SRodney W. Grimes } 137026f9a767SRodney W. Grimes } 1371976e77fcSDavid Greenman cnt.v_vnodeout++; 1372976e77fcSDavid Greenman cnt.v_vnodepgsout += count; 137326f9a767SRodney W. Grimes return rtvals[0]; 137426f9a767SRodney W. Grimes } 137526f9a767SRodney W. Grimes 137626f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 137726f9a767SRodney W. Grimes foff = m[i]->offset + paging_offset; 137826f9a767SRodney W. Grimes if (foff >= vnp->vnp_size) { 137926f9a767SRodney W. Grimes for (j = i; j < count; j++) 138026f9a767SRodney W. Grimes rtvals[j] = VM_PAGER_BAD; 138126f9a767SRodney W. Grimes count = i; 138226f9a767SRodney W. Grimes break; 138326f9a767SRodney W. Grimes } 138426f9a767SRodney W. Grimes } 138526f9a767SRodney W. Grimes if (count == 0) { 138626f9a767SRodney W. Grimes return rtvals[0]; 138726f9a767SRodney W. Grimes } 138826f9a767SRodney W. Grimes foff = m[0]->offset + paging_offset; 138926f9a767SRodney W. Grimes reqaddr = vnode_pager_addr(vp, foff); 1390bbc0ec52SDavid Greenman 139126f9a767SRodney W. Grimes /* 1392bbc0ec52SDavid Greenman * Scan forward and stop for the first non-contiguous entry or stop 1393bbc0ec52SDavid Greenman * for a page being in buffer cache. 139426f9a767SRodney W. Grimes */ 139526f9a767SRodney W. Grimes for (i = 1; i < count; i++) { 139626f9a767SRodney W. Grimes if (vnode_pager_addr(vp, m[i]->offset + paging_offset) 139726f9a767SRodney W. Grimes != reqaddr + i * PAGE_SIZE) { 139826f9a767SRodney W. Grimes count = i; 139926f9a767SRodney W. Grimes break; 140026f9a767SRodney W. Grimes } 140126f9a767SRodney W. Grimes } 140226f9a767SRodney W. Grimes 140326f9a767SRodney W. Grimes /* 140426f9a767SRodney W. Grimes * calculate the size of the transfer 140526f9a767SRodney W. Grimes */ 140626f9a767SRodney W. Grimes size = count * PAGE_SIZE; 140726f9a767SRodney W. Grimes if ((foff + size) > vnp->vnp_size) 140826f9a767SRodney W. Grimes size = vnp->vnp_size - foff; 140926f9a767SRodney W. Grimes 141026f9a767SRodney W. Grimes /* 141126f9a767SRodney W. Grimes * round up physical size for real devices 141226f9a767SRodney W. Grimes */ 141326f9a767SRodney W. Grimes if (dp->v_type == VBLK || dp->v_type == VCHR) 141426f9a767SRodney W. Grimes size = (size + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1); 141526f9a767SRodney W. Grimes 141616f62314SDavid Greenman bp = getpbuf(); 141716f62314SDavid Greenman kva = (vm_offset_t)bp->b_data; 141826f9a767SRodney W. Grimes /* 141926f9a767SRodney W. Grimes * and map the pages to be read into the kva 142026f9a767SRodney W. Grimes */ 142116f62314SDavid Greenman pmap_qenter(kva, m, count); 1422db141545SDavid Greenman #if 0 142326f9a767SRodney W. Grimes printf("vnode: writing foff: %d, devoff: %d, size: %d\n", 142426f9a767SRodney W. Grimes foff, reqaddr, size); 1425db141545SDavid Greenman #endif 1426bbc0ec52SDavid Greenman 142726f9a767SRodney W. Grimes /* 142826f9a767SRodney W. Grimes * next invalidate the incore vfs_bio data 142926f9a767SRodney W. Grimes */ 14308e58bf68SDavid Greenman #ifdef NOTYET 14318e58bf68SDavid Greenman if( (vp->v_flag & VVMIO) == 0) { 14328e58bf68SDavid Greenman #endif 143326f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 143426f9a767SRodney W. Grimes int filblock = (foff + i * PAGE_SIZE) / bsize; 143526f9a767SRodney W. Grimes struct buf *fbp; 143626f9a767SRodney W. Grimes 143726f9a767SRodney W. Grimes s = splbio(); 143805f0fdd2SPoul-Henning Kamp fbp = incore(vp, filblock); 143905f0fdd2SPoul-Henning Kamp if (fbp) { 144026f9a767SRodney W. Grimes fbp = getblk(vp, filblock, fbp->b_bufsize, 0, 0); 1441bbc0ec52SDavid Greenman if (fbp->b_flags & B_DELWRI) { 1442bbc0ec52SDavid Greenman if (fbp->b_bufsize <= PAGE_SIZE) 1443bbc0ec52SDavid Greenman fbp->b_flags &= ~B_DELWRI; 1444bbc0ec52SDavid Greenman else { 1445bbc0ec52SDavid Greenman bwrite(fbp); 1446bbc0ec52SDavid Greenman fbp = getblk(vp, filblock, 1447bbc0ec52SDavid Greenman fbp->b_bufsize, 0, 0); 1448bbc0ec52SDavid Greenman } 1449bbc0ec52SDavid Greenman } 145026f9a767SRodney W. Grimes fbp->b_flags |= B_INVAL; 145126f9a767SRodney W. Grimes brelse(fbp); 145226f9a767SRodney W. Grimes } 145326f9a767SRodney W. Grimes splx(s); 145426f9a767SRodney W. Grimes } 14558e58bf68SDavid Greenman #ifdef NOTYET 14568e58bf68SDavid Greenman } 14578e58bf68SDavid Greenman #endif 145826f9a767SRodney W. Grimes 145926f9a767SRodney W. Grimes 146026f9a767SRodney W. Grimes VHOLD(vp); 146126f9a767SRodney W. Grimes /* build a minimal buffer header */ 146226f9a767SRodney W. Grimes bp->b_flags = B_BUSY | B_WRITE | B_CALL; 146326f9a767SRodney W. Grimes bp->b_iodone = vnode_pager_iodone; 146426f9a767SRodney W. Grimes /* B_PHYS is not set, but it is nice to fill this in */ 146526f9a767SRodney W. Grimes bp->b_proc = curproc; 146626f9a767SRodney W. Grimes bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred; 146726f9a767SRodney W. Grimes 146826f9a767SRodney W. Grimes if (bp->b_rcred != NOCRED) 146926f9a767SRodney W. Grimes crhold(bp->b_rcred); 147026f9a767SRodney W. Grimes if (bp->b_wcred != NOCRED) 147126f9a767SRodney W. Grimes crhold(bp->b_wcred); 147226f9a767SRodney W. Grimes bp->b_blkno = reqaddr / DEV_BSIZE; 147326f9a767SRodney W. Grimes bgetvp(dp, bp); 147426f9a767SRodney W. Grimes ++dp->v_numoutput; 147526f9a767SRodney W. Grimes 147626f9a767SRodney W. Grimes /* for NFS */ 147726f9a767SRodney W. Grimes bp->b_dirtyoff = 0; 147826f9a767SRodney W. Grimes bp->b_dirtyend = size; 147926f9a767SRodney W. Grimes 148026f9a767SRodney W. Grimes bp->b_bcount = size; 148126f9a767SRodney W. Grimes bp->b_bufsize = size; 148226f9a767SRodney W. Grimes 1483976e77fcSDavid Greenman cnt.v_vnodeout++; 1484976e77fcSDavid Greenman cnt.v_vnodepgsout += count; 1485976e77fcSDavid Greenman 148626f9a767SRodney W. Grimes /* do the output */ 148726f9a767SRodney W. Grimes VOP_STRATEGY(bp); 148826f9a767SRodney W. Grimes 148926f9a767SRodney W. Grimes s = splbio(); 149026f9a767SRodney W. Grimes 149126f9a767SRodney W. Grimes /* we definitely need to be at splbio here */ 149226f9a767SRodney W. Grimes 149326f9a767SRodney W. Grimes while ((bp->b_flags & B_DONE) == 0) { 149426f9a767SRodney W. Grimes tsleep((caddr_t) bp, PVM, "vnwrite", 0); 149526f9a767SRodney W. Grimes } 149626f9a767SRodney W. Grimes splx(s); 149726f9a767SRodney W. Grimes 149826f9a767SRodney W. Grimes if ((bp->b_flags & B_ERROR) != 0) 149926f9a767SRodney W. Grimes error = EIO; 150026f9a767SRodney W. Grimes 150116f62314SDavid Greenman pmap_qremove( kva, count); 150226f9a767SRodney W. Grimes 150326f9a767SRodney W. Grimes /* 150426f9a767SRodney W. Grimes * free the buffer header back to the swap buffer pool 150526f9a767SRodney W. Grimes */ 150626f9a767SRodney W. Grimes relpbuf(bp); 150726f9a767SRodney W. Grimes HOLDRELE(vp); 150826f9a767SRodney W. Grimes 150926f9a767SRodney W. Grimes if (!error) { 151026f9a767SRodney W. Grimes for (i = 0; i < count; i++) { 151126f9a767SRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(m[i])); 151226f9a767SRodney W. Grimes m[i]->flags |= PG_CLEAN; 151326f9a767SRodney W. Grimes m[i]->flags &= ~PG_LAUNDRY; 151426f9a767SRodney W. Grimes rtvals[i] = VM_PAGER_OK; 151526f9a767SRodney W. Grimes } 151626f9a767SRodney W. Grimes } else if (count != 1) { 151726f9a767SRodney W. Grimes error = 0; 151826f9a767SRodney W. Grimes count = 1; 151926f9a767SRodney W. Grimes goto retryoutput; 152026f9a767SRodney W. Grimes } 152126f9a767SRodney W. Grimes if (error) { 1522a83c285cSDavid Greenman printf("vnode_pager_output: I/O write error\n"); 152326f9a767SRodney W. Grimes } 1524a83c285cSDavid Greenman return (error ? VM_PAGER_ERROR: VM_PAGER_OK); 152526f9a767SRodney W. Grimes } 1526