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*67496Shibler * @(#)vm_pager.c 8.7 (Berkeley) 07/07/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.
8865692Shibler *
8965692Shibler * XXX needs to be large enough to support the number of pending async
9065692Shibler * cleaning requests (NPENDINGIO == 64) * the maximum swap cluster size
9165692Shibler * (MAXPHYS == 64k) if you want to get the most efficiency.
9245748Smckusick */
9365692Shibler #define PAGER_MAP_SIZE (4 * 1024 * 1024)
9465692Shibler
9545748Smckusick vm_map_t pager_map;
9665692Shibler boolean_t pager_map_wanted;
9749294Shibler vm_offset_t pager_sva, pager_eva;
9845748Smckusick
9945748Smckusick void
vm_pager_init()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
vm_pager_allocate(type,handle,size,prot,off)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
vm_pager_deallocate(pager)14145748Smckusick vm_pager_deallocate(pager)
14245748Smckusick vm_pager_t pager;
14345748Smckusick {
14448386Skarels if (pager == NULL)
14545748Smckusick panic("vm_pager_deallocate: null pager");
14645748Smckusick
14765692Shibler (*pager->pg_ops->pgo_dealloc)(pager);
14845748Smckusick }
14945748Smckusick
15053360Sbostic int
vm_pager_get_pages(pager,mlist,npages,sync)15165692Shibler vm_pager_get_pages(pager, mlist, npages, sync)
15245748Smckusick vm_pager_t pager;
15365692Shibler vm_page_t *mlist;
15465692Shibler int npages;
15545748Smckusick boolean_t sync;
15645748Smckusick {
15765692Shibler int rv;
15845748Smckusick
15965692Shibler if (pager == NULL) {
16065692Shibler rv = VM_PAGER_OK;
16165692Shibler while (npages--)
16265692Shibler if (!vm_page_zero_fill(*mlist)) {
16365692Shibler rv = VM_PAGER_FAIL;
16465692Shibler break;
16565692Shibler } else
16665692Shibler mlist++;
16765692Shibler return (rv);
16865692Shibler }
16965692Shibler return ((*pager->pg_ops->pgo_getpages)(pager, mlist, npages, sync));
17045748Smckusick }
17145748Smckusick
17253360Sbostic int
vm_pager_put_pages(pager,mlist,npages,sync)17365692Shibler vm_pager_put_pages(pager, mlist, npages, sync)
17445748Smckusick vm_pager_t pager;
17565692Shibler vm_page_t *mlist;
17665692Shibler int npages;
17745748Smckusick boolean_t sync;
17845748Smckusick {
17948386Skarels if (pager == NULL)
18065692Shibler panic("vm_pager_put_pages: null pager");
18165692Shibler return ((*pager->pg_ops->pgo_putpages)(pager, mlist, npages, sync));
18245748Smckusick }
18345748Smckusick
184*67496Shibler /* XXX compatibility*/
185*67496Shibler int
vm_pager_get(pager,m,sync)186*67496Shibler vm_pager_get(pager, m, sync)
187*67496Shibler vm_pager_t pager;
188*67496Shibler vm_page_t m;
189*67496Shibler boolean_t sync;
190*67496Shibler {
191*67496Shibler return vm_pager_get_pages(pager, &m, 1, sync);
192*67496Shibler }
193*67496Shibler
194*67496Shibler /* XXX compatibility*/
195*67496Shibler int
vm_pager_put(pager,m,sync)196*67496Shibler vm_pager_put(pager, m, sync)
197*67496Shibler vm_pager_t pager;
198*67496Shibler vm_page_t m;
199*67496Shibler boolean_t sync;
200*67496Shibler {
201*67496Shibler return vm_pager_put_pages(pager, &m, 1, sync);
202*67496Shibler }
203*67496Shibler
20445748Smckusick boolean_t
vm_pager_has_page(pager,offset)20545748Smckusick vm_pager_has_page(pager, offset)
20645748Smckusick vm_pager_t pager;
20745748Smckusick vm_offset_t offset;
20845748Smckusick {
20948386Skarels if (pager == NULL)
21065692Shibler panic("vm_pager_has_page: null pager");
21165692Shibler return ((*pager->pg_ops->pgo_haspage)(pager, offset));
21245748Smckusick }
21345748Smckusick
21445748Smckusick /*
21545748Smckusick * Called by pageout daemon before going back to sleep.
21645748Smckusick * Gives pagers a chance to clean up any completed async pageing operations.
21745748Smckusick */
21845748Smckusick void
vm_pager_sync()21945748Smckusick vm_pager_sync()
22045748Smckusick {
22145748Smckusick struct pagerops **pgops;
22245748Smckusick
22345748Smckusick for (pgops = pagertab; pgops < &pagertab[npagers]; pgops++)
22464859Shibler if (pgops)
22565692Shibler (*(*pgops)->pgo_putpages)(NULL, NULL, 0, FALSE);
22645748Smckusick }
22745748Smckusick
22865692Shibler void
vm_pager_cluster(pager,offset,loff,hoff)22965692Shibler vm_pager_cluster(pager, offset, loff, hoff)
23065692Shibler vm_pager_t pager;
23165692Shibler vm_offset_t offset;
23265692Shibler vm_offset_t *loff;
23365692Shibler vm_offset_t *hoff;
23465692Shibler {
23565692Shibler if (pager == NULL)
23665692Shibler panic("vm_pager_cluster: null pager");
237*67496Shibler ((*pager->pg_ops->pgo_cluster)(pager, offset, loff, hoff));
23865692Shibler }
23965692Shibler
24065692Shibler void
vm_pager_clusternull(pager,offset,loff,hoff)24165692Shibler vm_pager_clusternull(pager, offset, loff, hoff)
24265692Shibler vm_pager_t pager;
24365692Shibler vm_offset_t offset;
24465692Shibler vm_offset_t *loff;
24565692Shibler vm_offset_t *hoff;
24665692Shibler {
24765692Shibler panic("vm_pager_nullcluster called");
24865692Shibler }
24965692Shibler
25045748Smckusick vm_offset_t
vm_pager_map_pages(mlist,npages,canwait)25165692Shibler vm_pager_map_pages(mlist, npages, canwait)
25265692Shibler vm_page_t *mlist;
25365692Shibler int npages;
25465692Shibler boolean_t canwait;
25545748Smckusick {
25665692Shibler vm_offset_t kva, va;
25765692Shibler vm_size_t size;
25865692Shibler vm_page_t m;
25945748Smckusick
26065692Shibler /*
26165692Shibler * Allocate space in the pager map, if none available return 0.
26265692Shibler * This is basically an expansion of kmem_alloc_wait with optional
26365692Shibler * blocking on no space.
26465692Shibler */
26565692Shibler size = npages * PAGE_SIZE;
26665692Shibler vm_map_lock(pager_map);
26765692Shibler while (vm_map_findspace(pager_map, 0, size, &kva)) {
26865692Shibler if (!canwait) {
26965692Shibler vm_map_unlock(pager_map);
27065692Shibler return (0);
27165692Shibler }
27265692Shibler pager_map_wanted = TRUE;
27365692Shibler vm_map_unlock(pager_map);
27465692Shibler (void) tsleep(pager_map, PVM, "pager_map", 0);
27565692Shibler vm_map_lock(pager_map);
27665692Shibler }
27765692Shibler vm_map_insert(pager_map, NULL, 0, kva, kva + size);
27865692Shibler vm_map_unlock(pager_map);
27965692Shibler
28065692Shibler for (va = kva; npages--; va += PAGE_SIZE) {
28165692Shibler m = *mlist++;
28249294Shibler #ifdef DEBUG
28365692Shibler if ((m->flags & PG_BUSY) == 0)
28465692Shibler panic("vm_pager_map_pages: page not busy");
28565692Shibler if (m->flags & PG_PAGEROWNED)
28665692Shibler panic("vm_pager_map_pages: page already in pager");
28749294Shibler #endif
28849294Shibler #ifdef DEBUG
28965692Shibler m->flags |= PG_PAGEROWNED;
29049294Shibler #endif
29165692Shibler pmap_enter(vm_map_pmap(pager_map), va, VM_PAGE_TO_PHYS(m),
29265692Shibler VM_PROT_DEFAULT, TRUE);
29365692Shibler }
29465692Shibler return (kva);
29545748Smckusick }
29645748Smckusick
29745748Smckusick void
vm_pager_unmap_pages(kva,npages)29865692Shibler vm_pager_unmap_pages(kva, npages)
29945748Smckusick vm_offset_t kva;
30065692Shibler int npages;
30145748Smckusick {
30265692Shibler vm_size_t size = npages * PAGE_SIZE;
30365692Shibler
30449294Shibler #ifdef DEBUG
30565692Shibler vm_offset_t va;
30649294Shibler vm_page_t m;
30765692Shibler int np = npages;
30849294Shibler
30965692Shibler for (va = kva; np--; va += PAGE_SIZE) {
31065692Shibler m = vm_pager_atop(va);
31165692Shibler if (m->flags & PG_PAGEROWNED)
31265692Shibler m->flags &= ~PG_PAGEROWNED;
31365692Shibler else
31465692Shibler printf("vm_pager_unmap_pages: %x(%x/%x) not owned\n",
31565692Shibler m, va, VM_PAGE_TO_PHYS(m));
31665692Shibler }
31745748Smckusick #endif
31865692Shibler pmap_remove(vm_map_pmap(pager_map), kva, kva + size);
31965692Shibler vm_map_lock(pager_map);
32065692Shibler (void) vm_map_delete(pager_map, kva, kva + size);
32165692Shibler if (pager_map_wanted)
32265692Shibler wakeup(pager_map);
32365692Shibler vm_map_unlock(pager_map);
32445748Smckusick }
32545748Smckusick
32665692Shibler vm_page_t
vm_pager_atop(kva)32765692Shibler vm_pager_atop(kva)
32865692Shibler vm_offset_t kva;
32965692Shibler {
33065692Shibler vm_offset_t pa;
33165692Shibler
33265692Shibler pa = pmap_extract(vm_map_pmap(pager_map), kva);
33365692Shibler if (pa == 0)
33465692Shibler panic("vm_pager_atop");
33565692Shibler return (PHYS_TO_VM_PAGE(pa));
33665692Shibler }
33765692Shibler
33845748Smckusick vm_pager_t
vm_pager_lookup(pglist,handle)33965231Smckusick vm_pager_lookup(pglist, handle)
34065231Smckusick register struct pagerlst *pglist;
34145748Smckusick caddr_t handle;
34245748Smckusick {
34345748Smckusick register vm_pager_t pager;
34445748Smckusick
34565231Smckusick for (pager = pglist->tqh_first; pager; pager = pager->pg_list.tqe_next)
34645748Smckusick if (pager->pg_handle == handle)
34765692Shibler return (pager);
34865692Shibler return (NULL);
34945748Smckusick }
35045748Smckusick
35145748Smckusick /*
35245748Smckusick * This routine gains a reference to the object.
35345748Smckusick * Explicit deallocation is necessary.
35445748Smckusick */
35553360Sbostic int
pager_cache(object,should_cache)35645748Smckusick pager_cache(object, should_cache)
35745748Smckusick vm_object_t object;
35845748Smckusick boolean_t should_cache;
35945748Smckusick {
36048386Skarels if (object == NULL)
36165692Shibler return (KERN_INVALID_ARGUMENT);
36245748Smckusick
36345748Smckusick vm_object_cache_lock();
36445748Smckusick vm_object_lock(object);
36550920Smckusick if (should_cache)
36650920Smckusick object->flags |= OBJ_CANPERSIST;
36750920Smckusick else
36850920Smckusick object->flags &= ~OBJ_CANPERSIST;
36945748Smckusick vm_object_unlock(object);
37045748Smckusick vm_object_cache_unlock();
37145748Smckusick
37245748Smckusick vm_object_deallocate(object);
37345748Smckusick
37465692Shibler return (KERN_SUCCESS);
37545748Smckusick }
376