vm_pager.c revision 1817
1/* 2 * Copyright (c) 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * The Mach Operating System project at Carnegie-Mellon University. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * from: @(#)vm_pager.c 8.6 (Berkeley) 1/12/94 37 * 38 * 39 * Copyright (c) 1987, 1990 Carnegie-Mellon University. 40 * All rights reserved. 41 * 42 * Authors: Avadis Tevanian, Jr., Michael Wayne Young 43 * 44 * Permission to use, copy, modify and distribute this software and 45 * its documentation is hereby granted, provided that both the copyright 46 * notice and this permission notice appear in all copies of the 47 * software, derivative works or modified versions, and any portions 48 * thereof, and that both notices appear in supporting documentation. 49 * 50 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 51 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 52 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 53 * 54 * Carnegie Mellon requests users of this software to return to 55 * 56 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 57 * School of Computer Science 58 * Carnegie Mellon University 59 * Pittsburgh PA 15213-3890 60 * 61 * any improvements or extensions that they make and grant Carnegie the 62 * rights to redistribute these changes. 63 * 64 * $Id$ 65 */ 66 67/* 68 * Paging space routine stubs. Emulates a matchmaker-like interface 69 * for builtin pagers. 70 */ 71 72#include <sys/param.h> 73#include <sys/systm.h> 74#include <sys/malloc.h> 75 76#include <vm/vm.h> 77#include <vm/vm_page.h> 78#include <vm/vm_kern.h> 79 80extern struct pagerops swappagerops; 81extern struct pagerops vnodepagerops; 82extern struct pagerops devicepagerops; 83 84struct pagerops *pagertab[] = { 85 &swappagerops, /* PG_SWAP */ 86 &vnodepagerops, /* PG_VNODE */ 87 &devicepagerops, /* PG_DEV */ 88}; 89int npagers = sizeof (pagertab) / sizeof (pagertab[0]); 90 91struct pagerops *dfltpagerops = NULL; /* default pager */ 92 93/* 94 * Kernel address space for mapping pages. 95 * Used by pagers where KVAs are needed for IO. 96 * 97 * XXX needs to be large enough to support the number of pending async 98 * cleaning requests (NPENDINGIO == 64) * the maximum swap cluster size 99 * (MAXPHYS == 64k) if you want to get the most efficiency. 100 */ 101#define PAGER_MAP_SIZE (4 * 1024 * 1024) 102 103int pager_map_size = PAGER_MAP_SIZE; 104vm_map_t pager_map; 105boolean_t pager_map_wanted; 106vm_offset_t pager_sva, pager_eva; 107 108void 109vm_pager_init() 110{ 111 struct pagerops **pgops; 112 113 /* 114 * Allocate a kernel submap for tracking get/put page mappings 115 */ 116/* 117 pager_map = kmem_suballoc(kernel_map, &pager_sva, &pager_eva, 118 PAGER_MAP_SIZE, FALSE); 119*/ 120 /* 121 * Initialize known pagers 122 */ 123 for (pgops = pagertab; pgops < &pagertab[npagers]; pgops++) 124 if (pgops) 125 (*(*pgops)->pgo_init)(); 126 if (dfltpagerops == NULL) 127 panic("no default pager"); 128} 129 130/* 131 * Allocate an instance of a pager of the given type. 132 * Size, protection and offset parameters are passed in for pagers that 133 * need to perform page-level validation (e.g. the device pager). 134 */ 135vm_pager_t 136vm_pager_allocate(type, handle, size, prot, off) 137 int type; 138 caddr_t handle; 139 vm_size_t size; 140 vm_prot_t prot; 141 vm_offset_t off; 142{ 143 struct pagerops *ops; 144 145 ops = (type == PG_DFLT) ? dfltpagerops : pagertab[type]; 146 if (ops) 147 return ((*ops->pgo_alloc)(handle, size, prot, off)); 148 return (NULL); 149} 150 151void 152vm_pager_deallocate(pager) 153 vm_pager_t pager; 154{ 155 if (pager == NULL) 156 panic("vm_pager_deallocate: null pager"); 157 158 (*pager->pg_ops->pgo_dealloc)(pager); 159} 160 161 162int 163vm_pager_get_pages(pager, m, count, reqpage, sync) 164 vm_pager_t pager; 165 vm_page_t *m; 166 int count; 167 int reqpage; 168 boolean_t sync; 169{ 170 extern boolean_t vm_page_zero_fill(); 171 extern int vm_pageout_count; 172 int i; 173 174 if (pager == NULL) { 175 for (i=0;i<count;i++) { 176 if( i != reqpage) { 177 PAGE_WAKEUP(m[i]); 178 vm_page_free(m[i]); 179 } 180 } 181 vm_page_zero_fill(m[reqpage]); 182 return VM_PAGER_OK; 183 } 184 185 if( pager->pg_ops->pgo_getpages == 0) { 186 for(i=0;i<count;i++) { 187 if( i != reqpage) { 188 PAGE_WAKEUP(m[i]); 189 vm_page_free(m[i]); 190 } 191 } 192 return(VM_PAGER_GET(pager, m[reqpage], sync)); 193 } else { 194 return(VM_PAGER_GET_MULTI(pager, m, count, reqpage, sync)); 195 } 196} 197 198int 199vm_pager_put_pages(pager, m, count, sync, rtvals) 200 vm_pager_t pager; 201 vm_page_t *m; 202 int count; 203 boolean_t sync; 204 int *rtvals; 205{ 206 int i; 207 208 if( pager->pg_ops->pgo_putpages) 209 return(VM_PAGER_PUT_MULTI(pager, m, count, sync, rtvals)); 210 else { 211 for(i=0;i<count;i++) { 212 rtvals[i] = VM_PAGER_PUT( pager, m[i], sync); 213 } 214 return rtvals[0]; 215 } 216} 217 218boolean_t 219vm_pager_has_page(pager, offset) 220 vm_pager_t pager; 221 vm_offset_t offset; 222{ 223 if (pager == NULL) 224 panic("vm_pager_has_page: null pager"); 225 return ((*pager->pg_ops->pgo_haspage)(pager, offset)); 226} 227 228/* 229 * Called by pageout daemon before going back to sleep. 230 * Gives pagers a chance to clean up any completed async pageing operations. 231 */ 232void 233vm_pager_sync() 234{ 235 struct pagerops **pgops; 236 237 for (pgops = pagertab; pgops < &pagertab[npagers]; pgops++) 238 if (pgops) 239 (*(*pgops)->pgo_putpage)(NULL, NULL, 0); 240} 241 242#if 0 243void 244vm_pager_cluster(pager, offset, loff, hoff) 245 vm_pager_t pager; 246 vm_offset_t offset; 247 vm_offset_t *loff; 248 vm_offset_t *hoff; 249{ 250 if (pager == NULL) 251 panic("vm_pager_cluster: null pager"); 252 return ((*pager->pg_ops->pgo_cluster)(pager, offset, loff, hoff)); 253} 254#endif 255 256vm_offset_t 257vm_pager_map_page(m) 258 vm_page_t m; 259{ 260 vm_offset_t kva; 261 262 kva = kmem_alloc_wait(pager_map, PAGE_SIZE); 263 pmap_enter(vm_map_pmap(pager_map), kva, VM_PAGE_TO_PHYS(m), 264 VM_PROT_DEFAULT, TRUE); 265 return(kva); 266} 267 268void 269vm_pager_unmap_page(kva) 270 vm_offset_t kva; 271{ 272 kmem_free_wakeup(pager_map, kva, PAGE_SIZE); 273} 274 275vm_page_t 276vm_pager_atop(kva) 277 vm_offset_t kva; 278{ 279 vm_offset_t pa; 280 281 pa = pmap_extract(vm_map_pmap(pager_map), kva); 282 if (pa == 0) 283 panic("vm_pager_atop"); 284 return (PHYS_TO_VM_PAGE(pa)); 285} 286 287vm_pager_t 288vm_pager_lookup(pglist, handle) 289 register struct pagerlst *pglist; 290 caddr_t handle; 291{ 292 register vm_pager_t pager; 293 294 for (pager = pglist->tqh_first; pager; pager = pager->pg_list.tqe_next) 295 if (pager->pg_handle == handle) 296 return (pager); 297 return (NULL); 298} 299 300/* 301 * This routine gains a reference to the object. 302 * Explicit deallocation is necessary. 303 */ 304int 305pager_cache(object, should_cache) 306 vm_object_t object; 307 boolean_t should_cache; 308{ 309 if (object == NULL) 310 return (KERN_INVALID_ARGUMENT); 311 312 vm_object_cache_lock(); 313 vm_object_lock(object); 314 if (should_cache) 315 object->flags |= OBJ_CANPERSIST; 316 else 317 object->flags &= ~OBJ_CANPERSIST; 318 vm_object_unlock(object); 319 vm_object_cache_unlock(); 320 321 vm_object_deallocate(object); 322 323 return (KERN_SUCCESS); 324} 325