xref: /freebsd/sys/vm/phys_pager.c (revision e735691b613c2ac4aed254ffefeef429c91c2e0d)
160727d8bSWarner Losh /*-
224964514SPeter Wemm  * Copyright (c) 2000 Peter Wemm
324964514SPeter Wemm  *
424964514SPeter Wemm  * Redistribution and use in source and binary forms, with or without
524964514SPeter Wemm  * modification, are permitted provided that the following conditions
624964514SPeter Wemm  * are met:
724964514SPeter Wemm  * 1. Redistributions of source code must retain the above copyright
824964514SPeter Wemm  *    notice, this list of conditions and the following disclaimer.
924964514SPeter Wemm  * 2. Redistributions in binary form must reproduce the above copyright
1024964514SPeter Wemm  *    notice, this list of conditions and the following disclaimer in the
1124964514SPeter Wemm  *    documentation and/or other materials provided with the distribution.
1224964514SPeter Wemm  *
1324964514SPeter Wemm  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
1424964514SPeter Wemm  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1524964514SPeter Wemm  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1624964514SPeter Wemm  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
1724964514SPeter Wemm  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1824964514SPeter Wemm  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1924964514SPeter Wemm  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2024964514SPeter Wemm  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2124964514SPeter Wemm  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2224964514SPeter Wemm  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2324964514SPeter Wemm  * SUCH DAMAGE.
2424964514SPeter Wemm  */
2524964514SPeter Wemm 
26874651b1SDavid E. O'Brien #include <sys/cdefs.h>
27874651b1SDavid E. O'Brien __FBSDID("$FreeBSD$");
28874651b1SDavid E. O'Brien 
2924964514SPeter Wemm #include <sys/param.h>
3024964514SPeter Wemm #include <sys/systm.h>
3124964514SPeter Wemm #include <sys/conf.h>
32a9fa2c05SAlfred Perlstein #include <sys/kernel.h>
33fb919e4dSMark Murray #include <sys/lock.h>
340cddd8f0SMatthew Dillon #include <sys/proc.h>
35fb919e4dSMark Murray #include <sys/mutex.h>
3624964514SPeter Wemm #include <sys/mman.h>
3789f6b863SAttilio Rao #include <sys/rwlock.h>
3824964514SPeter Wemm #include <sys/sysctl.h>
3924964514SPeter Wemm 
4024964514SPeter Wemm #include <vm/vm.h>
41c7aebda8SAttilio Rao #include <vm/vm_param.h>
4224964514SPeter Wemm #include <vm/vm_object.h>
4324964514SPeter Wemm #include <vm/vm_page.h>
4424964514SPeter Wemm #include <vm/vm_pager.h>
4524964514SPeter Wemm 
46248a0568SRemko Lodder /* list of phys pager objects */
4724964514SPeter Wemm static struct pagerlst phys_pager_object_list;
48a9fa2c05SAlfred Perlstein /* protect access to phys_pager_object_list */
49a9fa2c05SAlfred Perlstein static struct mtx phys_pager_mtx;
5024964514SPeter Wemm 
5124964514SPeter Wemm static void
52bb663856SPeter Wemm phys_pager_init(void)
5324964514SPeter Wemm {
54bb663856SPeter Wemm 
5524964514SPeter Wemm 	TAILQ_INIT(&phys_pager_object_list);
566008862bSJohn Baldwin 	mtx_init(&phys_pager_mtx, "phys_pager list", NULL, MTX_DEF);
5724964514SPeter Wemm }
5824964514SPeter Wemm 
592a1618cdSAlan Cox /*
602a1618cdSAlan Cox  * MPSAFE
612a1618cdSAlan Cox  */
6224964514SPeter Wemm static vm_object_t
6324964514SPeter Wemm phys_pager_alloc(void *handle, vm_ooffset_t size, vm_prot_t prot,
643364c323SKonstantin Belousov     vm_ooffset_t foff, struct ucred *cred)
6524964514SPeter Wemm {
66efe7553eSKonstantin Belousov 	vm_object_t object, object1;
672f7af3dbSAlan Cox 	vm_pindex_t pindex;
6824964514SPeter Wemm 
6924964514SPeter Wemm 	/*
7024964514SPeter Wemm 	 * Offset should be page aligned.
7124964514SPeter Wemm 	 */
7224964514SPeter Wemm 	if (foff & PAGE_MASK)
7324964514SPeter Wemm 		return (NULL);
7424964514SPeter Wemm 
752f7af3dbSAlan Cox 	pindex = OFF_TO_IDX(foff + PAGE_MASK + size);
7624964514SPeter Wemm 
77b5861b34SAlfred Perlstein 	if (handle != NULL) {
78efe7553eSKonstantin Belousov 		mtx_lock(&phys_pager_mtx);
7924964514SPeter Wemm 		/*
8024964514SPeter Wemm 		 * Look up pager, creating as necessary.
8124964514SPeter Wemm 		 */
82efe7553eSKonstantin Belousov 		object1 = NULL;
8324964514SPeter Wemm 		object = vm_pager_object_lookup(&phys_pager_object_list, handle);
8424964514SPeter Wemm 		if (object == NULL) {
8524964514SPeter Wemm 			/*
8624964514SPeter Wemm 			 * Allocate object and associate it with the pager.
8724964514SPeter Wemm 			 */
88efe7553eSKonstantin Belousov 			mtx_unlock(&phys_pager_mtx);
89efe7553eSKonstantin Belousov 			object1 = vm_object_allocate(OBJT_PHYS, pindex);
90a9fa2c05SAlfred Perlstein 			mtx_lock(&phys_pager_mtx);
91efe7553eSKonstantin Belousov 			object = vm_pager_object_lookup(&phys_pager_object_list,
92efe7553eSKonstantin Belousov 			    handle);
93efe7553eSKonstantin Belousov 			if (object != NULL) {
94efe7553eSKonstantin Belousov 				/*
95efe7553eSKonstantin Belousov 				 * We raced with other thread while
96efe7553eSKonstantin Belousov 				 * allocating object.
97efe7553eSKonstantin Belousov 				 */
98efe7553eSKonstantin Belousov 				if (pindex > object->size)
99efe7553eSKonstantin Belousov 					object->size = pindex;
100efe7553eSKonstantin Belousov 			} else {
101efe7553eSKonstantin Belousov 				object = object1;
102efe7553eSKonstantin Belousov 				object1 = NULL;
103efe7553eSKonstantin Belousov 				object->handle = handle;
10424964514SPeter Wemm 				TAILQ_INSERT_TAIL(&phys_pager_object_list, object,
10524964514SPeter Wemm 				    pager_object_list);
106efe7553eSKonstantin Belousov 			}
10724964514SPeter Wemm 		} else {
1082f7af3dbSAlan Cox 			if (pindex > object->size)
1092f7af3dbSAlan Cox 				object->size = pindex;
11024964514SPeter Wemm 		}
111efe7553eSKonstantin Belousov 		mtx_unlock(&phys_pager_mtx);
112efe7553eSKonstantin Belousov 		vm_object_deallocate(object1);
113b5861b34SAlfred Perlstein 	} else {
1142f7af3dbSAlan Cox 		object = vm_object_allocate(OBJT_PHYS, pindex);
115b5861b34SAlfred Perlstein 	}
11624964514SPeter Wemm 
11724964514SPeter Wemm 	return (object);
11824964514SPeter Wemm }
11924964514SPeter Wemm 
1202a1618cdSAlan Cox /*
1212a1618cdSAlan Cox  * MPSAFE
1222a1618cdSAlan Cox  */
12324964514SPeter Wemm static void
124bb663856SPeter Wemm phys_pager_dealloc(vm_object_t object)
12524964514SPeter Wemm {
12624964514SPeter Wemm 
127a9fa2c05SAlfred Perlstein 	if (object->handle != NULL) {
12889f6b863SAttilio Rao 		VM_OBJECT_WUNLOCK(object);
129a9fa2c05SAlfred Perlstein 		mtx_lock(&phys_pager_mtx);
13024964514SPeter Wemm 		TAILQ_REMOVE(&phys_pager_object_list, object, pager_object_list);
131a9fa2c05SAlfred Perlstein 		mtx_unlock(&phys_pager_mtx);
13289f6b863SAttilio Rao 		VM_OBJECT_WLOCK(object);
133a9fa2c05SAlfred Perlstein 	}
134*e735691bSJohn Baldwin 	object->handle = NULL;
135*e735691bSJohn Baldwin 	object->type = OBJT_DEAD;
13624964514SPeter Wemm }
13724964514SPeter Wemm 
13824964514SPeter Wemm /*
13924964514SPeter Wemm  * Fill as many pages as vm_fault has allocated for us.
14024964514SPeter Wemm  */
141e265f054SAlan Cox static int
142e265f054SAlan Cox phys_pager_getpages(vm_object_t object, vm_page_t *m, int count, int reqpage)
143e265f054SAlan Cox {
144e265f054SAlan Cox 	int i;
145e265f054SAlan Cox 
14689f6b863SAttilio Rao 	VM_OBJECT_ASSERT_WLOCKED(object);
1478a3ef857SAlan Cox 	for (i = 0; i < count; i++) {
1488a3ef857SAlan Cox 		if (m[i]->valid == 0) {
1498a3ef857SAlan Cox 			if ((m[i]->flags & PG_ZERO) == 0)
1508a3ef857SAlan Cox 				pmap_zero_page(m[i]);
1518a3ef857SAlan Cox 			m[i]->valid = VM_PAGE_BITS_ALL;
1528a3ef857SAlan Cox 		}
1538a3ef857SAlan Cox 		KASSERT(m[i]->valid == VM_PAGE_BITS_ALL,
1548a3ef857SAlan Cox 		    ("phys_pager_getpages: partially valid page %p", m[i]));
15553f55a43SAlan Cox 		KASSERT(m[i]->dirty == 0,
15653f55a43SAlan Cox 		    ("phys_pager_getpages: dirty page %p", m[i]));
15724964514SPeter Wemm 		/* The requested page must remain busy, the others not. */
158c7aebda8SAttilio Rao 		if (i == reqpage) {
159c7aebda8SAttilio Rao 			vm_page_lock(m[i]);
1605637a591SKonstantin Belousov 			vm_page_flash(m[i]);
161c7aebda8SAttilio Rao 			vm_page_unlock(m[i]);
162c7aebda8SAttilio Rao 		} else
163c7aebda8SAttilio Rao 			vm_page_xunbusy(m[i]);
16424964514SPeter Wemm 	}
16524964514SPeter Wemm 	return (VM_PAGER_OK);
16624964514SPeter Wemm }
16724964514SPeter Wemm 
16824964514SPeter Wemm static void
169bb663856SPeter Wemm phys_pager_putpages(vm_object_t object, vm_page_t *m, int count, boolean_t sync,
170bb663856SPeter Wemm 		    int *rtvals)
17124964514SPeter Wemm {
172bb663856SPeter Wemm 
17324964514SPeter Wemm 	panic("phys_pager_putpage called");
17424964514SPeter Wemm }
17524964514SPeter Wemm 
17624964514SPeter Wemm /*
17724964514SPeter Wemm  * Implement a pretty aggressive clustered getpages strategy.  Hint that
17824964514SPeter Wemm  * everything in an entire 4MB window should be prefaulted at once.
17924964514SPeter Wemm  *
18024964514SPeter Wemm  * XXX 4MB (1024 slots per page table page) is convenient for x86,
18124964514SPeter Wemm  * but may not be for other arches.
18224964514SPeter Wemm  */
18324964514SPeter Wemm #ifndef PHYSCLUSTER
18424964514SPeter Wemm #define PHYSCLUSTER 1024
18524964514SPeter Wemm #endif
18624964514SPeter Wemm static boolean_t
187bb663856SPeter Wemm phys_pager_haspage(vm_object_t object, vm_pindex_t pindex, int *before,
188bb663856SPeter Wemm 		   int *after)
18924964514SPeter Wemm {
19024964514SPeter Wemm 	vm_pindex_t base, end;
19124964514SPeter Wemm 
19224964514SPeter Wemm 	base = pindex & (~(PHYSCLUSTER - 1));
19324964514SPeter Wemm 	end = base + (PHYSCLUSTER - 1);
19424964514SPeter Wemm 	if (before != NULL)
19524964514SPeter Wemm 		*before = pindex - base;
19624964514SPeter Wemm 	if (after != NULL)
19724964514SPeter Wemm 		*after = end - pindex;
19824964514SPeter Wemm 	return (TRUE);
19924964514SPeter Wemm }
200bb663856SPeter Wemm 
201bb663856SPeter Wemm struct pagerops physpagerops = {
2024e658600SPoul-Henning Kamp 	.pgo_init =	phys_pager_init,
2034e658600SPoul-Henning Kamp 	.pgo_alloc =	phys_pager_alloc,
2044e658600SPoul-Henning Kamp 	.pgo_dealloc = 	phys_pager_dealloc,
2054e658600SPoul-Henning Kamp 	.pgo_getpages =	phys_pager_getpages,
2064e658600SPoul-Henning Kamp 	.pgo_putpages =	phys_pager_putpages,
2074e658600SPoul-Henning Kamp 	.pgo_haspage =	phys_pager_haspage,
208bb663856SPeter Wemm };
209