xref: /csrg-svn/sys/vm/vm_pager.c (revision 65692)
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