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