xref: /csrg-svn/sys/vm/vm_pager.c (revision 65231)
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*65231Smckusick  *	@(#)vm_pager.c	8.4 (Berkeley) 12/30/93
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.
8845748Smckusick  */
8945748Smckusick #define PAGER_MAP_SIZE	(256 * PAGE_SIZE)
9045748Smckusick vm_map_t pager_map;
9149294Shibler vm_offset_t pager_sva, pager_eva;
9245748Smckusick 
9345748Smckusick void
9445748Smckusick vm_pager_init()
9545748Smckusick {
9645748Smckusick 	struct pagerops **pgops;
9745748Smckusick 
9845748Smckusick 	/*
9945748Smckusick 	 * Allocate a kernel submap for tracking get/put page mappings
10045748Smckusick 	 */
10149294Shibler 	pager_map = kmem_suballoc(kernel_map, &pager_sva, &pager_eva,
10245748Smckusick 				  PAGER_MAP_SIZE, FALSE);
10345748Smckusick 	/*
10445748Smckusick 	 * Initialize known pagers
10545748Smckusick 	 */
10645748Smckusick 	for (pgops = pagertab; pgops < &pagertab[npagers]; pgops++)
10764859Shibler 		if (pgops)
10864859Shibler 			(*(*pgops)->pgo_init)();
10948386Skarels 	if (dfltpagerops == NULL)
11045748Smckusick 		panic("no default pager");
11145748Smckusick }
11245748Smckusick 
11345748Smckusick /*
11445748Smckusick  * Allocate an instance of a pager of the given type.
11564859Shibler  * Size, protection and offset parameters are passed in for pagers that
11664859Shibler  * need to perform page-level validation (e.g. the device pager).
11745748Smckusick  */
11845748Smckusick vm_pager_t
11964827Storek vm_pager_allocate(type, handle, size, prot, off)
12045748Smckusick 	int type;
12145748Smckusick 	caddr_t handle;
12245748Smckusick 	vm_size_t size;
12345748Smckusick 	vm_prot_t prot;
12464827Storek 	vm_offset_t off;
12545748Smckusick {
12645748Smckusick 	vm_pager_t pager;
12745748Smckusick 	struct pagerops *ops;
12845748Smckusick 
12945748Smckusick 	ops = (type == PG_DFLT) ? dfltpagerops : pagertab[type];
13064859Shibler 	if (ops)
13164859Shibler 		return ((*ops->pgo_alloc)(handle, size, prot, off));
13264859Shibler 	return (NULL);
13345748Smckusick }
13445748Smckusick 
13545748Smckusick void
13645748Smckusick vm_pager_deallocate(pager)
13745748Smckusick 	vm_pager_t	pager;
13845748Smckusick {
13948386Skarels 	if (pager == NULL)
14045748Smckusick 		panic("vm_pager_deallocate: null pager");
14145748Smckusick 
14245748Smckusick 	VM_PAGER_DEALLOC(pager);
14345748Smckusick }
14445748Smckusick 
14553360Sbostic int
14645748Smckusick vm_pager_get(pager, m, sync)
14745748Smckusick 	vm_pager_t	pager;
14845748Smckusick 	vm_page_t	m;
14945748Smckusick 	boolean_t	sync;
15045748Smckusick {
15145748Smckusick 	extern boolean_t vm_page_zero_fill();
15245748Smckusick 
15348386Skarels 	if (pager == NULL)
15445748Smckusick 		return(vm_page_zero_fill(m) ? VM_PAGER_OK : VM_PAGER_FAIL);
15545748Smckusick 	return(VM_PAGER_GET(pager, m, sync));
15645748Smckusick }
15745748Smckusick 
15853360Sbostic int
15945748Smckusick vm_pager_put(pager, m, sync)
16045748Smckusick 	vm_pager_t	pager;
16145748Smckusick 	vm_page_t	m;
16245748Smckusick 	boolean_t	sync;
16345748Smckusick {
16448386Skarels 	if (pager == NULL)
16545748Smckusick 		panic("vm_pager_put: null pager");
16645748Smckusick 	return(VM_PAGER_PUT(pager, m, sync));
16745748Smckusick }
16845748Smckusick 
16945748Smckusick boolean_t
17045748Smckusick vm_pager_has_page(pager, offset)
17145748Smckusick 	vm_pager_t	pager;
17245748Smckusick 	vm_offset_t	offset;
17345748Smckusick {
17448386Skarels 	if (pager == NULL)
17545748Smckusick 		panic("vm_pager_has_page");
17645748Smckusick 	return(VM_PAGER_HASPAGE(pager, offset));
17745748Smckusick }
17845748Smckusick 
17945748Smckusick /*
18045748Smckusick  * Called by pageout daemon before going back to sleep.
18145748Smckusick  * Gives pagers a chance to clean up any completed async pageing operations.
18245748Smckusick  */
18345748Smckusick void
18445748Smckusick vm_pager_sync()
18545748Smckusick {
18645748Smckusick 	struct pagerops **pgops;
18745748Smckusick 
18845748Smckusick 	for (pgops = pagertab; pgops < &pagertab[npagers]; pgops++)
18964859Shibler 		if (pgops)
19064859Shibler 			(*(*pgops)->pgo_putpage)(NULL, NULL, FALSE);
19145748Smckusick }
19245748Smckusick 
19345748Smckusick vm_offset_t
19445748Smckusick vm_pager_map_page(m)
19545748Smckusick 	vm_page_t	m;
19645748Smckusick {
19745748Smckusick 	vm_offset_t kva;
19845748Smckusick 
19949294Shibler #ifdef DEBUG
20057835Smckusick 	if ((m->flags & PG_BUSY) == 0)
20157835Smckusick 		panic("vm_pager_map_page: page not busy");
20256382Smckusick 	if (m->flags & PG_PAGEROWNED)
20349294Shibler 		printf("vm_pager_map_page: page %x already in pager\n", m);
20449294Shibler #endif
20545748Smckusick 	kva = kmem_alloc_wait(pager_map, PAGE_SIZE);
20649294Shibler #ifdef DEBUG
20756382Smckusick 	m->flags |= PG_PAGEROWNED;
20849294Shibler #endif
20945748Smckusick 	pmap_enter(vm_map_pmap(pager_map), kva, VM_PAGE_TO_PHYS(m),
21045748Smckusick 		   VM_PROT_DEFAULT, TRUE);
21145748Smckusick 	return(kva);
21245748Smckusick }
21345748Smckusick 
21445748Smckusick void
21545748Smckusick vm_pager_unmap_page(kva)
21645748Smckusick 	vm_offset_t	kva;
21745748Smckusick {
21849294Shibler #ifdef DEBUG
21949294Shibler 	vm_page_t m;
22049294Shibler 
22149294Shibler 	m = PHYS_TO_VM_PAGE(pmap_extract(vm_map_pmap(pager_map), kva));
22245748Smckusick #endif
22349294Shibler 	pmap_remove(vm_map_pmap(pager_map), kva, kva + PAGE_SIZE);
22445748Smckusick 	kmem_free_wakeup(pager_map, kva, PAGE_SIZE);
22549294Shibler #ifdef DEBUG
22656382Smckusick 	if (m->flags & PG_PAGEROWNED)
22756382Smckusick 		m->flags &= ~PG_PAGEROWNED;
22849294Shibler 	else
22949294Shibler 		printf("vm_pager_unmap_page: page %x(%x/%x) not owned\n",
23049294Shibler 		       m, kva, VM_PAGE_TO_PHYS(m));
23149294Shibler #endif
23245748Smckusick }
23345748Smckusick 
23445748Smckusick vm_pager_t
235*65231Smckusick vm_pager_lookup(pglist, handle)
236*65231Smckusick 	register struct pagerlst *pglist;
23745748Smckusick 	caddr_t handle;
23845748Smckusick {
23945748Smckusick 	register vm_pager_t pager;
24045748Smckusick 
241*65231Smckusick 	for (pager = pglist->tqh_first; pager; pager = pager->pg_list.tqe_next)
24245748Smckusick 		if (pager->pg_handle == handle)
24345748Smckusick 			return(pager);
24448386Skarels 	return(NULL);
24545748Smckusick }
24645748Smckusick 
24745748Smckusick /*
24845748Smckusick  * This routine gains a reference to the object.
24945748Smckusick  * Explicit deallocation is necessary.
25045748Smckusick  */
25153360Sbostic int
25245748Smckusick pager_cache(object, should_cache)
25345748Smckusick 	vm_object_t	object;
25445748Smckusick 	boolean_t	should_cache;
25545748Smckusick {
25648386Skarels 	if (object == NULL)
25745748Smckusick 		return(KERN_INVALID_ARGUMENT);
25845748Smckusick 
25945748Smckusick 	vm_object_cache_lock();
26045748Smckusick 	vm_object_lock(object);
26150920Smckusick 	if (should_cache)
26250920Smckusick 		object->flags |= OBJ_CANPERSIST;
26350920Smckusick 	else
26450920Smckusick 		object->flags &= ~OBJ_CANPERSIST;
26545748Smckusick 	vm_object_unlock(object);
26645748Smckusick 	vm_object_cache_unlock();
26745748Smckusick 
26845748Smckusick 	vm_object_deallocate(object);
26945748Smckusick 
27045748Smckusick 	return(KERN_SUCCESS);
27145748Smckusick }
272