summaryrefslogtreecommitdiff
path: root/sys/vm/vm_fault.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/vm/vm_fault.c')
-rw-r--r--sys/vm/vm_fault.c796
1 files changed, 358 insertions, 438 deletions
diff --git a/sys/vm/vm_fault.c b/sys/vm/vm_fault.c
index 31a69c2a47d3..b8a404bf0518 100644
--- a/sys/vm/vm_fault.c
+++ b/sys/vm/vm_fault.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 1994 John S. Dyson
@@ -45,17 +45,17 @@
* All rights reserved.
*
* Authors: Avadis Tevanian, Jr., Michael Wayne Young
- *
+ *
* Permission to use, copy, modify and distribute this software and
* its documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
- *
- * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
- * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
+ *
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
@@ -66,7 +66,7 @@
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*
- * $Id: vm_fault.c,v 1.12 1994/11/06 09:55:29 davidg Exp $
+ * $Id: vm_fault.c,v 1.13 1994/11/13 22:48:53 davidg Exp $
*/
/*
@@ -85,7 +85,7 @@
#include <vm/vm_pageout.h>
#include <vm/vm_kern.h>
-int vm_fault_additional_pages __P((vm_object_t, vm_offset_t, vm_page_t, int, int, vm_page_t *, int *));
+int vm_fault_additional_pages __P((vm_object_t, vm_offset_t, vm_page_t, int, int, vm_page_t *, int *));
#define VM_FAULT_READ_AHEAD 4
#define VM_FAULT_READ_AHEAD_MIN 1
@@ -114,31 +114,31 @@ extern int vm_pageout_proc_limit;
*/
int
vm_fault(map, vaddr, fault_type, change_wiring)
- vm_map_t map;
- vm_offset_t vaddr;
- vm_prot_t fault_type;
- boolean_t change_wiring;
+ vm_map_t map;
+ vm_offset_t vaddr;
+ vm_prot_t fault_type;
+ boolean_t change_wiring;
{
- vm_object_t first_object;
- vm_offset_t first_offset;
- vm_map_entry_t entry;
- register vm_object_t object;
- register vm_offset_t offset;
- vm_page_t m;
- vm_page_t first_m;
- vm_prot_t prot;
- int result;
- boolean_t wired;
- boolean_t su;
- boolean_t lookup_still_valid;
- boolean_t page_exists;
- vm_page_t old_m;
- vm_object_t next_object;
- vm_page_t marray[VM_FAULT_READ];
- int spl;
- int hardfault=0;
-
- cnt.v_vm_faults++; /* needs lock XXX */
+ vm_object_t first_object;
+ vm_offset_t first_offset;
+ vm_map_entry_t entry;
+ register vm_object_t object;
+ register vm_offset_t offset;
+ vm_page_t m;
+ vm_page_t first_m;
+ vm_prot_t prot;
+ int result;
+ boolean_t wired;
+ boolean_t su;
+ boolean_t lookup_still_valid;
+ boolean_t page_exists;
+ vm_page_t old_m;
+ vm_object_t next_object;
+ vm_page_t marray[VM_FAULT_READ];
+ int spl;
+ int hardfault = 0;
+
+ cnt.v_vm_faults++; /* needs lock XXX */
/*
* Recovery actions
*/
@@ -185,17 +185,16 @@ vm_fault(map, vaddr, fault_type, change_wiring)
}
- RetryFault: ;
+RetryFault:;
/*
- * Find the backing store object and offset into
- * it to begin the search.
+ * Find the backing store object and offset into it to begin the
+ * search.
*/
- if ((result = vm_map_lookup(&map, vaddr, fault_type, &entry,
- &first_object, &first_offset,
- &prot, &wired, &su)) != KERN_SUCCESS) {
- return(result);
+ if ((result = vm_map_lookup(&map, vaddr, fault_type, &entry, &first_object,
+ &first_offset, &prot, &wired, &su)) != KERN_SUCCESS) {
+ return (result);
}
lookup_still_valid = TRUE;
@@ -204,12 +203,11 @@ vm_fault(map, vaddr, fault_type, change_wiring)
first_m = NULL;
- /*
- * Make a reference to this object to
- * prevent its disposal while we are messing with
- * it. Once we have the reference, the map is free
- * to be diddled. Since objects reference their
- * shadows (and copies), they will stay around as well.
+ /*
+ * Make a reference to this object to prevent its disposal while we
+ * are messing with it. Once we have the reference, the map is free
+ * to be diddled. Since objects reference their shadows (and copies),
+ * they will stay around as well.
*/
vm_object_lock(first_object);
@@ -218,132 +216,111 @@ vm_fault(map, vaddr, fault_type, change_wiring)
first_object->paging_in_progress++;
/*
- * INVARIANTS (through entire routine):
- *
- * 1) At all times, we must either have the object
- * lock or a busy page in some object to prevent
- * some other thread from trying to bring in
- * the same page.
- *
- * Note that we cannot hold any locks during the
- * pager access or when waiting for memory, so
- * we use a busy page then.
- *
- * Note also that we aren't as concerned about
- * more than one thead attempting to pager_data_unlock
- * the same page at once, so we don't hold the page
- * as busy then, but do record the highest unlock
- * value so far. [Unlock requests may also be delivered
- * out of order.]
- *
- * 2) Once we have a busy page, we must remove it from
- * the pageout queues, so that the pageout daemon
- * will not grab it away.
- *
- * 3) To prevent another thread from racing us down the
- * shadow chain and entering a new page in the top
- * object before we do, we must keep a busy page in
- * the top object while following the shadow chain.
- *
- * 4) We must increment paging_in_progress on any object
- * for which we have a busy page, to prevent
- * vm_object_collapse from removing the busy page
- * without our noticing.
+ * INVARIANTS (through entire routine):
+ *
+ * 1) At all times, we must either have the object lock or a busy
+ * page in some object to prevent some other thread from trying to
+ * bring in the same page.
+ *
+ * Note that we cannot hold any locks during the pager access or when
+ * waiting for memory, so we use a busy page then.
+ *
+ * Note also that we aren't as concerned about more than one thead
+ * attempting to pager_data_unlock the same page at once, so we don't
+ * hold the page as busy then, but do record the highest unlock value
+ * so far. [Unlock requests may also be delivered out of order.]
+ *
+ * 2) Once we have a busy page, we must remove it from the pageout
+ * queues, so that the pageout daemon will not grab it away.
+ *
+ * 3) To prevent another thread from racing us down the shadow chain
+ * and entering a new page in the top object before we do, we must
+ * keep a busy page in the top object while following the shadow
+ * chain.
+ *
+ * 4) We must increment paging_in_progress on any object for which
+ * we have a busy page, to prevent vm_object_collapse from removing
+ * the busy page without our noticing.
*/
/*
- * Search for the page at object/offset.
+ * Search for the page at object/offset.
*/
object = first_object;
offset = first_offset;
/*
- * See whether this page is resident
+ * See whether this page is resident
*/
while (TRUE) {
m = vm_page_lookup(object, offset);
if (m != NULL) {
/*
- * If the page is being brought in,
- * wait for it and then retry.
+ * If the page is being brought in, wait for it and
+ * then retry.
*/
- if (m->flags & (PG_BUSY|PG_VMIO)) {
+ if ((m->flags & PG_BUSY) || m->busy) {
int s;
+
UNLOCK_THINGS;
s = splhigh();
- if (m->flags & (PG_BUSY|PG_VMIO)) {
- m->flags |= PG_WANTED;
+ if ((m->flags & PG_BUSY) || m->busy) {
+ m->flags |= PG_WANTED | PG_REFERENCED;
cnt.v_intrans++;
- tsleep((caddr_t)m,PSWP,"vmpfw",0);
+ tsleep((caddr_t) m, PSWP, "vmpfw", 0);
}
splx(s);
vm_object_deallocate(first_object);
goto RetryFault;
}
-
+ if ((m->flags & PG_CACHE) &&
+ (cnt.v_free_count + cnt.v_cache_count) < cnt.v_free_reserved) {
+ UNLOCK_AND_DEALLOCATE;
+ VM_WAIT;
+ goto RetryFault;
+ }
/*
- * Remove the page from the pageout daemon's
- * reach while we play with it.
+ * Remove the page from the pageout daemon's reach
+ * while we play with it.
*/
vm_page_lock_queues();
- spl = splhigh();
- if (m->flags & PG_INACTIVE) {
- TAILQ_REMOVE(&vm_page_queue_inactive, m, pageq);
- m->flags &= ~PG_INACTIVE;
- cnt.v_inactive_count--;
- cnt.v_reactivated++;
- }
-
- if (m->flags & PG_ACTIVE) {
- TAILQ_REMOVE(&vm_page_queue_active, m, pageq);
- m->flags &= ~PG_ACTIVE;
- cnt.v_active_count--;
- }
- splx(spl);
+ vm_page_unqueue(m);
vm_page_unlock_queues();
/*
- * Mark page busy for other threads.
+ * Mark page busy for other threads.
*/
m->flags |= PG_BUSY;
+ if (m->object != kernel_object && m->object != kmem_object &&
+ m->valid &&
+ ((m->valid & vm_page_bits(0, PAGE_SIZE))
+ != vm_page_bits(0, PAGE_SIZE))) {
+ goto readrest;
+ }
break;
}
-
- if (((object->pager != NULL) &&
- (!change_wiring || wired))
+ if (((object->pager != NULL) && (!change_wiring || wired))
|| (object == first_object)) {
-#if 0
- if (curproc && (vaddr < VM_MAXUSER_ADDRESS) &&
- (curproc->p_rlimit[RLIMIT_RSS].rlim_max <
- curproc->p_vmspace->vm_pmap.pm_stats.resident_count * NBPG)) {
- UNLOCK_AND_DEALLOCATE;
- vm_fault_free_pages(curproc);
- goto RetryFault;
- }
-#endif
-
- if (swap_pager_full && !object->shadow && (!object->pager ||
+ if (swap_pager_full && !object->shadow && (!object->pager ||
(object->pager && object->pager->pg_type == PG_SWAP &&
- !vm_pager_has_page(object->pager, offset+object->paging_offset)))) {
- if (vaddr < VM_MAXUSER_ADDRESS && curproc && curproc->p_pid >= 48) /* XXX */ {
- printf("Process %lu killed by vm_fault -- out of swap\n", (u_long)curproc->p_pid);
+ !vm_pager_has_page(object->pager, offset + object->paging_offset)))) {
+ if (vaddr < VM_MAXUSER_ADDRESS && curproc && curproc->p_pid >= 48) { /* XXX */
+ printf("Process %lu killed by vm_fault -- out of swap\n", (u_long) curproc->p_pid);
psignal(curproc, SIGKILL);
curproc->p_estcpu = 0;
curproc->p_nice = PRIO_MIN;
resetpriority(curproc);
}
}
-
/*
- * Allocate a new page for this object/offset
- * pair.
+ * Allocate a new page for this object/offset pair.
*/
- m = vm_page_alloc(object, offset);
+ m = vm_page_alloc(object, offset, 0);
if (m == NULL) {
UNLOCK_AND_DEALLOCATE;
@@ -351,88 +328,90 @@ vm_fault(map, vaddr, fault_type, change_wiring)
goto RetryFault;
}
}
-
+readrest:
if (object->pager != NULL && (!change_wiring || wired)) {
int rv;
int faultcount;
int reqpage;
/*
- * Now that we have a busy page, we can
- * release the object lock.
+ * Now that we have a busy page, we can release the
+ * object lock.
*/
vm_object_unlock(object);
/*
- * now we find out if any other pages should
- * be paged in at this time
- * this routine checks to see if the pages surrounding this fault
- * reside in the same object as the page for this fault. If
- * they do, then they are faulted in also into the
- * object. The array "marray" returned contains an array of
- * vm_page_t structs where one of them is the vm_page_t passed to
- * the routine. The reqpage return value is the index into the
- * marray for the vm_page_t passed to the routine.
+ * now we find out if any other pages should be paged
+ * in at this time this routine checks to see if the
+ * pages surrounding this fault reside in the same
+ * object as the page for this fault. If they do,
+ * then they are faulted in also into the object. The
+ * array "marray" returned contains an array of
+ * vm_page_t structs where one of them is the
+ * vm_page_t passed to the routine. The reqpage
+ * return value is the index into the marray for the
+ * vm_page_t passed to the routine.
*/
faultcount = vm_fault_additional_pages(
- first_object, first_offset,
- m, VM_FAULT_READ_BEHIND, VM_FAULT_READ_AHEAD,
- marray, &reqpage);
+ first_object, first_offset,
+ m, VM_FAULT_READ_BEHIND, VM_FAULT_READ_AHEAD,
+ marray, &reqpage);
/*
- * Call the pager to retrieve the data, if any,
- * after releasing the lock on the map.
+ * Call the pager to retrieve the data, if any, after
+ * releasing the lock on the map.
*/
UNLOCK_MAP;
rv = faultcount ?
vm_pager_get_pages(object->pager,
- marray, faultcount, reqpage, TRUE): VM_PAGER_FAIL;
+ marray, faultcount, reqpage, TRUE) : VM_PAGER_FAIL;
if (rv == VM_PAGER_OK) {
/*
- * Found the page.
- * Leave it busy while we play with it.
+ * Found the page. Leave it busy while we play
+ * with it.
*/
vm_object_lock(object);
/*
- * Relookup in case pager changed page.
- * Pager is responsible for disposition
- * of old page if moved.
+ * Relookup in case pager changed page. Pager
+ * is responsible for disposition of old page
+ * if moved.
*/
m = vm_page_lookup(object, offset);
-
- m->flags &= ~PG_FAKE;
+ if (!m) {
+ printf("vm_fault: error fetching offset: %lx (fc: %d, rq: %d)\n",
+ offset, faultcount, reqpage);
+ }
+ m->valid = VM_PAGE_BITS_ALL;
pmap_clear_modify(VM_PAGE_TO_PHYS(m));
hardfault++;
break;
}
-
/*
- * Remove the bogus page (which does not
- * exist at this object/offset); before
- * doing so, we must get back our object
- * lock to preserve our invariant.
- *
- * Also wake up any other thread that may want
- * to bring in this page.
- *
- * If this is the top-level object, we must
- * leave the busy page to prevent another
- * thread from rushing past us, and inserting
- * the page in that object at the same time
- * that we are.
+ * Remove the bogus page (which does not exist at this
+ * object/offset); before doing so, we must get back
+ * our object lock to preserve our invariant.
+ *
+ * Also wake up any other thread that may want to bring
+ * in this page.
+ *
+ * If this is the top-level object, we must leave the
+ * busy page to prevent another thread from rushing
+ * past us, and inserting the page in that object at
+ * the same time that we are.
*/
if (rv == VM_PAGER_ERROR)
printf("vm_fault: pager input (probably hardware) error, PID %d failure\n",
- curproc->p_pid);
+ curproc->p_pid);
vm_object_lock(object);
/*
* Data outside the range of the pager or an I/O error
*/
/*
- * XXX - the check for kernel_map is a kludge to work around
- * having the machine panic on a kernel space fault w/ I/O error.
+ * XXX - the check for kernel_map is a kludge to work
+ * around having the machine panic on a kernel space
+ * fault w/ I/O error.
*/
if (((map != kernel_map) && (rv == VM_PAGER_ERROR)) || (rv == VM_PAGER_BAD)) {
FREE_PAGE(m);
@@ -447,25 +426,24 @@ vm_fault(map, vaddr, fault_type, change_wiring)
*/
}
}
-
/*
- * We get here if the object has no pager (or unwiring)
- * or the pager doesn't have the page.
+ * We get here if the object has no pager (or unwiring) or the
+ * pager doesn't have the page.
*/
if (object == first_object)
first_m = m;
/*
- * Move on to the next object. Lock the next
- * object before unlocking the current one.
+ * Move on to the next object. Lock the next object before
+ * unlocking the current one.
*/
offset += object->shadow_offset;
next_object = object->shadow;
if (next_object == NULL) {
/*
- * If there's no object left, fill the page
- * in the top object with zeros.
+ * If there's no object left, fill the page in the top
+ * object with zeros.
*/
if (object != first_object) {
object->paging_in_progress--;
@@ -481,11 +459,10 @@ vm_fault(map, vaddr, fault_type, change_wiring)
first_m = NULL;
vm_page_zero_fill(m);
+ m->valid = VM_PAGE_BITS_ALL;
cnt.v_zfod++;
- m->flags &= ~PG_FAKE;
break;
- }
- else {
+ } else {
vm_object_lock(next_object);
if (object != first_object) {
object->paging_in_progress--;
@@ -498,80 +475,73 @@ vm_fault(map, vaddr, fault_type, change_wiring)
}
}
- if ((m->flags & (PG_ACTIVE|PG_INACTIVE) != 0) ||
- (m->flags & PG_BUSY) == 0)
+ if ((m->flags & (PG_ACTIVE | PG_INACTIVE | PG_CACHE) != 0) ||
+ (m->flags & PG_BUSY) == 0)
panic("vm_fault: absent or active or inactive or not busy after main loop");
/*
- * PAGE HAS BEEN FOUND.
- * [Loop invariant still holds -- the object lock
- * is held.]
+ * PAGE HAS BEEN FOUND. [Loop invariant still holds -- the object lock
+ * is held.]
*/
old_m = m; /* save page that would be copied */
/*
- * If the page is being written, but isn't
- * already owned by the top-level object,
- * we have to copy it into a new page owned
- * by the top-level object.
+ * If the page is being written, but isn't already owned by the
+ * top-level object, we have to copy it into a new page owned by the
+ * top-level object.
*/
if (object != first_object) {
- /*
- * We only really need to copy if we
- * want to write it.
+ /*
+ * We only really need to copy if we want to write it.
*/
- if (fault_type & VM_PROT_WRITE) {
+ if (fault_type & VM_PROT_WRITE) {
/*
- * If we try to collapse first_object at this
- * point, we may deadlock when we try to get
- * the lock on an intermediate object (since we
- * have the bottom object locked). We can't
- * unlock the bottom object, because the page
- * we found may move (by collapse) if we do.
- *
- * Instead, we first copy the page. Then, when
- * we have no more use for the bottom object,
- * we unlock it and try to collapse.
- *
- * Note that we copy the page even if we didn't
- * need to... that's the breaks.
+ * If we try to collapse first_object at this point,
+ * we may deadlock when we try to get the lock on an
+ * intermediate object (since we have the bottom
+ * object locked). We can't unlock the bottom object,
+ * because the page we found may move (by collapse) if
+ * we do.
+ *
+ * Instead, we first copy the page. Then, when we have
+ * no more use for the bottom object, we unlock it and
+ * try to collapse.
+ *
+ * Note that we copy the page even if we didn't need
+ * to... that's the breaks.
*/
- /*
- * We already have an empty page in
- * first_object - use it.
+ /*
+ * We already have an empty page in first_object - use
+ * it.
*/
vm_page_copy(m, first_m);
- first_m->flags &= ~PG_FAKE;
+ first_m->valid = VM_PAGE_BITS_ALL;
/*
- * If another map is truly sharing this
- * page with us, we have to flush all
- * uses of the original page, since we
- * can't distinguish those which want the
- * original from those which need the
- * new copy.
- *
- * XXX If we know that only one map has
- * access to this page, then we could
- * avoid the pmap_page_protect() call.
+ * If another map is truly sharing this page with us,
+ * we have to flush all uses of the original page,
+ * since we can't distinguish those which want the
+ * original from those which need the new copy.
+ *
+ * XXX If we know that only one map has access to this
+ * page, then we could avoid the pmap_page_protect()
+ * call.
*/
vm_page_lock_queues();
vm_page_activate(m);
pmap_page_protect(VM_PAGE_TO_PHYS(m), VM_PROT_NONE);
- if ((m->flags & PG_CLEAN) == 0)
- m->flags |= PG_LAUNDRY;
vm_page_unlock_queues();
/*
- * We no longer need the old page or object.
+ * We no longer need the old page or object.
*/
PAGE_WAKEUP(m);
object->paging_in_progress--;
@@ -580,7 +550,7 @@ vm_fault(map, vaddr, fault_type, change_wiring)
vm_object_unlock(object);
/*
- * Only use the new page below...
+ * Only use the new page below...
*/
cnt.v_cow_faults++;
@@ -589,49 +559,46 @@ vm_fault(map, vaddr, fault_type, change_wiring)
offset = first_offset;
/*
- * Now that we've gotten the copy out of the
- * way, let's try to collapse the top object.
+ * Now that we've gotten the copy out of the way,
+ * let's try to collapse the top object.
*/
vm_object_lock(object);
/*
- * But we have to play ugly games with
- * paging_in_progress to do that...
+ * But we have to play ugly games with
+ * paging_in_progress to do that...
*/
object->paging_in_progress--;
if (object->paging_in_progress == 0)
wakeup((caddr_t) object);
vm_object_collapse(object);
object->paging_in_progress++;
- }
- else {
- prot &= ~VM_PROT_WRITE;
+ } else {
+ prot &= ~VM_PROT_WRITE;
m->flags |= PG_COPYONWRITE;
}
}
-
- if (m->flags & (PG_ACTIVE|PG_INACTIVE))
+ if (m->flags & (PG_ACTIVE | PG_INACTIVE | PG_CACHE))
panic("vm_fault: active or inactive before copy object handling");
/*
- * If the page is being written, but hasn't been
- * copied to the copy-object, we have to copy it there.
+ * If the page is being written, but hasn't been copied to the
+ * copy-object, we have to copy it there.
*/
- RetryCopy:
+RetryCopy:
if (first_object->copy != NULL) {
vm_object_t copy_object = first_object->copy;
vm_offset_t copy_offset;
vm_page_t copy_m;
/*
- * We only need to copy if we want to write it.
+ * We only need to copy if we want to write it.
*/
if ((fault_type & VM_PROT_WRITE) == 0) {
prot &= ~VM_PROT_WRITE;
m->flags |= PG_COPYONWRITE;
- }
- else {
+ } else {
/*
- * Try to get the lock on the copy_object.
+ * Try to get the lock on the copy_object.
*/
if (!vm_object_lock_try(copy_object)) {
vm_object_unlock(object);
@@ -639,64 +606,59 @@ vm_fault(map, vaddr, fault_type, change_wiring)
vm_object_lock(object);
goto RetryCopy;
}
-
/*
- * Make another reference to the copy-object,
- * to keep it from disappearing during the
- * copy.
+ * Make another reference to the copy-object, to keep
+ * it from disappearing during the copy.
*/
copy_object->ref_count++;
/*
- * Does the page exist in the copy?
+ * Does the page exist in the copy?
*/
copy_offset = first_offset
- - copy_object->shadow_offset;
+ - copy_object->shadow_offset;
copy_m = vm_page_lookup(copy_object, copy_offset);
page_exists = (copy_m != NULL);
if (page_exists) {
- if (copy_m->flags & (PG_BUSY|PG_VMIO)) {
+ if ((copy_m->flags & PG_BUSY) || copy_m->busy) {
/*
- * If the page is being brought
- * in, wait for it and then retry.
+ * If the page is being brought in,
+ * wait for it and then retry.
*/
RELEASE_PAGE(m);
copy_object->ref_count--;
vm_object_unlock(copy_object);
UNLOCK_THINGS;
spl = splhigh();
- if( copy_m->flags & (PG_BUSY|PG_VMIO)) {
- copy_m->flags |= PG_WANTED;
- tsleep((caddr_t)copy_m,PSWP,"vmpfwc",0);
+ if ((copy_m->flags & PG_BUSY) || copy_m->busy) {
+ copy_m->flags |= PG_WANTED | PG_REFERENCED;
+ tsleep((caddr_t) copy_m, PSWP, "vmpfwc", 0);
}
splx(spl);
vm_object_deallocate(first_object);
goto RetryFault;
}
}
-
/*
- * If the page is not in memory (in the object)
- * and the object has a pager, we have to check
- * if the pager has the data in secondary
- * storage.
+ * If the page is not in memory (in the object) and
+ * the object has a pager, we have to check if the
+ * pager has the data in secondary storage.
*/
if (!page_exists) {
/*
- * If we don't allocate a (blank) page
- * here... another thread could try
- * to page it in, allocate a page, and
- * then block on the busy page in its
- * shadow (first_object). Then we'd
- * trip over the busy page after we
- * found that the copy_object's pager
- * doesn't have the page...
+ * If we don't allocate a (blank) page here...
+ * another thread could try to page it in,
+ * allocate a page, and then block on the busy
+ * page in its shadow (first_object). Then
+ * we'd trip over the busy page after we found
+ * that the copy_object's pager doesn't have
+ * the page...
*/
- copy_m = vm_page_alloc(copy_object, copy_offset);
+ copy_m = vm_page_alloc(copy_object, copy_offset, 0);
if (copy_m == NULL) {
/*
- * Wait for a page, then retry.
+ * Wait for a page, then retry.
*/
RELEASE_PAGE(m);
copy_object->ref_count--;
@@ -705,15 +667,14 @@ vm_fault(map, vaddr, fault_type, change_wiring)
VM_WAIT;
goto RetryFault;
}
-
- if (copy_object->pager != NULL) {
+ if (copy_object->pager != NULL) {
vm_object_unlock(object);
vm_object_unlock(copy_object);
UNLOCK_MAP;
page_exists = vm_pager_has_page(
- copy_object->pager,
- (copy_offset + copy_object->paging_offset));
+ copy_object->pager,
+ (copy_offset + copy_object->paging_offset));
vm_object_lock(copy_object);
@@ -730,12 +691,12 @@ vm_fault(map, vaddr, fault_type, change_wiring)
if (copy_object->shadow != object ||
copy_object->ref_count == 1) {
/*
- * Gaah... start over!
+ * Gaah... start over!
*/
FREE_PAGE(copy_m);
vm_object_unlock(copy_object);
vm_object_deallocate(copy_object);
- /* may block */
+ /* may block */
vm_object_lock(object);
goto RetryCopy;
}
@@ -743,7 +704,7 @@ vm_fault(map, vaddr, fault_type, change_wiring)
if (page_exists) {
/*
- * We didn't need the page
+ * We didn't need the page
*/
FREE_PAGE(copy_m);
}
@@ -751,121 +712,108 @@ vm_fault(map, vaddr, fault_type, change_wiring)
}
if (!page_exists) {
/*
- * Must copy page into copy-object.
+ * Must copy page into copy-object.
*/
vm_page_copy(m, copy_m);
- copy_m->flags &= ~PG_FAKE;
+ copy_m->valid = VM_PAGE_BITS_ALL;
/*
- * Things to remember:
- * 1. The copied page must be marked 'dirty'
- * so it will be paged out to the copy
- * object.
- * 2. If the old page was in use by any users
- * of the copy-object, it must be removed
- * from all pmaps. (We can't know which
- * pmaps use it.)
+ * Things to remember: 1. The copied page must
+ * be marked 'dirty' so it will be paged out
+ * to the copy object. 2. If the old page was
+ * in use by any users of the copy-object, it
+ * must be removed from all pmaps. (We can't
+ * know which pmaps use it.)
*/
vm_page_lock_queues();
vm_page_activate(old_m);
-
pmap_page_protect(VM_PAGE_TO_PHYS(old_m),
- VM_PROT_NONE);
- if ((old_m->flags & PG_CLEAN) == 0)
- old_m->flags |= PG_LAUNDRY;
- copy_m->flags &= ~PG_CLEAN;
+ VM_PROT_NONE);
+ copy_m->dirty = VM_PAGE_BITS_ALL;
vm_page_activate(copy_m);
vm_page_unlock_queues();
PAGE_WAKEUP(copy_m);
}
/*
- * The reference count on copy_object must be
- * at least 2: one for our extra reference,
- * and at least one from the outside world
- * (we checked that when we last locked
- * copy_object).
+ * The reference count on copy_object must be at least
+ * 2: one for our extra reference, and at least one
+ * from the outside world (we checked that when we
+ * last locked copy_object).
*/
copy_object->ref_count--;
vm_object_unlock(copy_object);
m->flags &= ~PG_COPYONWRITE;
}
}
-
- if (m->flags & (PG_ACTIVE | PG_INACTIVE))
+ if (m->flags & (PG_ACTIVE | PG_INACTIVE | PG_CACHE))
panic("vm_fault: active or inactive before retrying lookup");
/*
- * We must verify that the maps have not changed
- * since our last lookup.
+ * We must verify that the maps have not changed since our last
+ * lookup.
*/
if (!lookup_still_valid) {
- vm_object_t retry_object;
- vm_offset_t retry_offset;
- vm_prot_t retry_prot;
+ vm_object_t retry_object;
+ vm_offset_t retry_offset;
+ vm_prot_t retry_prot;
/*
- * Since map entries may be pageable, make sure we can
- * take a page fault on them.
+ * Since map entries may be pageable, make sure we can take a
+ * page fault on them.
*/
vm_object_unlock(object);
/*
- * To avoid trying to write_lock the map while another
- * thread has it read_locked (in vm_map_pageable), we
- * do not try for write permission. If the page is
- * still writable, we will get write permission. If it
- * is not, or has been marked needs_copy, we enter the
- * mapping without write permission, and will merely
- * take another fault.
+ * To avoid trying to write_lock the map while another thread
+ * has it read_locked (in vm_map_pageable), we do not try for
+ * write permission. If the page is still writable, we will
+ * get write permission. If it is not, or has been marked
+ * needs_copy, we enter the mapping without write permission,
+ * and will merely take another fault.
*/
- result = vm_map_lookup(&map, vaddr,
- fault_type & ~VM_PROT_WRITE, &entry,
- &retry_object, &retry_offset, &retry_prot,
- &wired, &su);
+ result = vm_map_lookup(&map, vaddr, fault_type & ~VM_PROT_WRITE,
+ &entry, &retry_object, &retry_offset, &retry_prot, &wired, &su);
vm_object_lock(object);
/*
- * If we don't need the page any longer, put it on the
- * active list (the easiest thing to do here). If no
- * one needs it, pageout will grab it eventually.
+ * If we don't need the page any longer, put it on the active
+ * list (the easiest thing to do here). If no one needs it,
+ * pageout will grab it eventually.
*/
if (result != KERN_SUCCESS) {
RELEASE_PAGE(m);
UNLOCK_AND_DEALLOCATE;
- return(result);
+ return (result);
}
-
lookup_still_valid = TRUE;
if ((retry_object != first_object) ||
- (retry_offset != first_offset)) {
+ (retry_offset != first_offset)) {
RELEASE_PAGE(m);
UNLOCK_AND_DEALLOCATE;
goto RetryFault;
}
-
/*
- * Check whether the protection has changed or the object
- * has been copied while we left the map unlocked.
- * Changing from read to write permission is OK - we leave
- * the page write-protected, and catch the write fault.
- * Changing from write to read permission means that we
- * can't mark the page write-enabled after all.
+ * Check whether the protection has changed or the object has
+ * been copied while we left the map unlocked. Changing from
+ * read to write permission is OK - we leave the page
+ * write-protected, and catch the write fault. Changing from
+ * write to read permission means that we can't mark the page
+ * write-enabled after all.
*/
prot &= retry_prot;
if (m->flags & PG_COPYONWRITE)
prot &= ~VM_PROT_WRITE;
}
-
/*
- * (the various bits we're fiddling with here are locked by
- * the object's lock)
+ * (the various bits we're fiddling with here are locked by the
+ * object's lock)
*/
/* XXX This distorts the meaning of the copy_on_write bit */
@@ -874,28 +822,27 @@ vm_fault(map, vaddr, fault_type, change_wiring)
m->flags &= ~PG_COPYONWRITE;
/*
- * It's critically important that a wired-down page be faulted
- * only once in each map for which it is wired.
+ * It's critically important that a wired-down page be faulted only
+ * once in each map for which it is wired.
*/
- if (m->flags & (PG_ACTIVE | PG_INACTIVE))
+ if (m->flags & (PG_ACTIVE | PG_INACTIVE | PG_CACHE))
panic("vm_fault: active or inactive before pmap_enter");
vm_object_unlock(object);
/*
- * Put this page into the physical map.
- * We had to do the unlock above because pmap_enter
- * may cause other faults. We don't put the
- * page back on the active queue until later so
- * that the page-out daemon won't find us (yet).
+ * Put this page into the physical map. We had to do the unlock above
+ * because pmap_enter may cause other faults. We don't put the page
+ * back on the active queue until later so that the page-out daemon
+ * won't find us (yet).
*/
pmap_enter(map->pmap, vaddr, VM_PAGE_TO_PHYS(m), prot, wired);
/*
- * If the page is not wired down, then put it where the
- * pageout daemon can find it.
+ * If the page is not wired down, then put it where the pageout daemon
+ * can find it.
*/
vm_object_lock(object);
vm_page_lock_queues();
@@ -904,29 +851,27 @@ vm_fault(map, vaddr, fault_type, change_wiring)
vm_page_wire(m);
else
vm_page_unwire(m);
- }
- else {
+ } else {
vm_page_activate(m);
}
- if( curproc && curproc->p_stats) {
+ if (curproc && curproc->p_stats) {
if (hardfault) {
curproc->p_stats->p_ru.ru_majflt++;
} else {
curproc->p_stats->p_ru.ru_minflt++;
}
}
-
vm_page_unlock_queues();
/*
- * Unlock everything, and return
+ * Unlock everything, and return
*/
PAGE_WAKEUP(m);
UNLOCK_AND_DEALLOCATE;
- return(KERN_SUCCESS);
+ return (KERN_SUCCESS);
}
@@ -937,27 +882,26 @@ vm_fault(map, vaddr, fault_type, change_wiring)
*/
int
vm_fault_wire(map, start, end)
- vm_map_t map;
- vm_offset_t start, end;
+ vm_map_t map;
+ vm_offset_t start, end;
{
- register vm_offset_t va;
- register pmap_t pmap;
+ register vm_offset_t va;
+ register pmap_t pmap;
int rv;
pmap = vm_map_pmap(map);
/*
- * Inform the physical mapping system that the
- * range of addresses may not fault, so that
- * page tables and such can be locked down as well.
+ * Inform the physical mapping system that the range of addresses may
+ * not fault, so that page tables and such can be locked down as well.
*/
pmap_pageable(pmap, start, end, FALSE);
/*
- * We simulate a fault to get the page and enter it
- * in the physical map.
+ * We simulate a fault to get the page and enter it in the physical
+ * map.
*/
for (va = start; va < end; va += PAGE_SIZE) {
@@ -965,10 +909,10 @@ vm_fault_wire(map, start, end)
if (rv) {
if (va != start)
vm_fault_unwire(map, start, va);
- return(rv);
+ return (rv);
}
}
- return(KERN_SUCCESS);
+ return (KERN_SUCCESS);
}
@@ -979,18 +923,18 @@ vm_fault_wire(map, start, end)
*/
void
vm_fault_unwire(map, start, end)
- vm_map_t map;
- vm_offset_t start, end;
+ vm_map_t map;
+ vm_offset_t start, end;
{
- register vm_offset_t va, pa;
- register pmap_t pmap;
+ register vm_offset_t va, pa;
+ register pmap_t pmap;
pmap = vm_map_pmap(map);
/*
- * Since the pages are wired down, we must be able to
- * get their mappings from the physical map system.
+ * Since the pages are wired down, we must be able to get their
+ * mappings from the physical map system.
*/
vm_page_lock_queues();
@@ -1006,9 +950,8 @@ vm_fault_unwire(map, start, end)
vm_page_unlock_queues();
/*
- * Inform the physical mapping system that the range
- * of addresses may fault, so that page tables and
- * such may be unwired themselves.
+ * Inform the physical mapping system that the range of addresses may
+ * fault, so that page tables and such may be unwired themselves.
*/
pmap_pageable(pmap, start, end, TRUE);
@@ -1029,55 +972,54 @@ vm_fault_unwire(map, start, end)
void
vm_fault_copy_entry(dst_map, src_map, dst_entry, src_entry)
- vm_map_t dst_map;
- vm_map_t src_map;
- vm_map_entry_t dst_entry;
- vm_map_entry_t src_entry;
+ vm_map_t dst_map;
+ vm_map_t src_map;
+ vm_map_entry_t dst_entry;
+ vm_map_entry_t src_entry;
{
- vm_object_t dst_object;
- vm_object_t src_object;
- vm_offset_t dst_offset;
- vm_offset_t src_offset;
- vm_prot_t prot;
- vm_offset_t vaddr;
- vm_page_t dst_m;
- vm_page_t src_m;
+ vm_object_t dst_object;
+ vm_object_t src_object;
+ vm_offset_t dst_offset;
+ vm_offset_t src_offset;
+ vm_prot_t prot;
+ vm_offset_t vaddr;
+ vm_page_t dst_m;
+ vm_page_t src_m;
#ifdef lint
src_map++;
-#endif lint
+#endif /* lint */
src_object = src_entry->object.vm_object;
src_offset = src_entry->offset;
/*
- * Create the top-level object for the destination entry.
- * (Doesn't actually shadow anything - we copy the pages
- * directly.)
+ * Create the top-level object for the destination entry. (Doesn't
+ * actually shadow anything - we copy the pages directly.)
*/
dst_object = vm_object_allocate(
- (vm_size_t) (dst_entry->end - dst_entry->start));
+ (vm_size_t) (dst_entry->end - dst_entry->start));
dst_entry->object.vm_object = dst_object;
dst_entry->offset = 0;
- prot = dst_entry->max_protection;
+ prot = dst_entry->max_protection;
/*
- * Loop through all of the pages in the entry's range, copying
- * each one from the source object (it should be there) to the
- * destination object.
+ * Loop through all of the pages in the entry's range, copying each
+ * one from the source object (it should be there) to the destination
+ * object.
*/
for (vaddr = dst_entry->start, dst_offset = 0;
- vaddr < dst_entry->end;
- vaddr += PAGE_SIZE, dst_offset += PAGE_SIZE) {
+ vaddr < dst_entry->end;
+ vaddr += PAGE_SIZE, dst_offset += PAGE_SIZE) {
/*
- * Allocate a page in the destination object
+ * Allocate a page in the destination object
*/
vm_object_lock(dst_object);
do {
- dst_m = vm_page_alloc(dst_object, dst_offset);
+ dst_m = vm_page_alloc(dst_object, dst_offset, 0);
if (dst_m == NULL) {
vm_object_unlock(dst_object);
VM_WAIT;
@@ -1086,9 +1028,9 @@ vm_fault_copy_entry(dst_map, src_map, dst_entry, src_entry)
} while (dst_m == NULL);
/*
- * Find the page in the source object, and copy it in.
- * (Because the source is wired down, the page will be
- * in memory.)
+ * Find the page in the source object, and copy it in.
+ * (Because the source is wired down, the page will be in
+ * memory.)
*/
vm_object_lock(src_object);
src_m = vm_page_lookup(src_object, dst_offset + src_offset);
@@ -1098,16 +1040,16 @@ vm_fault_copy_entry(dst_map, src_map, dst_entry, src_entry)
vm_page_copy(src_m, dst_m);
/*
- * Enter it in the pmap...
+ * Enter it in the pmap...
*/
vm_object_unlock(src_object);
vm_object_unlock(dst_object);
pmap_enter(dst_map->pmap, vaddr, VM_PAGE_TO_PHYS(dst_m),
- prot, FALSE);
+ prot, FALSE);
/*
- * Mark it no longer busy, and put it on the active list.
+ * Mark it no longer busy, and put it on the active list.
*/
vm_object_lock(dst_object);
vm_page_lock_queues();
@@ -1122,7 +1064,7 @@ vm_fault_copy_entry(dst_map, src_map, dst_entry, src_entry)
/*
* looks page up in shadow chain
*/
-
+
int
vm_fault_page_lookup(object, offset, rtobject, rtoffset, rtm)
vm_object_t object;
@@ -1137,16 +1079,14 @@ vm_fault_page_lookup(object, offset, rtobject, rtoffset, rtm)
*rtobject = 0;
*rtoffset = 0;
-
- while (!(m=vm_page_lookup(object, offset))) {
+ while (!(m = vm_page_lookup(object, offset))) {
if (object->pager) {
- if (vm_pager_has_page(object->pager, object->paging_offset+offset)) {
+ if (vm_pager_has_page(object->pager, object->paging_offset + offset)) {
*rtobject = object;
*rtoffset = offset;
return 1;
}
}
-
if (!object->shadow)
return 0;
else {
@@ -1202,36 +1142,19 @@ vm_fault_additional_pages(first_object, first_offset, m, rbehind, raheada, marra
* if the requested page is not available, then give up now
*/
- if (!vm_pager_has_page(object->pager, object->paging_offset+offset))
+ if (!vm_pager_has_page(object->pager, object->paging_offset + offset))
return 0;
/*
- * if there is no getmulti routine for this pager, then just allow
- * one page to be read.
- */
-/*
- if (!object->pager->pg_ops->pgo_getpages) {
- *reqpage = 0;
- marray[0] = m;
- return 1;
- }
-*/
-
- /*
* try to do any readahead that we might have free pages for.
*/
rahead = raheada;
- if (rahead > (cnt.v_free_count - cnt.v_free_reserved)) {
- rahead = cnt.v_free_count - cnt.v_free_reserved;
- rbehind = 0;
+ if ((rahead + rbehind) > ((cnt.v_free_count + cnt.v_cache_count) - cnt.v_free_reserved)) {
+ rahead = ((cnt.v_free_count + cnt.v_cache_count) - cnt.v_free_reserved) / 2;
+ rbehind = rahead;
+ if (!rahead)
+ wakeup((caddr_t) & vm_pages_needed);
}
-
- if (cnt.v_free_count < cnt.v_free_min) {
- if (rahead > VM_FAULT_READ_AHEAD_MIN)
- rahead = VM_FAULT_READ_AHEAD_MIN;
- rbehind = 0;
- }
-
/*
* if we don't have any free pages, then just read one page.
*/
@@ -1240,23 +1163,22 @@ vm_fault_additional_pages(first_object, first_offset, m, rbehind, raheada, marra
marray[0] = m;
return 1;
}
-
/*
- * scan backward for the read behind pages --
- * in memory or on disk not in same object
+ * scan backward for the read behind pages -- in memory or on disk not
+ * in same object
*/
toffset = offset - NBPG;
- if( toffset < offset) {
- if( rbehind*NBPG > offset)
+ if (toffset < offset) {
+ if (rbehind * NBPG > offset)
rbehind = offset / NBPG;
- startoffset = offset - rbehind*NBPG;
+ startoffset = offset - rbehind * NBPG;
while (toffset >= startoffset) {
if (!vm_fault_page_lookup(first_object, toffset - offsetdiff, &rtobject, &rtoffset, &rtm) ||
rtm != 0 || rtobject != object) {
startoffset = toffset + NBPG;
break;
}
- if( toffset == 0)
+ if (toffset == 0)
break;
toffset -= NBPG;
}
@@ -1265,11 +1187,11 @@ vm_fault_additional_pages(first_object, first_offset, m, rbehind, raheada, marra
}
/*
- * scan forward for the read ahead pages --
- * in memory or on disk not in same object
+ * scan forward for the read ahead pages -- in memory or on disk not
+ * in same object
*/
toffset = offset + NBPG;
- endoffset = offset + (rahead+1)*NBPG;
+ endoffset = offset + (rahead + 1) * NBPG;
while (toffset < object->size && toffset < endoffset) {
if (!vm_fault_page_lookup(first_object, toffset - offsetdiff, &rtobject, &rtoffset, &rtm) ||
rtm != 0 || rtobject != object) {
@@ -1284,16 +1206,16 @@ vm_fault_additional_pages(first_object, first_offset, m, rbehind, raheada, marra
/* calculate the page offset of the required page */
treqpage = (offset - startoffset) / NBPG;
-
+
/* see if we have space (again) */
- if (cnt.v_free_count >= cnt.v_free_reserved + size) {
+ if ((cnt.v_free_count + cnt.v_cache_count) > (cnt.v_free_reserved + size)) {
bzero(marray, (rahead + rbehind + 1) * sizeof(vm_page_t));
/*
* get our pages and don't block for them
*/
for (i = 0; i < size; i++) {
if (i != treqpage)
- rtm = vm_page_alloc(object, startoffset + i * NBPG);
+ rtm = vm_page_alloc(object, startoffset + i * NBPG, 0);
else
rtm = m;
marray[i] = rtm;
@@ -1305,8 +1227,8 @@ vm_fault_additional_pages(first_object, first_offset, m, rbehind, raheada, marra
}
/*
- * if we could not get our block of pages, then
- * free the readahead/readbehind pages.
+ * if we could not get our block of pages, then free the
+ * readahead/readbehind pages.
*/
if (i < size) {
for (i = 0; i < size; i++) {
@@ -1316,8 +1238,7 @@ vm_fault_additional_pages(first_object, first_offset, m, rbehind, raheada, marra
*reqpage = 0;
marray[0] = m;
return 1;
- }
-
+ }
*reqpage = treqpage;
return size;
}
@@ -1325,4 +1246,3 @@ vm_fault_additional_pages(first_object, first_offset, m, rbehind, raheada, marra
marray[0] = m;
return 1;
}
-