1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1990 University of Utah. 3df8bae1dSRodney W. Grimes * Copyright (c) 1991, 1993 4df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 5df8bae1dSRodney W. Grimes * 6df8bae1dSRodney W. Grimes * This code is derived from software contributed to Berkeley by 7df8bae1dSRodney W. Grimes * the Systems Programming Group of the University of Utah Computer 8df8bae1dSRodney W. Grimes * Science Department. 9df8bae1dSRodney W. Grimes * 10df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 11df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 12df8bae1dSRodney W. Grimes * are met: 13df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 14df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 15df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 16df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 17df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 18df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 19df8bae1dSRodney W. Grimes * must display the following acknowledgement: 20df8bae1dSRodney W. Grimes * This product includes software developed by the University of 21df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 22df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 23df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 24df8bae1dSRodney W. Grimes * without specific prior written permission. 25df8bae1dSRodney W. Grimes * 26df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36df8bae1dSRodney W. Grimes * SUCH DAMAGE. 37df8bae1dSRodney W. Grimes * 38df8bae1dSRodney W. Grimes * @(#)vnode_pager.c 8.8 (Berkeley) 2/13/94 39df8bae1dSRodney W. Grimes */ 40df8bae1dSRodney W. Grimes 41df8bae1dSRodney W. Grimes /* 42df8bae1dSRodney W. Grimes * Page to/from files (vnodes). 43df8bae1dSRodney W. Grimes * 44df8bae1dSRodney W. Grimes * TODO: 45df8bae1dSRodney W. Grimes * pageouts 46df8bae1dSRodney W. Grimes * fix credential use (uses current process credentials now) 47df8bae1dSRodney W. Grimes */ 48df8bae1dSRodney W. Grimes 49df8bae1dSRodney W. Grimes #include <sys/param.h> 50df8bae1dSRodney W. Grimes #include <sys/systm.h> 51df8bae1dSRodney W. Grimes #include <sys/proc.h> 52df8bae1dSRodney W. Grimes #include <sys/malloc.h> 53df8bae1dSRodney W. Grimes #include <sys/vnode.h> 54df8bae1dSRodney W. Grimes #include <sys/uio.h> 55df8bae1dSRodney W. Grimes #include <sys/mount.h> 56df8bae1dSRodney W. Grimes 57df8bae1dSRodney W. Grimes #include <vm/vm.h> 58df8bae1dSRodney W. Grimes #include <vm/vm_page.h> 59df8bae1dSRodney W. Grimes #include <vm/vnode_pager.h> 60df8bae1dSRodney W. Grimes 61df8bae1dSRodney W. Grimes struct pagerlst vnode_pager_list; /* list of managed vnodes */ 62df8bae1dSRodney W. Grimes 63df8bae1dSRodney W. Grimes #ifdef DEBUG 64df8bae1dSRodney W. Grimes int vpagerdebug = 0x00; 65df8bae1dSRodney W. Grimes #define VDB_FOLLOW 0x01 66df8bae1dSRodney W. Grimes #define VDB_INIT 0x02 67df8bae1dSRodney W. Grimes #define VDB_IO 0x04 68df8bae1dSRodney W. Grimes #define VDB_FAIL 0x08 69df8bae1dSRodney W. Grimes #define VDB_ALLOC 0x10 70df8bae1dSRodney W. Grimes #define VDB_SIZE 0x20 71df8bae1dSRodney W. Grimes #endif 72df8bae1dSRodney W. Grimes 73df8bae1dSRodney W. Grimes static vm_pager_t vnode_pager_alloc 74df8bae1dSRodney W. Grimes __P((caddr_t, vm_size_t, vm_prot_t, vm_offset_t)); 75df8bae1dSRodney W. Grimes static void vnode_pager_cluster 76df8bae1dSRodney W. Grimes __P((vm_pager_t, vm_offset_t, 77df8bae1dSRodney W. Grimes vm_offset_t *, vm_offset_t *)); 78df8bae1dSRodney W. Grimes static void vnode_pager_dealloc __P((vm_pager_t)); 79df8bae1dSRodney W. Grimes static int vnode_pager_getpage 80df8bae1dSRodney W. Grimes __P((vm_pager_t, vm_page_t *, int, boolean_t)); 81df8bae1dSRodney W. Grimes static boolean_t vnode_pager_haspage __P((vm_pager_t, vm_offset_t)); 82df8bae1dSRodney W. Grimes static void vnode_pager_init __P((void)); 83df8bae1dSRodney W. Grimes static int vnode_pager_io 84df8bae1dSRodney W. Grimes __P((vn_pager_t, vm_page_t *, int, 85df8bae1dSRodney W. Grimes boolean_t, enum uio_rw)); 86df8bae1dSRodney W. Grimes static boolean_t vnode_pager_putpage 87df8bae1dSRodney W. Grimes __P((vm_pager_t, vm_page_t *, int, boolean_t)); 88df8bae1dSRodney W. Grimes 89df8bae1dSRodney W. Grimes struct pagerops vnodepagerops = { 90df8bae1dSRodney W. Grimes vnode_pager_init, 91df8bae1dSRodney W. Grimes vnode_pager_alloc, 92df8bae1dSRodney W. Grimes vnode_pager_dealloc, 93df8bae1dSRodney W. Grimes vnode_pager_getpage, 94df8bae1dSRodney W. Grimes vnode_pager_putpage, 95df8bae1dSRodney W. Grimes vnode_pager_haspage, 96df8bae1dSRodney W. Grimes vnode_pager_cluster 97df8bae1dSRodney W. Grimes }; 98df8bae1dSRodney W. Grimes 99df8bae1dSRodney W. Grimes static void 100df8bae1dSRodney W. Grimes vnode_pager_init() 101df8bae1dSRodney W. Grimes { 102df8bae1dSRodney W. Grimes #ifdef DEBUG 103df8bae1dSRodney W. Grimes if (vpagerdebug & VDB_FOLLOW) 104df8bae1dSRodney W. Grimes printf("vnode_pager_init()\n"); 105df8bae1dSRodney W. Grimes #endif 106df8bae1dSRodney W. Grimes TAILQ_INIT(&vnode_pager_list); 107df8bae1dSRodney W. Grimes } 108df8bae1dSRodney W. Grimes 109df8bae1dSRodney W. Grimes /* 110df8bae1dSRodney W. Grimes * Allocate (or lookup) pager for a vnode. 111df8bae1dSRodney W. Grimes * Handle is a vnode pointer. 112df8bae1dSRodney W. Grimes */ 113df8bae1dSRodney W. Grimes static vm_pager_t 114df8bae1dSRodney W. Grimes vnode_pager_alloc(handle, size, prot, foff) 115df8bae1dSRodney W. Grimes caddr_t handle; 116df8bae1dSRodney W. Grimes vm_size_t size; 117df8bae1dSRodney W. Grimes vm_prot_t prot; 118df8bae1dSRodney W. Grimes vm_offset_t foff; 119df8bae1dSRodney W. Grimes { 120df8bae1dSRodney W. Grimes register vm_pager_t pager; 121df8bae1dSRodney W. Grimes register vn_pager_t vnp; 122df8bae1dSRodney W. Grimes vm_object_t object; 123df8bae1dSRodney W. Grimes struct vattr vattr; 124df8bae1dSRodney W. Grimes struct vnode *vp; 125df8bae1dSRodney W. Grimes struct proc *p = curproc; /* XXX */ 126df8bae1dSRodney W. Grimes 127df8bae1dSRodney W. Grimes #ifdef DEBUG 128df8bae1dSRodney W. Grimes if (vpagerdebug & (VDB_FOLLOW|VDB_ALLOC)) 129df8bae1dSRodney W. Grimes printf("vnode_pager_alloc(%x, %x, %x)\n", handle, size, prot); 130df8bae1dSRodney W. Grimes #endif 131df8bae1dSRodney W. Grimes /* 132df8bae1dSRodney W. Grimes * Pageout to vnode, no can do yet. 133df8bae1dSRodney W. Grimes */ 134df8bae1dSRodney W. Grimes if (handle == NULL) 135df8bae1dSRodney W. Grimes return(NULL); 136df8bae1dSRodney W. Grimes 137df8bae1dSRodney W. Grimes /* 138df8bae1dSRodney W. Grimes * Vnodes keep a pointer to any associated pager so no need to 139df8bae1dSRodney W. Grimes * lookup with vm_pager_lookup. 140df8bae1dSRodney W. Grimes */ 141df8bae1dSRodney W. Grimes vp = (struct vnode *)handle; 142df8bae1dSRodney W. Grimes pager = (vm_pager_t)vp->v_vmdata; 143df8bae1dSRodney W. Grimes if (pager == NULL) { 144df8bae1dSRodney W. Grimes /* 145df8bae1dSRodney W. Grimes * Allocate pager structures 146df8bae1dSRodney W. Grimes */ 147df8bae1dSRodney W. Grimes pager = (vm_pager_t)malloc(sizeof *pager, M_VMPAGER, M_WAITOK); 148df8bae1dSRodney W. Grimes if (pager == NULL) 149df8bae1dSRodney W. Grimes return(NULL); 150df8bae1dSRodney W. Grimes vnp = (vn_pager_t)malloc(sizeof *vnp, M_VMPGDATA, M_WAITOK); 151df8bae1dSRodney W. Grimes if (vnp == NULL) { 152df8bae1dSRodney W. Grimes free((caddr_t)pager, M_VMPAGER); 153df8bae1dSRodney W. Grimes return(NULL); 154df8bae1dSRodney W. Grimes } 155df8bae1dSRodney W. Grimes /* 156df8bae1dSRodney W. Grimes * And an object of the appropriate size 157df8bae1dSRodney W. Grimes */ 158df8bae1dSRodney W. Grimes if (VOP_GETATTR(vp, &vattr, p->p_ucred, p) == 0) { 159df8bae1dSRodney W. Grimes object = vm_object_allocate(round_page(vattr.va_size)); 160df8bae1dSRodney W. Grimes vm_object_enter(object, pager); 161df8bae1dSRodney W. Grimes vm_object_setpager(object, pager, 0, TRUE); 162df8bae1dSRodney W. Grimes } else { 163df8bae1dSRodney W. Grimes free((caddr_t)vnp, M_VMPGDATA); 164df8bae1dSRodney W. Grimes free((caddr_t)pager, M_VMPAGER); 165df8bae1dSRodney W. Grimes return(NULL); 166df8bae1dSRodney W. Grimes } 167df8bae1dSRodney W. Grimes /* 168df8bae1dSRodney W. Grimes * Hold a reference to the vnode and initialize pager data. 169df8bae1dSRodney W. Grimes */ 170df8bae1dSRodney W. Grimes VREF(vp); 171df8bae1dSRodney W. Grimes vnp->vnp_flags = 0; 172df8bae1dSRodney W. Grimes vnp->vnp_vp = vp; 173df8bae1dSRodney W. Grimes vnp->vnp_size = vattr.va_size; 174df8bae1dSRodney W. Grimes TAILQ_INSERT_TAIL(&vnode_pager_list, pager, pg_list); 175df8bae1dSRodney W. Grimes pager->pg_handle = handle; 176df8bae1dSRodney W. Grimes pager->pg_type = PG_VNODE; 177df8bae1dSRodney W. Grimes pager->pg_flags = 0; 178df8bae1dSRodney W. Grimes pager->pg_ops = &vnodepagerops; 179df8bae1dSRodney W. Grimes pager->pg_data = vnp; 180df8bae1dSRodney W. Grimes vp->v_vmdata = (caddr_t)pager; 181df8bae1dSRodney W. Grimes } else { 182df8bae1dSRodney W. Grimes /* 183df8bae1dSRodney W. Grimes * vm_object_lookup() will remove the object from the 184df8bae1dSRodney W. Grimes * cache if found and also gain a reference to the object. 185df8bae1dSRodney W. Grimes */ 186df8bae1dSRodney W. Grimes object = vm_object_lookup(pager); 187df8bae1dSRodney W. Grimes #ifdef DEBUG 188df8bae1dSRodney W. Grimes vnp = (vn_pager_t)pager->pg_data; 189df8bae1dSRodney W. Grimes #endif 190df8bae1dSRodney W. Grimes } 191df8bae1dSRodney W. Grimes #ifdef DEBUG 192df8bae1dSRodney W. Grimes if (vpagerdebug & VDB_ALLOC) 193df8bae1dSRodney W. Grimes printf("vnode_pager_setup: vp %x sz %x pager %x object %x\n", 194df8bae1dSRodney W. Grimes vp, vnp->vnp_size, pager, object); 195df8bae1dSRodney W. Grimes #endif 196df8bae1dSRodney W. Grimes return(pager); 197df8bae1dSRodney W. Grimes } 198df8bae1dSRodney W. Grimes 199df8bae1dSRodney W. Grimes static void 200df8bae1dSRodney W. Grimes vnode_pager_dealloc(pager) 201df8bae1dSRodney W. Grimes vm_pager_t pager; 202df8bae1dSRodney W. Grimes { 203df8bae1dSRodney W. Grimes register vn_pager_t vnp = (vn_pager_t)pager->pg_data; 204df8bae1dSRodney W. Grimes register struct vnode *vp; 205df8bae1dSRodney W. Grimes #ifdef NOTDEF 206df8bae1dSRodney W. Grimes struct proc *p = curproc; /* XXX */ 207df8bae1dSRodney W. Grimes #endif 208df8bae1dSRodney W. Grimes 209df8bae1dSRodney W. Grimes #ifdef DEBUG 210df8bae1dSRodney W. Grimes if (vpagerdebug & VDB_FOLLOW) 211df8bae1dSRodney W. Grimes printf("vnode_pager_dealloc(%x)\n", pager); 212df8bae1dSRodney W. Grimes #endif 213df8bae1dSRodney W. Grimes if (vp = vnp->vnp_vp) { 214df8bae1dSRodney W. Grimes vp->v_vmdata = NULL; 215df8bae1dSRodney W. Grimes vp->v_flag &= ~VTEXT; 216df8bae1dSRodney W. Grimes #if NOTDEF 217df8bae1dSRodney W. Grimes /* can hang if done at reboot on NFS FS */ 218df8bae1dSRodney W. Grimes (void) VOP_FSYNC(vp, p->p_ucred, p); 219df8bae1dSRodney W. Grimes #endif 220df8bae1dSRodney W. Grimes vrele(vp); 221df8bae1dSRodney W. Grimes } 222df8bae1dSRodney W. Grimes TAILQ_REMOVE(&vnode_pager_list, pager, pg_list); 223df8bae1dSRodney W. Grimes free((caddr_t)vnp, M_VMPGDATA); 224df8bae1dSRodney W. Grimes free((caddr_t)pager, M_VMPAGER); 225df8bae1dSRodney W. Grimes } 226df8bae1dSRodney W. Grimes 227df8bae1dSRodney W. Grimes static int 228df8bae1dSRodney W. Grimes vnode_pager_getpage(pager, mlist, npages, sync) 229df8bae1dSRodney W. Grimes vm_pager_t pager; 230df8bae1dSRodney W. Grimes vm_page_t *mlist; 231df8bae1dSRodney W. Grimes int npages; 232df8bae1dSRodney W. Grimes boolean_t sync; 233df8bae1dSRodney W. Grimes { 234df8bae1dSRodney W. Grimes 235df8bae1dSRodney W. Grimes #ifdef DEBUG 236df8bae1dSRodney W. Grimes if (vpagerdebug & VDB_FOLLOW) 237df8bae1dSRodney W. Grimes printf("vnode_pager_getpage(%x, %x, %x, %x)\n", 238df8bae1dSRodney W. Grimes pager, mlist, npages, sync); 239df8bae1dSRodney W. Grimes #endif 240df8bae1dSRodney W. Grimes return(vnode_pager_io((vn_pager_t)pager->pg_data, 241df8bae1dSRodney W. Grimes mlist, npages, sync, UIO_READ)); 242df8bae1dSRodney W. Grimes } 243df8bae1dSRodney W. Grimes 244df8bae1dSRodney W. Grimes static boolean_t 245df8bae1dSRodney W. Grimes vnode_pager_putpage(pager, mlist, npages, sync) 246df8bae1dSRodney W. Grimes vm_pager_t pager; 247df8bae1dSRodney W. Grimes vm_page_t *mlist; 248df8bae1dSRodney W. Grimes int npages; 249df8bae1dSRodney W. Grimes boolean_t sync; 250df8bae1dSRodney W. Grimes { 251df8bae1dSRodney W. Grimes int err; 252df8bae1dSRodney W. Grimes 253df8bae1dSRodney W. Grimes #ifdef DEBUG 254df8bae1dSRodney W. Grimes if (vpagerdebug & VDB_FOLLOW) 255df8bae1dSRodney W. Grimes printf("vnode_pager_putpage(%x, %x, %x, %x)\n", 256df8bae1dSRodney W. Grimes pager, mlist, npages, sync); 257df8bae1dSRodney W. Grimes #endif 258df8bae1dSRodney W. Grimes if (pager == NULL) 259df8bae1dSRodney W. Grimes return (FALSE); /* ??? */ 260df8bae1dSRodney W. Grimes err = vnode_pager_io((vn_pager_t)pager->pg_data, 261df8bae1dSRodney W. Grimes mlist, npages, sync, UIO_WRITE); 262df8bae1dSRodney W. Grimes /* 263df8bae1dSRodney W. Grimes * If the operation was successful, mark the pages clean. 264df8bae1dSRodney W. Grimes */ 265df8bae1dSRodney W. Grimes if (err == VM_PAGER_OK) { 266df8bae1dSRodney W. Grimes while (npages--) { 267df8bae1dSRodney W. Grimes (*mlist)->flags |= PG_CLEAN; 268df8bae1dSRodney W. Grimes pmap_clear_modify(VM_PAGE_TO_PHYS(*mlist)); 269df8bae1dSRodney W. Grimes mlist++; 270df8bae1dSRodney W. Grimes } 271df8bae1dSRodney W. Grimes } 272df8bae1dSRodney W. Grimes return(err); 273df8bae1dSRodney W. Grimes } 274df8bae1dSRodney W. Grimes 275df8bae1dSRodney W. Grimes static boolean_t 276df8bae1dSRodney W. Grimes vnode_pager_haspage(pager, offset) 277df8bae1dSRodney W. Grimes vm_pager_t pager; 278df8bae1dSRodney W. Grimes vm_offset_t offset; 279df8bae1dSRodney W. Grimes { 280df8bae1dSRodney W. Grimes register vn_pager_t vnp = (vn_pager_t)pager->pg_data; 281df8bae1dSRodney W. Grimes daddr_t bn; 282df8bae1dSRodney W. Grimes int err; 283df8bae1dSRodney W. Grimes 284df8bae1dSRodney W. Grimes #ifdef DEBUG 285df8bae1dSRodney W. Grimes if (vpagerdebug & VDB_FOLLOW) 286df8bae1dSRodney W. Grimes printf("vnode_pager_haspage(%x, %x)\n", pager, offset); 287df8bae1dSRodney W. Grimes #endif 288df8bae1dSRodney W. Grimes 289df8bae1dSRodney W. Grimes /* 290df8bae1dSRodney W. Grimes * Offset beyond end of file, do not have the page 291df8bae1dSRodney W. Grimes * Lock the vnode first to make sure we have the most recent 292df8bae1dSRodney W. Grimes * version of the size. 293df8bae1dSRodney W. Grimes */ 294df8bae1dSRodney W. Grimes VOP_LOCK(vnp->vnp_vp); 295df8bae1dSRodney W. Grimes if (offset >= vnp->vnp_size) { 296df8bae1dSRodney W. Grimes VOP_UNLOCK(vnp->vnp_vp); 297df8bae1dSRodney W. Grimes #ifdef DEBUG 298df8bae1dSRodney W. Grimes if (vpagerdebug & (VDB_FAIL|VDB_SIZE)) 299df8bae1dSRodney W. Grimes printf("vnode_pager_haspage: pg %x, off %x, size %x\n", 300df8bae1dSRodney W. Grimes pager, offset, vnp->vnp_size); 301df8bae1dSRodney W. Grimes #endif 302df8bae1dSRodney W. Grimes return(FALSE); 303df8bae1dSRodney W. Grimes } 304df8bae1dSRodney W. Grimes 305df8bae1dSRodney W. Grimes /* 306df8bae1dSRodney W. Grimes * Read the index to find the disk block to read 307df8bae1dSRodney W. Grimes * from. If there is no block, report that we don't 308df8bae1dSRodney W. Grimes * have this data. 309df8bae1dSRodney W. Grimes * 310df8bae1dSRodney W. Grimes * Assumes that the vnode has whole page or nothing. 311df8bae1dSRodney W. Grimes */ 312df8bae1dSRodney W. Grimes err = VOP_BMAP(vnp->vnp_vp, 313df8bae1dSRodney W. Grimes offset / vnp->vnp_vp->v_mount->mnt_stat.f_iosize, 314df8bae1dSRodney W. Grimes (struct vnode **)0, &bn, NULL); 315df8bae1dSRodney W. Grimes VOP_UNLOCK(vnp->vnp_vp); 316df8bae1dSRodney W. Grimes if (err) { 317df8bae1dSRodney W. Grimes #ifdef DEBUG 318df8bae1dSRodney W. Grimes if (vpagerdebug & VDB_FAIL) 319df8bae1dSRodney W. Grimes printf("vnode_pager_haspage: BMAP err %d, pg %x, off %x\n", 320df8bae1dSRodney W. Grimes err, pager, offset); 321df8bae1dSRodney W. Grimes #endif 322df8bae1dSRodney W. Grimes return(TRUE); 323df8bae1dSRodney W. Grimes } 324df8bae1dSRodney W. Grimes return((long)bn < 0 ? FALSE : TRUE); 325df8bae1dSRodney W. Grimes } 326df8bae1dSRodney W. Grimes 327df8bae1dSRodney W. Grimes static void 328df8bae1dSRodney W. Grimes vnode_pager_cluster(pager, offset, loffset, hoffset) 329df8bae1dSRodney W. Grimes vm_pager_t pager; 330df8bae1dSRodney W. Grimes vm_offset_t offset; 331df8bae1dSRodney W. Grimes vm_offset_t *loffset; 332df8bae1dSRodney W. Grimes vm_offset_t *hoffset; 333df8bae1dSRodney W. Grimes { 334df8bae1dSRodney W. Grimes vn_pager_t vnp = (vn_pager_t)pager->pg_data; 335df8bae1dSRodney W. Grimes vm_offset_t loff, hoff; 336df8bae1dSRodney W. Grimes 337df8bae1dSRodney W. Grimes #ifdef DEBUG 338df8bae1dSRodney W. Grimes if (vpagerdebug & VDB_FOLLOW) 339df8bae1dSRodney W. Grimes printf("vnode_pager_cluster(%x, %x) ", pager, offset); 340df8bae1dSRodney W. Grimes #endif 341df8bae1dSRodney W. Grimes loff = offset; 342df8bae1dSRodney W. Grimes if (loff >= vnp->vnp_size) 343df8bae1dSRodney W. Grimes panic("vnode_pager_cluster: bad offset"); 344df8bae1dSRodney W. Grimes /* 345df8bae1dSRodney W. Grimes * XXX could use VOP_BMAP to get maxcontig value 346df8bae1dSRodney W. Grimes */ 347df8bae1dSRodney W. Grimes hoff = loff + MAXBSIZE; 348df8bae1dSRodney W. Grimes if (hoff > round_page(vnp->vnp_size)) 349df8bae1dSRodney W. Grimes hoff = round_page(vnp->vnp_size); 350df8bae1dSRodney W. Grimes 351df8bae1dSRodney W. Grimes *loffset = loff; 352df8bae1dSRodney W. Grimes *hoffset = hoff; 353df8bae1dSRodney W. Grimes #ifdef DEBUG 354df8bae1dSRodney W. Grimes if (vpagerdebug & VDB_FOLLOW) 355df8bae1dSRodney W. Grimes printf("returns [%x-%x]\n", loff, hoff); 356df8bae1dSRodney W. Grimes #endif 357df8bae1dSRodney W. Grimes } 358df8bae1dSRodney W. Grimes 359df8bae1dSRodney W. Grimes /* 360df8bae1dSRodney W. Grimes * (XXX) 361df8bae1dSRodney W. Grimes * Lets the VM system know about a change in size for a file. 362df8bae1dSRodney W. Grimes * If this vnode is mapped into some address space (i.e. we have a pager 363df8bae1dSRodney W. Grimes * for it) we adjust our own internal size and flush any cached pages in 364df8bae1dSRodney W. Grimes * the associated object that are affected by the size change. 365df8bae1dSRodney W. Grimes * 366df8bae1dSRodney W. Grimes * Note: this routine may be invoked as a result of a pager put 367df8bae1dSRodney W. Grimes * operation (possibly at object termination time), so we must be careful. 368df8bae1dSRodney W. Grimes */ 369df8bae1dSRodney W. Grimes void 370df8bae1dSRodney W. Grimes vnode_pager_setsize(vp, nsize) 371df8bae1dSRodney W. Grimes struct vnode *vp; 372df8bae1dSRodney W. Grimes u_long nsize; 373df8bae1dSRodney W. Grimes { 374df8bae1dSRodney W. Grimes register vn_pager_t vnp; 375df8bae1dSRodney W. Grimes register vm_object_t object; 376df8bae1dSRodney W. Grimes vm_pager_t pager; 377df8bae1dSRodney W. Grimes 378df8bae1dSRodney W. Grimes /* 379df8bae1dSRodney W. Grimes * Not a mapped vnode 380df8bae1dSRodney W. Grimes */ 381df8bae1dSRodney W. Grimes if (vp == NULL || vp->v_type != VREG || vp->v_vmdata == NULL) 382df8bae1dSRodney W. Grimes return; 383df8bae1dSRodney W. Grimes /* 384df8bae1dSRodney W. Grimes * Hasn't changed size 385df8bae1dSRodney W. Grimes */ 386df8bae1dSRodney W. Grimes pager = (vm_pager_t)vp->v_vmdata; 387df8bae1dSRodney W. Grimes vnp = (vn_pager_t)pager->pg_data; 388df8bae1dSRodney W. Grimes if (nsize == vnp->vnp_size) 389df8bae1dSRodney W. Grimes return; 390df8bae1dSRodney W. Grimes /* 391df8bae1dSRodney W. Grimes * No object. 392df8bae1dSRodney W. Grimes * This can happen during object termination since 393df8bae1dSRodney W. Grimes * vm_object_page_clean is called after the object 394df8bae1dSRodney W. Grimes * has been removed from the hash table, and clean 395df8bae1dSRodney W. Grimes * may cause vnode write operations which can wind 396df8bae1dSRodney W. Grimes * up back here. 397df8bae1dSRodney W. Grimes */ 398df8bae1dSRodney W. Grimes object = vm_object_lookup(pager); 399df8bae1dSRodney W. Grimes if (object == NULL) 400df8bae1dSRodney W. Grimes return; 401df8bae1dSRodney W. Grimes 402df8bae1dSRodney W. Grimes #ifdef DEBUG 403df8bae1dSRodney W. Grimes if (vpagerdebug & (VDB_FOLLOW|VDB_SIZE)) 404df8bae1dSRodney W. Grimes printf("vnode_pager_setsize: vp %x obj %x osz %d nsz %d\n", 405df8bae1dSRodney W. Grimes vp, object, vnp->vnp_size, nsize); 406df8bae1dSRodney W. Grimes #endif 407df8bae1dSRodney W. Grimes /* 408df8bae1dSRodney W. Grimes * File has shrunk. 409df8bae1dSRodney W. Grimes * Toss any cached pages beyond the new EOF. 410df8bae1dSRodney W. Grimes */ 411df8bae1dSRodney W. Grimes if (nsize < vnp->vnp_size) { 412df8bae1dSRodney W. Grimes vm_object_lock(object); 413df8bae1dSRodney W. Grimes vm_object_page_remove(object, 414df8bae1dSRodney W. Grimes (vm_offset_t)nsize, vnp->vnp_size); 415df8bae1dSRodney W. Grimes vm_object_unlock(object); 416df8bae1dSRodney W. Grimes } 417df8bae1dSRodney W. Grimes vnp->vnp_size = (vm_offset_t)nsize; 418df8bae1dSRodney W. Grimes vm_object_deallocate(object); 419df8bae1dSRodney W. Grimes } 420df8bae1dSRodney W. Grimes 421df8bae1dSRodney W. Grimes void 422df8bae1dSRodney W. Grimes vnode_pager_umount(mp) 423df8bae1dSRodney W. Grimes register struct mount *mp; 424df8bae1dSRodney W. Grimes { 425df8bae1dSRodney W. Grimes register vm_pager_t pager, npager; 426df8bae1dSRodney W. Grimes struct vnode *vp; 427df8bae1dSRodney W. Grimes 428df8bae1dSRodney W. Grimes for (pager = vnode_pager_list.tqh_first; pager != NULL; pager = npager){ 429df8bae1dSRodney W. Grimes /* 430df8bae1dSRodney W. Grimes * Save the next pointer now since uncaching may 431df8bae1dSRodney W. Grimes * terminate the object and render pager invalid 432df8bae1dSRodney W. Grimes */ 433df8bae1dSRodney W. Grimes npager = pager->pg_list.tqe_next; 434df8bae1dSRodney W. Grimes vp = ((vn_pager_t)pager->pg_data)->vnp_vp; 435df8bae1dSRodney W. Grimes if (mp == (struct mount *)0 || vp->v_mount == mp) { 436df8bae1dSRodney W. Grimes VOP_LOCK(vp); 437df8bae1dSRodney W. Grimes (void) vnode_pager_uncache(vp); 438df8bae1dSRodney W. Grimes VOP_UNLOCK(vp); 439df8bae1dSRodney W. Grimes } 440df8bae1dSRodney W. Grimes } 441df8bae1dSRodney W. Grimes } 442df8bae1dSRodney W. Grimes 443df8bae1dSRodney W. Grimes /* 444df8bae1dSRodney W. Grimes * Remove vnode associated object from the object cache. 445df8bae1dSRodney W. Grimes * 446df8bae1dSRodney W. Grimes * XXX unlock the vnode if it is currently locked. 447df8bae1dSRodney W. Grimes * We must do this since uncaching the object may result in its 448df8bae1dSRodney W. Grimes * destruction which may initiate paging activity which may necessitate 449df8bae1dSRodney W. Grimes * re-locking the vnode. 450df8bae1dSRodney W. Grimes */ 451df8bae1dSRodney W. Grimes boolean_t 452df8bae1dSRodney W. Grimes vnode_pager_uncache(vp) 453df8bae1dSRodney W. Grimes register struct vnode *vp; 454df8bae1dSRodney W. Grimes { 455df8bae1dSRodney W. Grimes register vm_object_t object; 456df8bae1dSRodney W. Grimes boolean_t uncached; 457df8bae1dSRodney W. Grimes vm_pager_t pager; 458df8bae1dSRodney W. Grimes 459df8bae1dSRodney W. Grimes /* 460df8bae1dSRodney W. Grimes * Not a mapped vnode 461df8bae1dSRodney W. Grimes */ 462df8bae1dSRodney W. Grimes pager = (vm_pager_t)vp->v_vmdata; 463df8bae1dSRodney W. Grimes if (pager == NULL) 464df8bae1dSRodney W. Grimes return (TRUE); 465df8bae1dSRodney W. Grimes #ifdef DEBUG 466df8bae1dSRodney W. Grimes if (!VOP_ISLOCKED(vp)) { 467df8bae1dSRodney W. Grimes extern int (**nfsv2_vnodeop_p)(); 468df8bae1dSRodney W. Grimes 469df8bae1dSRodney W. Grimes if (vp->v_op != nfsv2_vnodeop_p) 470df8bae1dSRodney W. Grimes panic("vnode_pager_uncache: vnode not locked!"); 471df8bae1dSRodney W. Grimes } 472df8bae1dSRodney W. Grimes #endif 473df8bae1dSRodney W. Grimes /* 474df8bae1dSRodney W. Grimes * Must use vm_object_lookup() as it actually removes 475df8bae1dSRodney W. Grimes * the object from the cache list. 476df8bae1dSRodney W. Grimes */ 477df8bae1dSRodney W. Grimes object = vm_object_lookup(pager); 478df8bae1dSRodney W. Grimes if (object) { 479df8bae1dSRodney W. Grimes uncached = (object->ref_count <= 1); 480df8bae1dSRodney W. Grimes VOP_UNLOCK(vp); 481df8bae1dSRodney W. Grimes pager_cache(object, FALSE); 482df8bae1dSRodney W. Grimes VOP_LOCK(vp); 483df8bae1dSRodney W. Grimes } else 484df8bae1dSRodney W. Grimes uncached = TRUE; 485df8bae1dSRodney W. Grimes return(uncached); 486df8bae1dSRodney W. Grimes } 487df8bae1dSRodney W. Grimes 488df8bae1dSRodney W. Grimes static int 489df8bae1dSRodney W. Grimes vnode_pager_io(vnp, mlist, npages, sync, rw) 490df8bae1dSRodney W. Grimes register vn_pager_t vnp; 491df8bae1dSRodney W. Grimes vm_page_t *mlist; 492df8bae1dSRodney W. Grimes int npages; 493df8bae1dSRodney W. Grimes boolean_t sync; 494df8bae1dSRodney W. Grimes enum uio_rw rw; 495df8bae1dSRodney W. Grimes { 496df8bae1dSRodney W. Grimes struct uio auio; 497df8bae1dSRodney W. Grimes struct iovec aiov; 498df8bae1dSRodney W. Grimes vm_offset_t kva, foff; 499df8bae1dSRodney W. Grimes int error, size; 500df8bae1dSRodney W. Grimes struct proc *p = curproc; /* XXX */ 501df8bae1dSRodney W. Grimes 502df8bae1dSRodney W. Grimes /* XXX */ 503df8bae1dSRodney W. Grimes vm_page_t m; 504df8bae1dSRodney W. Grimes if (npages != 1) 505df8bae1dSRodney W. Grimes panic("vnode_pager_io: cannot handle multiple pages"); 506df8bae1dSRodney W. Grimes m = *mlist; 507df8bae1dSRodney W. Grimes /* XXX */ 508df8bae1dSRodney W. Grimes 509df8bae1dSRodney W. Grimes #ifdef DEBUG 510df8bae1dSRodney W. Grimes if (vpagerdebug & VDB_FOLLOW) 511df8bae1dSRodney W. Grimes printf("vnode_pager_io(%x, %x, %c): vnode %x\n", 512df8bae1dSRodney W. Grimes vnp, m, rw == UIO_READ ? 'R' : 'W', vnp->vnp_vp); 513df8bae1dSRodney W. Grimes #endif 514df8bae1dSRodney W. Grimes foff = m->offset + m->object->paging_offset; 515df8bae1dSRodney W. Grimes /* 516df8bae1dSRodney W. Grimes * Allocate a kernel virtual address and initialize so that 517df8bae1dSRodney W. Grimes * we can use VOP_READ/WRITE routines. 518df8bae1dSRodney W. Grimes */ 519df8bae1dSRodney W. Grimes kva = vm_pager_map_pages(mlist, npages, sync); 520df8bae1dSRodney W. Grimes if (kva == NULL) 521df8bae1dSRodney W. Grimes return(VM_PAGER_AGAIN); 522df8bae1dSRodney W. Grimes /* 523df8bae1dSRodney W. Grimes * After all of the potentially blocking operations have been 524df8bae1dSRodney W. Grimes * performed, we can do the size checks: 525df8bae1dSRodney W. Grimes * read beyond EOF (returns error) 526df8bae1dSRodney W. Grimes * short read 527df8bae1dSRodney W. Grimes */ 528df8bae1dSRodney W. Grimes VOP_LOCK(vnp->vnp_vp); 529df8bae1dSRodney W. Grimes if (foff >= vnp->vnp_size) { 530df8bae1dSRodney W. Grimes VOP_UNLOCK(vnp->vnp_vp); 531df8bae1dSRodney W. Grimes vm_pager_unmap_pages(kva, npages); 532df8bae1dSRodney W. Grimes #ifdef DEBUG 533df8bae1dSRodney W. Grimes if (vpagerdebug & VDB_SIZE) 534df8bae1dSRodney W. Grimes printf("vnode_pager_io: vp %x, off %d size %d\n", 535df8bae1dSRodney W. Grimes vnp->vnp_vp, foff, vnp->vnp_size); 536df8bae1dSRodney W. Grimes #endif 537df8bae1dSRodney W. Grimes return(VM_PAGER_BAD); 538df8bae1dSRodney W. Grimes } 539df8bae1dSRodney W. Grimes if (foff + PAGE_SIZE > vnp->vnp_size) 540df8bae1dSRodney W. Grimes size = vnp->vnp_size - foff; 541df8bae1dSRodney W. Grimes else 542df8bae1dSRodney W. Grimes size = PAGE_SIZE; 543df8bae1dSRodney W. Grimes aiov.iov_base = (caddr_t)kva; 544df8bae1dSRodney W. Grimes aiov.iov_len = size; 545df8bae1dSRodney W. Grimes auio.uio_iov = &aiov; 546df8bae1dSRodney W. Grimes auio.uio_iovcnt = 1; 547df8bae1dSRodney W. Grimes auio.uio_offset = foff; 548df8bae1dSRodney W. Grimes auio.uio_segflg = UIO_SYSSPACE; 549df8bae1dSRodney W. Grimes auio.uio_rw = rw; 550df8bae1dSRodney W. Grimes auio.uio_resid = size; 551df8bae1dSRodney W. Grimes auio.uio_procp = (struct proc *)0; 552df8bae1dSRodney W. Grimes #ifdef DEBUG 553df8bae1dSRodney W. Grimes if (vpagerdebug & VDB_IO) 554df8bae1dSRodney W. Grimes printf("vnode_pager_io: vp %x kva %x foff %x size %x", 555df8bae1dSRodney W. Grimes vnp->vnp_vp, kva, foff, size); 556df8bae1dSRodney W. Grimes #endif 557df8bae1dSRodney W. Grimes if (rw == UIO_READ) 558df8bae1dSRodney W. Grimes error = VOP_READ(vnp->vnp_vp, &auio, 0, p->p_ucred); 559df8bae1dSRodney W. Grimes else 560df8bae1dSRodney W. Grimes error = VOP_WRITE(vnp->vnp_vp, &auio, 0, p->p_ucred); 561df8bae1dSRodney W. Grimes VOP_UNLOCK(vnp->vnp_vp); 562df8bae1dSRodney W. Grimes #ifdef DEBUG 563df8bae1dSRodney W. Grimes if (vpagerdebug & VDB_IO) { 564df8bae1dSRodney W. Grimes if (error || auio.uio_resid) 565df8bae1dSRodney W. Grimes printf(" returns error %x, resid %x", 566df8bae1dSRodney W. Grimes error, auio.uio_resid); 567df8bae1dSRodney W. Grimes printf("\n"); 568df8bae1dSRodney W. Grimes } 569df8bae1dSRodney W. Grimes #endif 570df8bae1dSRodney W. Grimes if (!error) { 571df8bae1dSRodney W. Grimes register int count = size - auio.uio_resid; 572df8bae1dSRodney W. Grimes 573df8bae1dSRodney W. Grimes if (count == 0) 574df8bae1dSRodney W. Grimes error = EINVAL; 575df8bae1dSRodney W. Grimes else if (count != PAGE_SIZE && rw == UIO_READ) 576df8bae1dSRodney W. Grimes bzero((void *)(kva + count), PAGE_SIZE - count); 577df8bae1dSRodney W. Grimes } 578df8bae1dSRodney W. Grimes vm_pager_unmap_pages(kva, npages); 579df8bae1dSRodney W. Grimes return (error ? VM_PAGER_ERROR : VM_PAGER_OK); 580df8bae1dSRodney W. Grimes } 581