xref: /freebsd/sys/vm/phys_pager.c (revision 63e9755548e4feebf798686ab8bce0cdaaaf7b46)
160727d8bSWarner Losh /*-
2fe267a55SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3fe267a55SPedro F. Giffuni  *
424964514SPeter Wemm  * Copyright (c) 2000 Peter Wemm
524964514SPeter Wemm  *
624964514SPeter Wemm  * Redistribution and use in source and binary forms, with or without
724964514SPeter Wemm  * modification, are permitted provided that the following conditions
824964514SPeter Wemm  * are met:
924964514SPeter Wemm  * 1. Redistributions of source code must retain the above copyright
1024964514SPeter Wemm  *    notice, this list of conditions and the following disclaimer.
1124964514SPeter Wemm  * 2. Redistributions in binary form must reproduce the above copyright
1224964514SPeter Wemm  *    notice, this list of conditions and the following disclaimer in the
1324964514SPeter Wemm  *    documentation and/or other materials provided with the distribution.
1424964514SPeter Wemm  *
1524964514SPeter Wemm  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
1624964514SPeter Wemm  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1724964514SPeter Wemm  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1824964514SPeter Wemm  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
1924964514SPeter Wemm  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2024964514SPeter Wemm  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2124964514SPeter Wemm  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2224964514SPeter Wemm  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2324964514SPeter Wemm  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2424964514SPeter Wemm  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2524964514SPeter Wemm  * SUCH DAMAGE.
2624964514SPeter Wemm  */
2724964514SPeter Wemm 
28874651b1SDavid E. O'Brien #include <sys/cdefs.h>
29874651b1SDavid E. O'Brien __FBSDID("$FreeBSD$");
30874651b1SDavid E. O'Brien 
3124964514SPeter Wemm #include <sys/param.h>
3224964514SPeter Wemm #include <sys/systm.h>
3324964514SPeter Wemm #include <sys/conf.h>
34a9fa2c05SAlfred Perlstein #include <sys/kernel.h>
35fb919e4dSMark Murray #include <sys/lock.h>
360cddd8f0SMatthew Dillon #include <sys/proc.h>
37fb919e4dSMark Murray #include <sys/mutex.h>
3824964514SPeter Wemm #include <sys/mman.h>
3989f6b863SAttilio Rao #include <sys/rwlock.h>
4024964514SPeter Wemm #include <sys/sysctl.h>
4124964514SPeter Wemm 
4224964514SPeter Wemm #include <vm/vm.h>
43c7aebda8SAttilio Rao #include <vm/vm_param.h>
4424964514SPeter Wemm #include <vm/vm_object.h>
4524964514SPeter Wemm #include <vm/vm_page.h>
46ed01d989SKonstantin Belousov #include <vm/vm_pageout.h>
4724964514SPeter Wemm #include <vm/vm_pager.h>
4824964514SPeter Wemm 
49248a0568SRemko Lodder /* list of phys pager objects */
5024964514SPeter Wemm static struct pagerlst phys_pager_object_list;
51a9fa2c05SAlfred Perlstein /* protect access to phys_pager_object_list */
52a9fa2c05SAlfred Perlstein static struct mtx phys_pager_mtx;
5324964514SPeter Wemm 
5424964514SPeter Wemm static void
55bb663856SPeter Wemm phys_pager_init(void)
5624964514SPeter Wemm {
57bb663856SPeter Wemm 
5824964514SPeter Wemm 	TAILQ_INIT(&phys_pager_object_list);
596008862bSJohn Baldwin 	mtx_init(&phys_pager_mtx, "phys_pager list", NULL, MTX_DEF);
6024964514SPeter Wemm }
6124964514SPeter Wemm 
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;
104ed01d989SKonstantin Belousov 				vm_object_set_flag(object, OBJ_POPULATE);
105272cc3c4SKonstantin Belousov 				TAILQ_INSERT_TAIL(&phys_pager_object_list,
106272cc3c4SKonstantin Belousov 				    object, pager_object_list);
107efe7553eSKonstantin Belousov 			}
10824964514SPeter Wemm 		} else {
1092f7af3dbSAlan Cox 			if (pindex > object->size)
1102f7af3dbSAlan Cox 				object->size = pindex;
11124964514SPeter Wemm 		}
112efe7553eSKonstantin Belousov 		mtx_unlock(&phys_pager_mtx);
113efe7553eSKonstantin Belousov 		vm_object_deallocate(object1);
114b5861b34SAlfred Perlstein 	} else {
1152f7af3dbSAlan Cox 		object = vm_object_allocate(OBJT_PHYS, pindex);
116ed01d989SKonstantin Belousov 		vm_object_set_flag(object, OBJ_POPULATE);
117b5861b34SAlfred Perlstein 	}
11824964514SPeter Wemm 
11924964514SPeter Wemm 	return (object);
12024964514SPeter Wemm }
12124964514SPeter Wemm 
12224964514SPeter Wemm static void
123bb663856SPeter Wemm phys_pager_dealloc(vm_object_t object)
12424964514SPeter Wemm {
12524964514SPeter Wemm 
126a9fa2c05SAlfred Perlstein 	if (object->handle != NULL) {
12789f6b863SAttilio Rao 		VM_OBJECT_WUNLOCK(object);
128a9fa2c05SAlfred Perlstein 		mtx_lock(&phys_pager_mtx);
12924964514SPeter Wemm 		TAILQ_REMOVE(&phys_pager_object_list, object, pager_object_list);
130a9fa2c05SAlfred Perlstein 		mtx_unlock(&phys_pager_mtx);
13189f6b863SAttilio Rao 		VM_OBJECT_WLOCK(object);
132a9fa2c05SAlfred Perlstein 	}
133e735691bSJohn Baldwin 	object->handle = NULL;
134e735691bSJohn Baldwin 	object->type = OBJT_DEAD;
13524964514SPeter Wemm }
13624964514SPeter Wemm 
13724964514SPeter Wemm /*
13824964514SPeter Wemm  * Fill as many pages as vm_fault has allocated for us.
13924964514SPeter Wemm  */
140e265f054SAlan Cox static int
141b0cd2017SGleb Smirnoff phys_pager_getpages(vm_object_t object, vm_page_t *m, int count, int *rbehind,
142b0cd2017SGleb Smirnoff     int *rahead)
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 	}
158b0cd2017SGleb Smirnoff 	if (rbehind)
159b0cd2017SGleb Smirnoff 		*rbehind = 0;
160b0cd2017SGleb Smirnoff 	if (rahead)
161b0cd2017SGleb Smirnoff 		*rahead = 0;
16224964514SPeter Wemm 	return (VM_PAGER_OK);
16324964514SPeter Wemm }
16424964514SPeter Wemm 
165ed01d989SKonstantin Belousov /*
166ed01d989SKonstantin Belousov  * Implement a pretty aggressive clustered getpages strategy.  Hint that
167ed01d989SKonstantin Belousov  * everything in an entire 4MB window should be prefaulted at once.
168ed01d989SKonstantin Belousov  *
169ed01d989SKonstantin Belousov  * 4MB (1024 slots per page table page) is convenient for x86,
170ed01d989SKonstantin Belousov  * but may not be for other arches.
171ed01d989SKonstantin Belousov  */
172ed01d989SKonstantin Belousov #ifndef PHYSCLUSTER
173ed01d989SKonstantin Belousov #define PHYSCLUSTER 1024
174ed01d989SKonstantin Belousov #endif
175ed01d989SKonstantin Belousov static int phys_pager_cluster = PHYSCLUSTER;
176ed01d989SKonstantin Belousov SYSCTL_INT(_vm, OID_AUTO, phys_pager_cluster, CTLFLAG_RWTUN,
177ed01d989SKonstantin Belousov     &phys_pager_cluster, 0,
178ed01d989SKonstantin Belousov     "prefault window size for phys pager");
179ed01d989SKonstantin Belousov 
180ed01d989SKonstantin Belousov /*
181ed01d989SKonstantin Belousov  * Max hint to vm_page_alloc() about the further allocation needs
182ed01d989SKonstantin Belousov  * inside the phys_pager_populate() loop.  The number of bits used to
183ed01d989SKonstantin Belousov  * implement VM_ALLOC_COUNT() determines the hard limit on this value.
184ed01d989SKonstantin Belousov  * That limit is currently 65535.
185ed01d989SKonstantin Belousov  */
186ed01d989SKonstantin Belousov #define	PHYSALLOC	16
187ed01d989SKonstantin Belousov 
188ed01d989SKonstantin Belousov static int
189ed01d989SKonstantin Belousov phys_pager_populate(vm_object_t object, vm_pindex_t pidx,
190ed01d989SKonstantin Belousov     int fault_type __unused, vm_prot_t max_prot __unused, vm_pindex_t *first,
191ed01d989SKonstantin Belousov     vm_pindex_t *last)
192ed01d989SKonstantin Belousov {
193ed01d989SKonstantin Belousov 	vm_page_t m;
194ed01d989SKonstantin Belousov 	vm_pindex_t base, end, i;
195ed01d989SKonstantin Belousov 	int ahead;
196ed01d989SKonstantin Belousov 
197ed01d989SKonstantin Belousov 	base = rounddown(pidx, phys_pager_cluster);
198ed01d989SKonstantin Belousov 	end = base + phys_pager_cluster - 1;
199ed01d989SKonstantin Belousov 	if (end >= object->size)
200ed01d989SKonstantin Belousov 		end = object->size - 1;
201ed01d989SKonstantin Belousov 	if (*first > base)
202ed01d989SKonstantin Belousov 		base = *first;
203ed01d989SKonstantin Belousov 	if (end > *last)
204ed01d989SKonstantin Belousov 		end = *last;
205ed01d989SKonstantin Belousov 	*first = base;
206ed01d989SKonstantin Belousov 	*last = end;
207ed01d989SKonstantin Belousov 
208ed01d989SKonstantin Belousov 	for (i = base; i <= end; i++) {
209ed01d989SKonstantin Belousov 		ahead = MIN(end - i, PHYSALLOC);
210*63e97555SJeff Roberson 		m = vm_page_grab(object, i,
211*63e97555SJeff Roberson 		    VM_ALLOC_NORMAL | VM_ALLOC_COUNT(ahead));
212*63e97555SJeff Roberson 		if (m->valid != VM_PAGE_BITS_ALL) {
213ed01d989SKonstantin Belousov 			vm_page_zero_invalid(m, TRUE);
214*63e97555SJeff Roberson 			m->valid = VM_PAGE_BITS_ALL;
215ed01d989SKonstantin Belousov 		}
216ed01d989SKonstantin Belousov 		KASSERT(m->dirty == 0,
217ed01d989SKonstantin Belousov 		    ("phys_pager_populate: dirty page %p", m));
218ed01d989SKonstantin Belousov 	}
219ed01d989SKonstantin Belousov 	return (VM_PAGER_OK);
220ed01d989SKonstantin Belousov }
221ed01d989SKonstantin Belousov 
22224964514SPeter Wemm static void
223bb663856SPeter Wemm phys_pager_putpages(vm_object_t object, vm_page_t *m, int count, boolean_t sync,
224bb663856SPeter Wemm     int *rtvals)
22524964514SPeter Wemm {
226bb663856SPeter Wemm 
22724964514SPeter Wemm 	panic("phys_pager_putpage called");
22824964514SPeter Wemm }
22924964514SPeter Wemm 
23024964514SPeter Wemm static boolean_t
231bb663856SPeter Wemm phys_pager_haspage(vm_object_t object, vm_pindex_t pindex, int *before,
232bb663856SPeter Wemm     int *after)
23324964514SPeter Wemm {
23424964514SPeter Wemm 	vm_pindex_t base, end;
23524964514SPeter Wemm 
236ed01d989SKonstantin Belousov 	base = rounddown(pindex, phys_pager_cluster);
237ed01d989SKonstantin Belousov 	end = base + phys_pager_cluster - 1;
23824964514SPeter Wemm 	if (before != NULL)
23924964514SPeter Wemm 		*before = pindex - base;
24024964514SPeter Wemm 	if (after != NULL)
24124964514SPeter Wemm 		*after = end - pindex;
24224964514SPeter Wemm 	return (TRUE);
24324964514SPeter Wemm }
244bb663856SPeter Wemm 
245bb663856SPeter Wemm struct pagerops physpagerops = {
2464e658600SPoul-Henning Kamp 	.pgo_init =	phys_pager_init,
2474e658600SPoul-Henning Kamp 	.pgo_alloc =	phys_pager_alloc,
2484e658600SPoul-Henning Kamp 	.pgo_dealloc = 	phys_pager_dealloc,
2494e658600SPoul-Henning Kamp 	.pgo_getpages =	phys_pager_getpages,
2504e658600SPoul-Henning Kamp 	.pgo_putpages =	phys_pager_putpages,
2514e658600SPoul-Henning Kamp 	.pgo_haspage =	phys_pager_haspage,
252ed01d989SKonstantin Belousov 	.pgo_populate =	phys_pager_populate,
253bb663856SPeter Wemm };
254