diff options
author | peter <peter@FreeBSD.org> | 2000-05-21 13:41:29 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 2000-05-21 13:41:29 +0000 |
commit | 807a5519028c413f1a6eb2a4a100af4170425554 (patch) | |
tree | 04ec85a52c81760d92cfd7592df079b556640168 /sys/vm/phys_pager.c | |
parent | 7ae48d4d372ec107a8d8d0e583c97f198a52389d (diff) | |
download | FreeBSD-src-807a5519028c413f1a6eb2a4a100af4170425554.zip FreeBSD-src-807a5519028c413f1a6eb2a4a100af4170425554.tar.gz |
Checkpoint of a new physical memory backed object type, that does not
have pv_entries. This is intended for very special circumstances,
eg: a certain database that has a 1GB shm segment mapped into 300
processes. That would consume 2GB of kvm just to hold the pv_entries
alone. This would not be used on systems unless the physical ram was
available, as it's not pageable.
This is a work-in-progress, but is a useful and functional checkpoint.
Matt has got some more fixes for it that will be committed soon.
Reviewed by: dillon
Diffstat (limited to 'sys/vm/phys_pager.c')
-rw-r--r-- | sys/vm/phys_pager.c | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/sys/vm/phys_pager.c b/sys/vm/phys_pager.c new file mode 100644 index 0000000..a48126c --- /dev/null +++ b/sys/vm/phys_pager.c @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2000 Peter Wemm + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/linker_set.h> +#include <sys/conf.h> +#include <sys/mman.h> +#include <sys/sysctl.h> + +#include <vm/vm.h> +#include <vm/vm_object.h> +#include <vm/vm_page.h> +#include <vm/vm_pager.h> +#include <vm/vm_zone.h> + +static void phys_pager_init __P((void)); +static vm_object_t phys_pager_alloc __P((void *, vm_ooffset_t, vm_prot_t, + vm_ooffset_t)); +static void phys_pager_dealloc __P((vm_object_t)); +static int phys_pager_getpages __P((vm_object_t, vm_page_t *, int, int)); +static void phys_pager_putpages __P((vm_object_t, vm_page_t *, int, + boolean_t, int *)); +static boolean_t phys_pager_haspage __P((vm_object_t, vm_pindex_t, int *, + int *)); + +/* list of device pager objects */ +static struct pagerlst phys_pager_object_list; + +static int phys_pager_alloc_lock, phys_pager_alloc_lock_want; + +struct pagerops physpagerops = { + phys_pager_init, + phys_pager_alloc, + phys_pager_dealloc, + phys_pager_getpages, + phys_pager_putpages, + phys_pager_haspage, + NULL +}; + +static void +phys_pager_init() +{ + TAILQ_INIT(&phys_pager_object_list); +} + +static vm_object_t +phys_pager_alloc(void *handle, vm_ooffset_t size, vm_prot_t prot, + vm_ooffset_t foff) +{ + vm_object_t object; + + /* + * Offset should be page aligned. + */ + if (foff & PAGE_MASK) + return (NULL); + + size = round_page(size); + + /* + * Lock to prevent object creation race condition. + */ + while (phys_pager_alloc_lock) { + phys_pager_alloc_lock_want++; + tsleep(&phys_pager_alloc_lock, PVM, "ppall", 0); + phys_pager_alloc_lock_want--; + } + phys_pager_alloc_lock = 1; + + /* + * Look up pager, creating as necessary. + */ + object = vm_pager_object_lookup(&phys_pager_object_list, handle); + if (object == NULL) { + /* + * Allocate object and associate it with the pager. + */ + object = vm_object_allocate(OBJT_PHYS, + OFF_TO_IDX(foff + size)); + object->handle = handle; + TAILQ_INIT(&object->un_pager.physp.physp_pglist); + TAILQ_INSERT_TAIL(&phys_pager_object_list, object, + pager_object_list); + } else { + /* + * Gain a reference to the object. + */ + vm_object_reference(object); + if (OFF_TO_IDX(foff + size) > object->size) + object->size = OFF_TO_IDX(foff + size); + } + + phys_pager_alloc_lock = 0; + if (phys_pager_alloc_lock_want) + wakeup(&phys_pager_alloc_lock); + + return (object); +} + +static void +phys_pager_dealloc(object) + vm_object_t object; +{ + vm_page_t m; + int s; + + TAILQ_REMOVE(&phys_pager_object_list, object, pager_object_list); + /* + * Free up our fake pages. + */ + s = splvm(); + while ((m = TAILQ_FIRST(&object->un_pager.physp.physp_pglist)) != 0) { + TAILQ_REMOVE(&object->un_pager.physp.physp_pglist, m, pageq); + /* return the page back to normal */ + m->flags &= ~PG_FICTITIOUS; + m->dirty = 0; + vm_page_unwire(m, 0); + vm_page_flag_clear(m, PG_ZERO); + vm_page_free(m); + } + splx(s); +} + +static int +phys_pager_getpages(object, m, count, reqpage) + vm_object_t object; + vm_page_t *m; + int count; + int reqpage; +{ + int i, s; + + s = splvm(); + /* + * Fill as many pages as vm_fault has allocated for us. + */ + for (i = 0; i < count; i++) { + if ((m[i]->flags & PG_ZERO) == 0) + vm_page_zero_fill(m[i]); + vm_page_flag_set(m[i], PG_ZERO); + /* Switch off pv_entries */ + vm_page_wire(m[i]); + vm_page_flag_set(m[i], PG_FICTITIOUS); + m[i]->valid = VM_PAGE_BITS_ALL; + m[i]->dirty = 0; + /* The requested page must remain busy, the others not. */ + if (reqpage != i) { + vm_page_flag_clear(m[i], PG_BUSY); + m[i]->busy = 0; + } + TAILQ_INSERT_TAIL(&object->un_pager.physp.physp_pglist, m[i], + pageq); + } + splx(s); + + return (VM_PAGER_OK); +} + +static void +phys_pager_putpages(object, m, count, sync, rtvals) + vm_object_t object; + vm_page_t *m; + int count; + boolean_t sync; + int *rtvals; +{ + panic("phys_pager_putpage called"); +} + +/* + * Implement a pretty aggressive clustered getpages strategy. Hint that + * everything in an entire 4MB window should be prefaulted at once. + * + * XXX 4MB (1024 slots per page table page) is convenient for x86, + * but may not be for other arches. + */ +#ifndef PHYSCLUSTER +#define PHYSCLUSTER 1024 +#endif +static boolean_t +phys_pager_haspage(object, pindex, before, after) + vm_object_t object; + vm_pindex_t pindex; + int *before; + int *after; +{ + vm_pindex_t base, end; + + base = pindex & (~(PHYSCLUSTER - 1)); + end = base + (PHYSCLUSTER - 1); + if (before != NULL) + *before = pindex - base; + if (after != NULL) + *after = end - pindex; + return (TRUE); +} |