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