summaryrefslogtreecommitdiffstats
path: root/sys/vm
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2014-07-24 16:29:44 +0000
committerkib <kib@FreeBSD.org>2014-07-24 16:29:44 +0000
commitd7d6313cf44fa12148b5cee3cb0542287af7a37f (patch)
tree671bf425a15fe4f80c0c080b0d8ce7545ed6f149 /sys/vm
parentbc8d80ff4e8a4a3106923968524f11648f134483 (diff)
downloadFreeBSD-src-d7d6313cf44fa12148b5cee3cb0542287af7a37f.zip
FreeBSD-src-d7d6313cf44fa12148b5cee3cb0542287af7a37f.tar.gz
MFC r267213 (by alc):
Add a page size field to struct vm_page. Approved by: alc
Diffstat (limited to 'sys/vm')
-rw-r--r--sys/vm/vm_map.c39
-rw-r--r--sys/vm/vm_page.c25
-rw-r--r--sys/vm/vm_page.h2
-rw-r--r--sys/vm/vm_reserv.c10
4 files changed, 62 insertions, 14 deletions
diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c
index 0713af8..891b68c 100644
--- a/sys/vm/vm_map.c
+++ b/sys/vm/vm_map.c
@@ -1802,20 +1802,22 @@ vm_map_submap(
}
/*
- * The maximum number of pages to map
+ * The maximum number of pages to map if MAP_PREFAULT_PARTIAL is specified
*/
#define MAX_INIT_PT 96
/*
* vm_map_pmap_enter:
*
- * Preload read-only mappings for the specified object's resident pages
- * into the target map. If "flags" is MAP_PREFAULT_PARTIAL, then only
- * the resident pages within the address range [addr, addr + ulmin(size,
- * ptoa(MAX_INIT_PT))) are mapped. Otherwise, all resident pages within
- * the specified address range are mapped. This eliminates many soft
- * faults on process startup and immediately after an mmap(2). Because
- * these are speculative mappings, cached pages are not reactivated and
+ * Preload the specified map's pmap with mappings to the specified
+ * object's memory-resident pages. No further physical pages are
+ * allocated, and no further virtual pages are retrieved from secondary
+ * storage. If the specified flags include MAP_PREFAULT_PARTIAL, then a
+ * limited number of page mappings are created at the low-end of the
+ * specified address range. (For this purpose, a superpage mapping
+ * counts as one page mapping.) Otherwise, all resident pages within
+ * the specified address range are mapped. Because these mappings are
+ * being created speculatively, cached pages are not reactivated and
* mapped.
*/
void
@@ -1824,7 +1826,7 @@ vm_map_pmap_enter(vm_map_t map, vm_offset_t addr, vm_prot_t prot,
{
vm_offset_t start;
vm_page_t p, p_start;
- vm_pindex_t psize, tmpidx;
+ vm_pindex_t mask, psize, threshold, tmpidx;
if ((prot & (VM_PROT_READ | VM_PROT_EXECUTE)) == 0 || object == NULL)
return;
@@ -1842,8 +1844,6 @@ vm_map_pmap_enter(vm_map_t map, vm_offset_t addr, vm_prot_t prot,
}
psize = atop(size);
- if (psize > MAX_INIT_PT && (flags & MAP_PREFAULT_PARTIAL) != 0)
- psize = MAX_INIT_PT;
if (psize + pindex > object->size) {
if (object->size < pindex) {
VM_OBJECT_RUNLOCK(object);
@@ -1854,6 +1854,7 @@ vm_map_pmap_enter(vm_map_t map, vm_offset_t addr, vm_prot_t prot,
start = 0;
p_start = NULL;
+ threshold = MAX_INIT_PT;
p = vm_page_find_least(object, pindex);
/*
@@ -1868,8 +1869,10 @@ vm_map_pmap_enter(vm_map_t map, vm_offset_t addr, vm_prot_t prot,
* don't allow an madvise to blow away our really
* free pages allocating pv entries.
*/
- if ((flags & MAP_PREFAULT_MADVISE) &&
- cnt.v_free_count < cnt.v_free_reserved) {
+ if (((flags & MAP_PREFAULT_MADVISE) != 0 &&
+ cnt.v_free_count < cnt.v_free_reserved) ||
+ ((flags & MAP_PREFAULT_PARTIAL) != 0 &&
+ tmpidx >= threshold)) {
psize = tmpidx;
break;
}
@@ -1878,6 +1881,16 @@ vm_map_pmap_enter(vm_map_t map, vm_offset_t addr, vm_prot_t prot,
start = addr + ptoa(tmpidx);
p_start = p;
}
+ /* Jump ahead if a superpage mapping is possible. */
+ if (p->psind > 0 && ((addr + ptoa(tmpidx)) &
+ (pagesizes[p->psind] - 1)) == 0) {
+ mask = atop(pagesizes[p->psind]) - 1;
+ if (tmpidx + mask < psize &&
+ vm_page_ps_is_valid(p)) {
+ p += mask;
+ threshold += mask;
+ }
+ }
} else if (p_start != NULL) {
pmap_enter_object(map->pmap, start, addr +
ptoa(tmpidx), p_start, prot);
diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c
index 0242fe5..3f80238 100644
--- a/sys/vm/vm_page.c
+++ b/sys/vm/vm_page.c
@@ -3058,6 +3058,31 @@ vm_page_is_valid(vm_page_t m, int base, int size)
}
/*
+ * vm_page_ps_is_valid:
+ *
+ * Returns TRUE if the entire (super)page is valid and FALSE otherwise.
+ */
+boolean_t
+vm_page_ps_is_valid(vm_page_t m)
+{
+ int i, npages;
+
+ VM_OBJECT_ASSERT_LOCKED(m->object);
+ npages = atop(pagesizes[m->psind]);
+
+ /*
+ * The physically contiguous pages that make up a superpage, i.e., a
+ * page with a page size index ("psind") greater than zero, will
+ * occupy adjacent entries in vm_page_array[].
+ */
+ for (i = 0; i < npages; i++) {
+ if (m[i].valid != VM_PAGE_BITS_ALL)
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+/*
* Set the page's dirty bits if the page is modified.
*/
void
diff --git a/sys/vm/vm_page.h b/sys/vm/vm_page.h
index 7846702..f0dc5e8 100644
--- a/sys/vm/vm_page.h
+++ b/sys/vm/vm_page.h
@@ -157,6 +157,7 @@ struct vm_page {
/* so, on normal X86 kernels, they must be at least 8 bits wide */
vm_page_bits_t valid; /* map of valid DEV_BSIZE chunks (O) */
vm_page_bits_t dirty; /* map of dirty DEV_BSIZE chunks (M) */
+ int8_t psind; /* pagesizes[] index (O) */
};
/*
@@ -450,6 +451,7 @@ vm_page_t vm_page_next(vm_page_t m);
int vm_page_pa_tryrelock(pmap_t, vm_paddr_t, vm_paddr_t *);
struct vm_pagequeue *vm_page_pagequeue(vm_page_t m);
vm_page_t vm_page_prev(vm_page_t m);
+boolean_t vm_page_ps_is_valid(vm_page_t m);
void vm_page_putfake(vm_page_t m);
void vm_page_readahead_finish(vm_page_t m);
void vm_page_reference(vm_page_t m);
diff --git a/sys/vm/vm_reserv.c b/sys/vm/vm_reserv.c
index 6ca5642..7511a33 100644
--- a/sys/vm/vm_reserv.c
+++ b/sys/vm/vm_reserv.c
@@ -229,6 +229,11 @@ vm_reserv_depopulate(vm_reserv_t rv)
if (rv->inpartpopq) {
TAILQ_REMOVE(&vm_rvq_partpop, rv, partpopq);
rv->inpartpopq = FALSE;
+ } else {
+ KASSERT(rv->pages->psind == 1,
+ ("vm_reserv_depopulate: reserv %p is already demoted",
+ rv));
+ rv->pages->psind = 0;
}
rv->popcnt--;
if (rv->popcnt == 0) {
@@ -278,6 +283,8 @@ vm_reserv_populate(vm_reserv_t rv)
("vm_reserv_populate: reserv %p is free", rv));
KASSERT(rv->popcnt < VM_LEVEL_0_NPAGES,
("vm_reserv_populate: reserv %p is already full", rv));
+ KASSERT(rv->pages->psind == 0,
+ ("vm_reserv_populate: reserv %p is already promoted", rv));
if (rv->inpartpopq) {
TAILQ_REMOVE(&vm_rvq_partpop, rv, partpopq);
rv->inpartpopq = FALSE;
@@ -286,7 +293,8 @@ vm_reserv_populate(vm_reserv_t rv)
if (rv->popcnt < VM_LEVEL_0_NPAGES) {
rv->inpartpopq = TRUE;
TAILQ_INSERT_TAIL(&vm_rvq_partpop, rv, partpopq);
- }
+ } else
+ rv->pages->psind = 1;
}
/*
OpenPOWER on IntegriCloud