phys_pager.c revision 98605
1161748Scperciva/* 2161748Scperciva * Copyright (c) 2000 Peter Wemm 3161748Scperciva * 4161748Scperciva * Redistribution and use in source and binary forms, with or without 5161748Scperciva * modification, are permitted provided that the following conditions 6161748Scperciva * are met: 7161748Scperciva * 1. Redistributions of source code must retain the above copyright 8161748Scperciva * notice, this list of conditions and the following disclaimer. 9161748Scperciva * 2. Redistributions in binary form must reproduce the above copyright 10161748Scperciva * notice, this list of conditions and the following disclaimer in the 11161748Scperciva * documentation and/or other materials provided with the distribution. 12161748Scperciva * 13161748Scperciva * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 14161748Scperciva * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15161748Scperciva * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16161748Scperciva * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 17161748Scperciva * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18161748Scperciva * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19161748Scperciva * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20161748Scperciva * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21161748Scperciva * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22161748Scperciva * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23161748Scperciva * SUCH DAMAGE. 24161748Scperciva * 25161748Scperciva * $FreeBSD: head/sys/vm/phys_pager.c 98605 2002-06-22 07:54:42Z alc $ 26161748Scperciva */ 27161748Scperciva 28161748Scperciva#include <sys/param.h> 29161748Scperciva#include <sys/systm.h> 30161748Scperciva#include <sys/linker_set.h> 31161748Scperciva#include <sys/conf.h> 32161748Scperciva#include <sys/kernel.h> 33161748Scperciva#include <sys/lock.h> 34161748Scperciva#include <sys/proc.h> 35161748Scperciva#include <sys/mutex.h> 36161748Scperciva#include <sys/mman.h> 37161748Scperciva#include <sys/sysctl.h> 38161748Scperciva 39161748Scperciva#include <vm/vm.h> 40161748Scperciva#include <vm/vm_object.h> 41161748Scperciva#include <vm/vm_page.h> 42161748Scperciva#include <vm/vm_pager.h> 43161748Scperciva 44161748Scperciva/* prevent concurrant creation races */ 45161748Scpercivastatic int phys_pager_alloc_lock; 46161748Scperciva/* list of device pager objects */ 47161748Scpercivastatic struct pagerlst phys_pager_object_list; 48161748Scperciva/* protect access to phys_pager_object_list */ 49161748Scpercivastatic struct mtx phys_pager_mtx; 50161748Scperciva 51161748Scpercivastatic void 52161748Scpercivaphys_pager_init(void) 53161748Scperciva{ 54161748Scperciva 55161748Scperciva TAILQ_INIT(&phys_pager_object_list); 56161748Scperciva mtx_init(&phys_pager_mtx, "phys_pager list", NULL, MTX_DEF); 57161748Scperciva} 58161748Scperciva 59161748Scperciva/* 60161748Scperciva * MPSAFE 61161748Scperciva */ 62161748Scpercivastatic vm_object_t 63161748Scpercivaphys_pager_alloc(void *handle, vm_ooffset_t size, vm_prot_t prot, 64161748Scperciva vm_ooffset_t foff) 65161748Scperciva{ 66161748Scperciva vm_object_t object; 67161748Scperciva 68161748Scperciva /* 69161748Scperciva * Offset should be page aligned. 70161748Scperciva */ 71161748Scperciva if (foff & PAGE_MASK) 72161748Scperciva return (NULL); 73161748Scperciva 74161748Scperciva size = round_page(size); 75161748Scperciva 76161748Scperciva if (handle != NULL) { 77161748Scperciva mtx_lock(&Giant); 78161748Scperciva /* 79161748Scperciva * Lock to prevent object creation race condition. 80161748Scperciva */ 81161748Scperciva while (phys_pager_alloc_lock) { 82161748Scperciva phys_pager_alloc_lock = -1; 83161748Scperciva tsleep(&phys_pager_alloc_lock, PVM, "swpalc", 0); 84161748Scperciva } 85161748Scperciva phys_pager_alloc_lock = 1; 86161748Scperciva 87161748Scperciva /* 88161748Scperciva * Look up pager, creating as necessary. 89161748Scperciva */ 90161748Scperciva object = vm_pager_object_lookup(&phys_pager_object_list, handle); 91161748Scperciva if (object == NULL) { 92161748Scperciva /* 93161748Scperciva * Allocate object and associate it with the pager. 94161748Scperciva */ 95161748Scperciva object = vm_object_allocate(OBJT_PHYS, 96161748Scperciva OFF_TO_IDX(foff + size)); 97161748Scperciva object->handle = handle; 98161748Scperciva mtx_lock(&phys_pager_mtx); 99161748Scperciva TAILQ_INSERT_TAIL(&phys_pager_object_list, object, 100161748Scperciva pager_object_list); 101161748Scperciva mtx_unlock(&phys_pager_mtx); 102161748Scperciva } else { 103161748Scperciva /* 104161748Scperciva * Gain a reference to the object. 105161748Scperciva */ 106161748Scperciva vm_object_reference(object); 107161748Scperciva if (OFF_TO_IDX(foff + size) > object->size) 108161748Scperciva object->size = OFF_TO_IDX(foff + size); 109161748Scperciva } 110161748Scperciva if (phys_pager_alloc_lock == -1) 111161748Scperciva wakeup(&phys_pager_alloc_lock); 112161748Scperciva phys_pager_alloc_lock = 0; 113161748Scperciva mtx_unlock(&Giant); 114161748Scperciva } else { 115161748Scperciva object = vm_object_allocate(OBJT_PHYS, 116161748Scperciva OFF_TO_IDX(foff + size)); 117161748Scperciva } 118161748Scperciva 119161748Scperciva return (object); 120161748Scperciva} 121161748Scperciva 122161748Scperciva/* 123161748Scperciva * MPSAFE 124161748Scperciva */ 125161748Scpercivastatic void 126161748Scpercivaphys_pager_dealloc(vm_object_t object) 127161748Scperciva{ 128161748Scperciva 129161748Scperciva if (object->handle != NULL) { 130161748Scperciva mtx_lock(&phys_pager_mtx); 131161748Scperciva TAILQ_REMOVE(&phys_pager_object_list, object, pager_object_list); 132161748Scperciva mtx_unlock(&phys_pager_mtx); 133161748Scperciva } 134161748Scperciva} 135161748Scperciva 136161748Scpercivastatic int 137161748Scpercivaphys_pager_getpages(vm_object_t object, vm_page_t *m, int count, int reqpage) 138161748Scperciva{ 139161748Scperciva int i, s; 140161748Scperciva 141161748Scperciva s = splvm(); 142161748Scperciva /* 143161748Scperciva * Fill as many pages as vm_fault has allocated for us. 144161748Scperciva */ 145161748Scperciva for (i = 0; i < count; i++) { 146161748Scperciva if ((m[i]->flags & PG_ZERO) == 0) 147161748Scperciva vm_page_zero_fill(m[i]); 148161748Scperciva vm_page_flag_set(m[i], PG_ZERO); 149161748Scperciva /* Switch off pv_entries */ 150161748Scperciva vm_page_unmanage(m[i]); 151161748Scperciva m[i]->valid = VM_PAGE_BITS_ALL; 152161748Scperciva m[i]->dirty = 0; 153161748Scperciva /* The requested page must remain busy, the others not. */ 154161748Scperciva if (reqpage != i) { 155161748Scperciva vm_page_flag_clear(m[i], PG_BUSY); 156161748Scperciva m[i]->busy = 0; 157161748Scperciva } 158161748Scperciva } 159161748Scperciva splx(s); 160161748Scperciva 161161748Scperciva return (VM_PAGER_OK); 162161748Scperciva} 163161748Scperciva 164161748Scpercivastatic void 165161748Scpercivaphys_pager_putpages(vm_object_t object, vm_page_t *m, int count, boolean_t sync, 166161748Scperciva int *rtvals) 167161748Scperciva{ 168161748Scperciva 169161748Scperciva panic("phys_pager_putpage called"); 170161748Scperciva} 171161748Scperciva 172161748Scperciva/* 173161748Scperciva * Implement a pretty aggressive clustered getpages strategy. Hint that 174161748Scperciva * everything in an entire 4MB window should be prefaulted at once. 175161748Scperciva * 176161748Scperciva * XXX 4MB (1024 slots per page table page) is convenient for x86, 177161748Scperciva * but may not be for other arches. 178161748Scperciva */ 179161748Scperciva#ifndef PHYSCLUSTER 180161748Scperciva#define PHYSCLUSTER 1024 181161748Scperciva#endif 182161748Scpercivastatic boolean_t 183161748Scpercivaphys_pager_haspage(vm_object_t object, vm_pindex_t pindex, int *before, 184161748Scperciva int *after) 185161748Scperciva{ 186161748Scperciva vm_pindex_t base, end; 187161748Scperciva 188161748Scperciva base = pindex & (~(PHYSCLUSTER - 1)); 189161748Scperciva end = base + (PHYSCLUSTER - 1); 190161748Scperciva if (before != NULL) 191161748Scperciva *before = pindex - base; 192161748Scperciva if (after != NULL) 193161748Scperciva *after = end - pindex; 194161748Scperciva return (TRUE); 195161748Scperciva} 196161748Scperciva 197161748Scpercivastruct pagerops physpagerops = { 198161748Scperciva phys_pager_init, 199161748Scperciva phys_pager_alloc, 200161748Scperciva phys_pager_dealloc, 201161748Scperciva phys_pager_getpages, 202161748Scperciva phys_pager_putpages, 203161748Scperciva phys_pager_haspage, 204161748Scperciva NULL 205161748Scperciva}; 206161748Scperciva