1 /* 2 * Copyright (c) 1991 Regents of the University of California. 3 * 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 * %sccs.include.redist.c% 9 * 10 * @(#)vm_pager.c 7.6 (Berkeley) 08/28/91 11 * 12 * 13 * Copyright (c) 1987, 1990 Carnegie-Mellon University. 14 * All rights reserved. 15 * 16 * Authors: Avadis Tevanian, Jr., Michael Wayne Young 17 * 18 * Permission to use, copy, modify and distribute this software and 19 * its documentation is hereby granted, provided that both the copyright 20 * notice and this permission notice appear in all copies of the 21 * software, derivative works or modified versions, and any portions 22 * thereof, and that both notices appear in supporting documentation. 23 * 24 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 25 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 26 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 27 * 28 * Carnegie Mellon requests users of this software to return to 29 * 30 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 31 * School of Computer Science 32 * Carnegie Mellon University 33 * Pittsburgh PA 15213-3890 34 * 35 * any improvements or extensions that they make and grant Carnegie the 36 * rights to redistribute these changes. 37 */ 38 39 /* 40 * Paging space routine stubs. Emulates a matchmaker-like interface 41 * for builtin pagers. 42 */ 43 44 #include "param.h" 45 #include "malloc.h" 46 47 #include "vm.h" 48 #include "vm_page.h" 49 #include "vm_kern.h" 50 51 #include "swappager.h" 52 #if NSWAPPAGER > 0 53 extern struct pagerops swappagerops; 54 #define swappagerops_p &swappagerops 55 #else 56 #define swappagerops_p NULL 57 #endif 58 59 #include "vnodepager.h" 60 #if NVNODEPAGER > 0 61 extern struct pagerops vnodepagerops; 62 #define vnodepagerops_p &vnodepagerops 63 #else 64 #define vnodepagerops_p NULL 65 #endif 66 67 #include "devpager.h" 68 #if NDEVPAGER > 0 69 extern struct pagerops devicepagerops; 70 #define devicepagerops_p &devicepagerops 71 #else 72 #define devicepagerops_p NULL 73 #endif 74 75 struct pagerops *pagertab[] = { 76 swappagerops_p, /* PG_SWAP */ 77 vnodepagerops_p, /* PG_VNODE */ 78 devicepagerops_p, /* PG_DEV */ 79 }; 80 int npagers = sizeof (pagertab) / sizeof (pagertab[0]); 81 82 struct pagerops *dfltpagerops = NULL; /* default pager */ 83 84 /* 85 * Kernel address space for mapping pages. 86 * Used by pagers where KVAs are needed for IO. 87 */ 88 #define PAGER_MAP_SIZE (256 * PAGE_SIZE) 89 vm_map_t pager_map; 90 vm_offset_t pager_sva, pager_eva; 91 92 void 93 vm_pager_init() 94 { 95 struct pagerops **pgops; 96 97 /* 98 * Allocate a kernel submap for tracking get/put page mappings 99 */ 100 pager_map = kmem_suballoc(kernel_map, &pager_sva, &pager_eva, 101 PAGER_MAP_SIZE, FALSE); 102 /* 103 * Initialize known pagers 104 */ 105 for (pgops = pagertab; pgops < &pagertab[npagers]; pgops++) 106 (*(*pgops)->pgo_init)(); 107 if (dfltpagerops == NULL) 108 panic("no default pager"); 109 } 110 111 /* 112 * Allocate an instance of a pager of the given type. 113 */ 114 vm_pager_t 115 vm_pager_allocate(type, handle, size, prot) 116 int type; 117 caddr_t handle; 118 vm_size_t size; 119 vm_prot_t prot; 120 { 121 vm_pager_t pager; 122 struct pagerops *ops; 123 124 ops = (type == PG_DFLT) ? dfltpagerops : pagertab[type]; 125 return((*ops->pgo_alloc)(handle, size, prot)); 126 } 127 128 void 129 vm_pager_deallocate(pager) 130 vm_pager_t pager; 131 { 132 if (pager == NULL) 133 panic("vm_pager_deallocate: null pager"); 134 135 VM_PAGER_DEALLOC(pager); 136 } 137 138 vm_pager_get(pager, m, sync) 139 vm_pager_t pager; 140 vm_page_t m; 141 boolean_t sync; 142 { 143 extern boolean_t vm_page_zero_fill(); 144 145 if (pager == NULL) 146 return(vm_page_zero_fill(m) ? VM_PAGER_OK : VM_PAGER_FAIL); 147 return(VM_PAGER_GET(pager, m, sync)); 148 } 149 150 vm_pager_put(pager, m, sync) 151 vm_pager_t pager; 152 vm_page_t m; 153 boolean_t sync; 154 { 155 if (pager == NULL) 156 panic("vm_pager_put: null pager"); 157 return(VM_PAGER_PUT(pager, m, sync)); 158 } 159 160 boolean_t 161 vm_pager_has_page(pager, offset) 162 vm_pager_t pager; 163 vm_offset_t offset; 164 { 165 if (pager == NULL) 166 panic("vm_pager_has_page"); 167 return(VM_PAGER_HASPAGE(pager, offset)); 168 } 169 170 /* 171 * Called by pageout daemon before going back to sleep. 172 * Gives pagers a chance to clean up any completed async pageing operations. 173 */ 174 void 175 vm_pager_sync() 176 { 177 struct pagerops **pgops; 178 179 for (pgops = pagertab; pgops < &pagertab[npagers]; pgops++) 180 (*(*pgops)->pgo_putpage)(NULL, NULL, FALSE); 181 } 182 183 vm_offset_t 184 vm_pager_map_page(m) 185 vm_page_t m; 186 { 187 vm_offset_t kva; 188 189 #ifdef DEBUG 190 if (!m->busy || m->active) 191 panic("vm_pager_map_page: page active or not busy"); 192 if (m->pagerowned) 193 printf("vm_pager_map_page: page %x already in pager\n", m); 194 #endif 195 kva = kmem_alloc_wait(pager_map, PAGE_SIZE); 196 #ifdef DEBUG 197 m->pagerowned = 1; 198 #endif 199 pmap_enter(vm_map_pmap(pager_map), kva, VM_PAGE_TO_PHYS(m), 200 VM_PROT_DEFAULT, TRUE); 201 return(kva); 202 } 203 204 void 205 vm_pager_unmap_page(kva) 206 vm_offset_t kva; 207 { 208 #ifdef DEBUG 209 vm_page_t m; 210 211 m = PHYS_TO_VM_PAGE(pmap_extract(vm_map_pmap(pager_map), kva)); 212 #endif 213 pmap_remove(vm_map_pmap(pager_map), kva, kva + PAGE_SIZE); 214 kmem_free_wakeup(pager_map, kva, PAGE_SIZE); 215 #ifdef DEBUG 216 if (m->pagerowned) 217 m->pagerowned = 0; 218 else 219 printf("vm_pager_unmap_page: page %x(%x/%x) not owned\n", 220 m, kva, VM_PAGE_TO_PHYS(m)); 221 #endif 222 } 223 224 vm_pager_t 225 vm_pager_lookup(list, handle) 226 register queue_head_t *list; 227 caddr_t handle; 228 { 229 register vm_pager_t pager; 230 231 pager = (vm_pager_t) queue_first(list); 232 while (!queue_end(list, (queue_entry_t)pager)) { 233 if (pager->pg_handle == handle) 234 return(pager); 235 pager = (vm_pager_t) queue_next(&pager->pg_list); 236 } 237 return(NULL); 238 } 239 240 /* 241 * This routine gains a reference to the object. 242 * Explicit deallocation is necessary. 243 */ 244 pager_cache(object, should_cache) 245 vm_object_t object; 246 boolean_t should_cache; 247 { 248 if (object == NULL) 249 return(KERN_INVALID_ARGUMENT); 250 251 vm_object_cache_lock(); 252 vm_object_lock(object); 253 if (should_cache) 254 object->flags |= OBJ_CANPERSIST; 255 else 256 object->flags &= ~OBJ_CANPERSIST; 257 vm_object_unlock(object); 258 vm_object_cache_unlock(); 259 260 vm_object_deallocate(object); 261 262 return(KERN_SUCCESS); 263 } 264