145748Smckusick /* 263379Sbostic * Copyright (c) 1991, 1993 363379Sbostic * The Regents of the University of California. All rights reserved. 445748Smckusick * 545748Smckusick * This code is derived from software contributed to Berkeley by 645748Smckusick * The Mach Operating System project at Carnegie-Mellon University. 745748Smckusick * 848493Smckusick * %sccs.include.redist.c% 945748Smckusick * 10*65692Shibler * @(#)vm_pager.c 8.6 (Berkeley) 01/12/94 1148493Smckusick * 1248493Smckusick * 1348493Smckusick * Copyright (c) 1987, 1990 Carnegie-Mellon University. 1448493Smckusick * All rights reserved. 1548493Smckusick * 1648493Smckusick * Authors: Avadis Tevanian, Jr., Michael Wayne Young 1748493Smckusick * 1848493Smckusick * Permission to use, copy, modify and distribute this software and 1948493Smckusick * its documentation is hereby granted, provided that both the copyright 2048493Smckusick * notice and this permission notice appear in all copies of the 2148493Smckusick * software, derivative works or modified versions, and any portions 2248493Smckusick * thereof, and that both notices appear in supporting documentation. 2348493Smckusick * 2448493Smckusick * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 2548493Smckusick * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 2648493Smckusick * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 2748493Smckusick * 2848493Smckusick * Carnegie Mellon requests users of this software to return to 2948493Smckusick * 3048493Smckusick * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 3148493Smckusick * School of Computer Science 3248493Smckusick * Carnegie Mellon University 3348493Smckusick * Pittsburgh PA 15213-3890 3448493Smckusick * 3548493Smckusick * any improvements or extensions that they make and grant Carnegie the 3648493Smckusick * rights to redistribute these changes. 3745748Smckusick */ 3845748Smckusick 3945748Smckusick /* 4045748Smckusick * Paging space routine stubs. Emulates a matchmaker-like interface 4145748Smckusick * for builtin pagers. 4245748Smckusick */ 4345748Smckusick 4453360Sbostic #include <sys/param.h> 4553360Sbostic #include <sys/systm.h> 4653360Sbostic #include <sys/malloc.h> 4745748Smckusick 4853360Sbostic #include <vm/vm.h> 4953360Sbostic #include <vm/vm_page.h> 5053360Sbostic #include <vm/vm_kern.h> 5145748Smckusick 5259121Storek #ifdef SWAPPAGER 5345748Smckusick extern struct pagerops swappagerops; 5445748Smckusick #endif 5550421Smckusick 5659121Storek #ifdef VNODEPAGER 5745748Smckusick extern struct pagerops vnodepagerops; 5845748Smckusick #endif 5950421Smckusick 6059121Storek #ifdef DEVPAGER 6145748Smckusick extern struct pagerops devicepagerops; 6245748Smckusick #endif 6345748Smckusick 6445748Smckusick struct pagerops *pagertab[] = { 6559121Storek #ifdef SWAPPAGER 6659121Storek &swappagerops, /* PG_SWAP */ 6764859Shibler #else 6864859Shibler NULL, 6952774Smckusick #endif 7059121Storek #ifdef VNODEPAGER 7159121Storek &vnodepagerops, /* PG_VNODE */ 7264859Shibler #else 7364859Shibler NULL, 7452774Smckusick #endif 7559121Storek #ifdef DEVPAGER 7659121Storek &devicepagerops, /* PG_DEV */ 7764859Shibler #else 7864859Shibler NULL, 7952774Smckusick #endif 8045748Smckusick }; 8145748Smckusick int npagers = sizeof (pagertab) / sizeof (pagertab[0]); 8245748Smckusick 8348386Skarels struct pagerops *dfltpagerops = NULL; /* default pager */ 8445748Smckusick 8545748Smckusick /* 8645748Smckusick * Kernel address space for mapping pages. 8745748Smckusick * Used by pagers where KVAs are needed for IO. 88*65692Shibler * 89*65692Shibler * XXX needs to be large enough to support the number of pending async 90*65692Shibler * cleaning requests (NPENDINGIO == 64) * the maximum swap cluster size 91*65692Shibler * (MAXPHYS == 64k) if you want to get the most efficiency. 9245748Smckusick */ 93*65692Shibler #define PAGER_MAP_SIZE (4 * 1024 * 1024) 94*65692Shibler 9545748Smckusick vm_map_t pager_map; 96*65692Shibler boolean_t pager_map_wanted; 9749294Shibler vm_offset_t pager_sva, pager_eva; 9845748Smckusick 9945748Smckusick void 10045748Smckusick vm_pager_init() 10145748Smckusick { 10245748Smckusick struct pagerops **pgops; 10345748Smckusick 10445748Smckusick /* 10545748Smckusick * Allocate a kernel submap for tracking get/put page mappings 10645748Smckusick */ 10749294Shibler pager_map = kmem_suballoc(kernel_map, &pager_sva, &pager_eva, 10845748Smckusick PAGER_MAP_SIZE, FALSE); 10945748Smckusick /* 11045748Smckusick * Initialize known pagers 11145748Smckusick */ 11245748Smckusick for (pgops = pagertab; pgops < &pagertab[npagers]; pgops++) 11364859Shibler if (pgops) 11464859Shibler (*(*pgops)->pgo_init)(); 11548386Skarels if (dfltpagerops == NULL) 11645748Smckusick panic("no default pager"); 11745748Smckusick } 11845748Smckusick 11945748Smckusick /* 12045748Smckusick * Allocate an instance of a pager of the given type. 12164859Shibler * Size, protection and offset parameters are passed in for pagers that 12264859Shibler * need to perform page-level validation (e.g. the device pager). 12345748Smckusick */ 12445748Smckusick vm_pager_t 12564827Storek vm_pager_allocate(type, handle, size, prot, off) 12645748Smckusick int type; 12745748Smckusick caddr_t handle; 12845748Smckusick vm_size_t size; 12945748Smckusick vm_prot_t prot; 13064827Storek vm_offset_t off; 13145748Smckusick { 13245748Smckusick struct pagerops *ops; 13345748Smckusick 13445748Smckusick ops = (type == PG_DFLT) ? dfltpagerops : pagertab[type]; 13564859Shibler if (ops) 13664859Shibler return ((*ops->pgo_alloc)(handle, size, prot, off)); 13764859Shibler return (NULL); 13845748Smckusick } 13945748Smckusick 14045748Smckusick void 14145748Smckusick vm_pager_deallocate(pager) 14245748Smckusick vm_pager_t pager; 14345748Smckusick { 14448386Skarels if (pager == NULL) 14545748Smckusick panic("vm_pager_deallocate: null pager"); 14645748Smckusick 147*65692Shibler (*pager->pg_ops->pgo_dealloc)(pager); 14845748Smckusick } 14945748Smckusick 15053360Sbostic int 151*65692Shibler vm_pager_get_pages(pager, mlist, npages, sync) 15245748Smckusick vm_pager_t pager; 153*65692Shibler vm_page_t *mlist; 154*65692Shibler int npages; 15545748Smckusick boolean_t sync; 15645748Smckusick { 157*65692Shibler int rv; 15845748Smckusick 159*65692Shibler if (pager == NULL) { 160*65692Shibler rv = VM_PAGER_OK; 161*65692Shibler while (npages--) 162*65692Shibler if (!vm_page_zero_fill(*mlist)) { 163*65692Shibler rv = VM_PAGER_FAIL; 164*65692Shibler break; 165*65692Shibler } else 166*65692Shibler mlist++; 167*65692Shibler return (rv); 168*65692Shibler } 169*65692Shibler return ((*pager->pg_ops->pgo_getpages)(pager, mlist, npages, sync)); 17045748Smckusick } 17145748Smckusick 17253360Sbostic int 173*65692Shibler vm_pager_put_pages(pager, mlist, npages, sync) 17445748Smckusick vm_pager_t pager; 175*65692Shibler vm_page_t *mlist; 176*65692Shibler int npages; 17745748Smckusick boolean_t sync; 17845748Smckusick { 17948386Skarels if (pager == NULL) 180*65692Shibler panic("vm_pager_put_pages: null pager"); 181*65692Shibler return ((*pager->pg_ops->pgo_putpages)(pager, mlist, npages, sync)); 18245748Smckusick } 18345748Smckusick 18445748Smckusick boolean_t 18545748Smckusick vm_pager_has_page(pager, offset) 18645748Smckusick vm_pager_t pager; 18745748Smckusick vm_offset_t offset; 18845748Smckusick { 18948386Skarels if (pager == NULL) 190*65692Shibler panic("vm_pager_has_page: null pager"); 191*65692Shibler return ((*pager->pg_ops->pgo_haspage)(pager, offset)); 19245748Smckusick } 19345748Smckusick 19445748Smckusick /* 19545748Smckusick * Called by pageout daemon before going back to sleep. 19645748Smckusick * Gives pagers a chance to clean up any completed async pageing operations. 19745748Smckusick */ 19845748Smckusick void 19945748Smckusick vm_pager_sync() 20045748Smckusick { 20145748Smckusick struct pagerops **pgops; 20245748Smckusick 20345748Smckusick for (pgops = pagertab; pgops < &pagertab[npagers]; pgops++) 20464859Shibler if (pgops) 205*65692Shibler (*(*pgops)->pgo_putpages)(NULL, NULL, 0, FALSE); 20645748Smckusick } 20745748Smckusick 208*65692Shibler void 209*65692Shibler vm_pager_cluster(pager, offset, loff, hoff) 210*65692Shibler vm_pager_t pager; 211*65692Shibler vm_offset_t offset; 212*65692Shibler vm_offset_t *loff; 213*65692Shibler vm_offset_t *hoff; 214*65692Shibler { 215*65692Shibler if (pager == NULL) 216*65692Shibler panic("vm_pager_cluster: null pager"); 217*65692Shibler return ((*pager->pg_ops->pgo_cluster)(pager, offset, loff, hoff)); 218*65692Shibler } 219*65692Shibler 220*65692Shibler void 221*65692Shibler vm_pager_clusternull(pager, offset, loff, hoff) 222*65692Shibler vm_pager_t pager; 223*65692Shibler vm_offset_t offset; 224*65692Shibler vm_offset_t *loff; 225*65692Shibler vm_offset_t *hoff; 226*65692Shibler { 227*65692Shibler panic("vm_pager_nullcluster called"); 228*65692Shibler } 229*65692Shibler 23045748Smckusick vm_offset_t 231*65692Shibler vm_pager_map_pages(mlist, npages, canwait) 232*65692Shibler vm_page_t *mlist; 233*65692Shibler int npages; 234*65692Shibler boolean_t canwait; 23545748Smckusick { 236*65692Shibler vm_offset_t kva, va; 237*65692Shibler vm_size_t size; 238*65692Shibler vm_page_t m; 23945748Smckusick 240*65692Shibler /* 241*65692Shibler * Allocate space in the pager map, if none available return 0. 242*65692Shibler * This is basically an expansion of kmem_alloc_wait with optional 243*65692Shibler * blocking on no space. 244*65692Shibler */ 245*65692Shibler size = npages * PAGE_SIZE; 246*65692Shibler vm_map_lock(pager_map); 247*65692Shibler while (vm_map_findspace(pager_map, 0, size, &kva)) { 248*65692Shibler if (!canwait) { 249*65692Shibler vm_map_unlock(pager_map); 250*65692Shibler return (0); 251*65692Shibler } 252*65692Shibler pager_map_wanted = TRUE; 253*65692Shibler vm_map_unlock(pager_map); 254*65692Shibler (void) tsleep(pager_map, PVM, "pager_map", 0); 255*65692Shibler vm_map_lock(pager_map); 256*65692Shibler } 257*65692Shibler vm_map_insert(pager_map, NULL, 0, kva, kva + size); 258*65692Shibler vm_map_unlock(pager_map); 259*65692Shibler 260*65692Shibler for (va = kva; npages--; va += PAGE_SIZE) { 261*65692Shibler m = *mlist++; 26249294Shibler #ifdef DEBUG 263*65692Shibler if ((m->flags & PG_BUSY) == 0) 264*65692Shibler panic("vm_pager_map_pages: page not busy"); 265*65692Shibler if (m->flags & PG_PAGEROWNED) 266*65692Shibler panic("vm_pager_map_pages: page already in pager"); 26749294Shibler #endif 26849294Shibler #ifdef DEBUG 269*65692Shibler m->flags |= PG_PAGEROWNED; 27049294Shibler #endif 271*65692Shibler pmap_enter(vm_map_pmap(pager_map), va, VM_PAGE_TO_PHYS(m), 272*65692Shibler VM_PROT_DEFAULT, TRUE); 273*65692Shibler } 274*65692Shibler return (kva); 27545748Smckusick } 27645748Smckusick 27745748Smckusick void 278*65692Shibler vm_pager_unmap_pages(kva, npages) 27945748Smckusick vm_offset_t kva; 280*65692Shibler int npages; 28145748Smckusick { 282*65692Shibler vm_size_t size = npages * PAGE_SIZE; 283*65692Shibler 28449294Shibler #ifdef DEBUG 285*65692Shibler vm_offset_t va; 28649294Shibler vm_page_t m; 287*65692Shibler int np = npages; 28849294Shibler 289*65692Shibler for (va = kva; np--; va += PAGE_SIZE) { 290*65692Shibler m = vm_pager_atop(va); 291*65692Shibler if (m->flags & PG_PAGEROWNED) 292*65692Shibler m->flags &= ~PG_PAGEROWNED; 293*65692Shibler else 294*65692Shibler printf("vm_pager_unmap_pages: %x(%x/%x) not owned\n", 295*65692Shibler m, va, VM_PAGE_TO_PHYS(m)); 296*65692Shibler } 29745748Smckusick #endif 298*65692Shibler pmap_remove(vm_map_pmap(pager_map), kva, kva + size); 299*65692Shibler vm_map_lock(pager_map); 300*65692Shibler (void) vm_map_delete(pager_map, kva, kva + size); 301*65692Shibler if (pager_map_wanted) 302*65692Shibler wakeup(pager_map); 303*65692Shibler vm_map_unlock(pager_map); 30445748Smckusick } 30545748Smckusick 306*65692Shibler vm_page_t 307*65692Shibler vm_pager_atop(kva) 308*65692Shibler vm_offset_t kva; 309*65692Shibler { 310*65692Shibler vm_offset_t pa; 311*65692Shibler 312*65692Shibler pa = pmap_extract(vm_map_pmap(pager_map), kva); 313*65692Shibler if (pa == 0) 314*65692Shibler panic("vm_pager_atop"); 315*65692Shibler return (PHYS_TO_VM_PAGE(pa)); 316*65692Shibler } 317*65692Shibler 31845748Smckusick vm_pager_t 31965231Smckusick vm_pager_lookup(pglist, handle) 32065231Smckusick register struct pagerlst *pglist; 32145748Smckusick caddr_t handle; 32245748Smckusick { 32345748Smckusick register vm_pager_t pager; 32445748Smckusick 32565231Smckusick for (pager = pglist->tqh_first; pager; pager = pager->pg_list.tqe_next) 32645748Smckusick if (pager->pg_handle == handle) 327*65692Shibler return (pager); 328*65692Shibler return (NULL); 32945748Smckusick } 33045748Smckusick 33145748Smckusick /* 33245748Smckusick * This routine gains a reference to the object. 33345748Smckusick * Explicit deallocation is necessary. 33445748Smckusick */ 33553360Sbostic int 33645748Smckusick pager_cache(object, should_cache) 33745748Smckusick vm_object_t object; 33845748Smckusick boolean_t should_cache; 33945748Smckusick { 34048386Skarels if (object == NULL) 341*65692Shibler return (KERN_INVALID_ARGUMENT); 34245748Smckusick 34345748Smckusick vm_object_cache_lock(); 34445748Smckusick vm_object_lock(object); 34550920Smckusick if (should_cache) 34650920Smckusick object->flags |= OBJ_CANPERSIST; 34750920Smckusick else 34850920Smckusick object->flags &= ~OBJ_CANPERSIST; 34945748Smckusick vm_object_unlock(object); 35045748Smckusick vm_object_cache_unlock(); 35145748Smckusick 35245748Smckusick vm_object_deallocate(object); 35345748Smckusick 354*65692Shibler return (KERN_SUCCESS); 35545748Smckusick } 356