summaryrefslogtreecommitdiffstats
path: root/sys/vm
diff options
context:
space:
mode:
authordyson <dyson@FreeBSD.org>1996-11-05 04:19:08 +0000
committerdyson <dyson@FreeBSD.org>1996-11-05 04:19:08 +0000
commitf459fb44431db913ac99b2f44562b3eb5c29ec72 (patch)
tree6d66a30ad0327d321201874816f8f5392e0b9f0c /sys/vm
parent216fc55e6b7e92bd53156df727cfc4efa4b70c55 (diff)
downloadFreeBSD-src-f459fb44431db913ac99b2f44562b3eb5c29ec72.zip
FreeBSD-src-f459fb44431db913ac99b2f44562b3eb5c29ec72.tar.gz
Vastly improved contigmalloc routine. It does not solve the
problem of allocating contiguous buffer memory in general, but make it much more likely to work at boot-up time. The best chance for an LKM-type load of a sound driver is immediately after the mount of the root filesystem. This appears to work for a 64K allocation on an 8MB system.
Diffstat (limited to 'sys/vm')
-rw-r--r--sys/vm/vm_page.c216
1 files changed, 153 insertions, 63 deletions
diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c
index ebf49e4..ea5c4ea 100644
--- a/sys/vm/vm_page.c
+++ b/sys/vm/vm_page.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)vm_page.c 7.4 (Berkeley) 5/7/91
- * $Id: vm_page.c,v 1.68 1996/10/12 20:09:48 bde Exp $
+ * $Id: vm_page.c,v 1.69 1996/10/15 03:16:45 dyson Exp $
*/
/*
@@ -143,7 +143,7 @@ vm_page_queue_init(void) {
}
vm_page_t vm_page_array;
-static int vm_page_array_size;
+int vm_page_array_size;
long first_page;
static long last_page;
static vm_size_t page_mask;
@@ -1262,6 +1262,7 @@ contigmalloc(size, type, flags, low, high, alignment, boundary)
{
int i, s, start;
vm_offset_t addr, phys, tmp_addr;
+ int pass;
vm_page_t pga = vm_page_array;
size = round_page(size);
@@ -1273,75 +1274,164 @@ contigmalloc(size, type, flags, low, high, alignment, boundary)
panic("vm_page_alloc_contig: boundary must be a power of 2");
start = 0;
- s = splvm();
+ for (pass = 0; pass <= 1; pass++) {
+ s = splvm();
again:
- /*
- * Find first page in array that is free, within range, aligned, and
- * such that the boundary won't be crossed.
- */
- for (i = start; i < cnt.v_page_count; i++) {
- phys = VM_PAGE_TO_PHYS(&pga[i]);
- if (((pga[i].queue - pga[i].pc) == PQ_FREE) &&
- (phys >= low) && (phys < high) &&
- ((phys & (alignment - 1)) == 0) &&
- (((phys ^ (phys + size - 1)) & ~(boundary - 1)) == 0))
- break;
- }
+ /*
+ * Find first page in array that is free, within range, aligned, and
+ * such that the boundary won't be crossed.
+ */
+ for (i = start; i < cnt.v_page_count; i++) {
+ int pqtype;
+ phys = VM_PAGE_TO_PHYS(&pga[i]);
+ pqtype = pga[i].queue - pga[i].pc;
+ if (((pqtype == PQ_ZERO) || (pqtype == PQ_FREE) || (pqtype == PQ_CACHE)) &&
+ (phys >= low) && (phys < high) &&
+ ((phys & (alignment - 1)) == 0) &&
+ (((phys ^ (phys + size - 1)) & ~(boundary - 1)) == 0))
+ break;
+ }
- /*
- * If the above failed or we will exceed the upper bound, fail.
- */
- if ((i == cnt.v_page_count) ||
- ((VM_PAGE_TO_PHYS(&pga[i]) + size) > high)) {
- splx(s);
- return (NULL);
- }
- start = i;
+ /*
+ * If the above failed or we will exceed the upper bound, fail.
+ */
+ if ((i == cnt.v_page_count) ||
+ ((VM_PAGE_TO_PHYS(&pga[i]) + size) > high)) {
+ vm_page_t m, next;
- /*
- * Check successive pages for contiguous and free.
- */
- for (i = start + 1; i < (start + size / PAGE_SIZE); i++) {
- if ((VM_PAGE_TO_PHYS(&pga[i]) !=
- (VM_PAGE_TO_PHYS(&pga[i - 1]) + PAGE_SIZE)) ||
- ((pga[i].queue - pga[i].pc) != PQ_FREE)) {
- start++;
- goto again;
+again1:
+ for (m = TAILQ_FIRST(&vm_page_queue_inactive);
+ m != NULL;
+ m = next) {
+
+ if (m->queue != PQ_INACTIVE) {
+ break;
+ }
+
+ next = TAILQ_NEXT(m, pageq);
+ if (m->flags & PG_BUSY) {
+ m->flags |= PG_WANTED;
+ tsleep(m, PVM, "vpctw0", 0);
+ goto again1;
+ }
+ vm_page_test_dirty(m);
+ if (m->dirty) {
+ if (m->object->type == OBJT_VNODE) {
+ vm_object_page_clean(m->object, 0, 0, TRUE, TRUE);
+ goto again1;
+ } else if (m->object->type == OBJT_SWAP ||
+ m->object->type == OBJT_DEFAULT) {
+ vm_page_protect(m, VM_PROT_NONE);
+ vm_pageout_flush(&m, 1, 0);
+ goto again1;
+ }
+ }
+ if ((m->dirty == 0) &&
+ (m->busy == 0) &&
+ (m->hold_count == 0))
+ vm_page_cache(m);
+ }
+
+ for (m = TAILQ_FIRST(&vm_page_queue_active);
+ m != NULL;
+ m = next) {
+
+ if (m->queue != PQ_ACTIVE) {
+ break;
+ }
+
+ next = TAILQ_NEXT(m, pageq);
+ if (m->flags & PG_BUSY) {
+ m->flags |= PG_WANTED;
+ tsleep(m, PVM, "vpctw1", 0);
+ goto again1;
+ }
+ vm_page_test_dirty(m);
+ if (m->dirty) {
+ if (m->object->type == OBJT_VNODE) {
+ vm_object_page_clean(m->object, 0, 0, TRUE, TRUE);
+ goto again1;
+ } else if (m->object->type == OBJT_SWAP ||
+ m->object->type == OBJT_DEFAULT) {
+ vm_page_protect(m, VM_PROT_NONE);
+ vm_pageout_flush(&m, 1, 0);
+ goto again1;
+ }
+ }
+ if ((m->dirty == 0) &&
+ (m->busy == 0) &&
+ (m->hold_count == 0))
+ vm_page_cache(m);
+ }
+
+ splx(s);
+ continue;
+ }
+ start = i;
+
+ /*
+ * Check successive pages for contiguous and free.
+ */
+ for (i = start + 1; i < (start + size / PAGE_SIZE); i++) {
+ int pqtype;
+ pqtype = pga[i].queue - pga[i].pc;
+ if ((VM_PAGE_TO_PHYS(&pga[i]) !=
+ (VM_PAGE_TO_PHYS(&pga[i - 1]) + PAGE_SIZE)) ||
+ ((pqtype != PQ_ZERO) && (pqtype != PQ_FREE) && (pqtype != PQ_CACHE))) {
+ start++;
+ goto again;
+ }
}
- }
- /*
- * We've found a contiguous chunk that meets are requirements.
- * Allocate kernel VM, unfree and assign the physical pages to it and
- * return kernel VM pointer.
- */
- tmp_addr = addr = kmem_alloc_pageable(kernel_map, size);
- if (addr == 0) {
- splx(s);
- return (NULL);
- }
+ for (i = start; i < (start + size / PAGE_SIZE); i++) {
+ int pqtype;
+ vm_page_t m = &pga[i];
- for (i = start; i < (start + size / PAGE_SIZE); i++) {
- vm_page_t m = &pga[i];
+ pqtype = m->queue - m->pc;
+ if (pqtype == PQ_CACHE)
+ vm_page_free(m);
- TAILQ_REMOVE(vm_page_queues[m->queue].pl, m, pageq);
- --(*vm_page_queues[m->queue].lcnt);
- cnt.v_free_count--;
- m->valid = VM_PAGE_BITS_ALL;
- m->flags = 0;
- m->dirty = 0;
- m->wire_count = 0;
- m->busy = 0;
- m->queue = PQ_NONE;
- vm_page_insert(m, kernel_object,
- OFF_TO_IDX(tmp_addr - VM_MIN_KERNEL_ADDRESS));
- vm_page_wire(m);
- pmap_kenter(tmp_addr, VM_PAGE_TO_PHYS(m));
- tmp_addr += PAGE_SIZE;
- }
+ TAILQ_REMOVE(vm_page_queues[m->queue].pl, m, pageq);
+ --(*vm_page_queues[m->queue].lcnt);
+ cnt.v_free_count--;
+ m->valid = VM_PAGE_BITS_ALL;
+ m->flags = 0;
+ m->dirty = 0;
+ m->wire_count = 0;
+ m->busy = 0;
+ m->queue = PQ_NONE;
+ m->object = NULL;
+ vm_page_wire(m);
+ }
- splx(s);
- return ((void *)addr);
+ /*
+ * We've found a contiguous chunk that meets are requirements.
+ * Allocate kernel VM, unfree and assign the physical pages to it and
+ * return kernel VM pointer.
+ */
+ tmp_addr = addr = kmem_alloc_pageable(kernel_map, size);
+ if (addr == 0) {
+ /*
+ * XXX We almost never run out of kernel virtual
+ * space, so we don't make the allocated memory
+ * above available.
+ */
+ splx(s);
+ return (NULL);
+ }
+
+ for (i = start; i < (start + size / PAGE_SIZE); i++) {
+ vm_page_t m = &pga[i];
+ vm_page_insert(m, kernel_object,
+ OFF_TO_IDX(tmp_addr - VM_MIN_KERNEL_ADDRESS));
+ pmap_kenter(tmp_addr, VM_PAGE_TO_PHYS(m));
+ tmp_addr += PAGE_SIZE;
+ }
+
+ splx(s);
+ return ((void *)addr);
+ }
+ return NULL;
}
vm_offset_t
OpenPOWER on IntegriCloud