summaryrefslogtreecommitdiffstats
path: root/sys/vm/vm_fault.c
diff options
context:
space:
mode:
authordyson <dyson@FreeBSD.org>1998-01-22 17:30:44 +0000
committerdyson <dyson@FreeBSD.org>1998-01-22 17:30:44 +0000
commit197bd655c435302ddb4156bc654705dfef1d9143 (patch)
treea91dcc7eb7507f4d0088eb5e1b2e6872c51fd3ea /sys/vm/vm_fault.c
parentf95fe9806cd36e8b1fa77d590b5d1c2d48482618 (diff)
downloadFreeBSD-src-197bd655c435302ddb4156bc654705dfef1d9143.zip
FreeBSD-src-197bd655c435302ddb4156bc654705dfef1d9143.tar.gz
VM level code cleanups.
1) Start using TSM. Struct procs continue to point to upages structure, after being freed. Struct vmspace continues to point to pte object and kva space for kstack. u_map is now superfluous. 2) vm_map's don't need to be reference counted. They always exist either in the kernel or in a vmspace. The vmspaces are managed by reference counts. 3) Remove the "wired" vm_map nonsense. 4) No need to keep a cache of kernel stack kva's. 5) Get rid of strange looking ++var, and change to var++. 6) Change more data structures to use our "zone" allocator. Added struct proc, struct vmspace and struct vnode. This saves a significant amount of kva space and physical memory. Additionally, this enables TSM for the zone managed memory. 7) Keep ioopt disabled for now. 8) Remove the now bogus "single use" map concept. 9) Use generation counts or id's for data structures residing in TSM, where it allows us to avoid unneeded restart overhead during traversals, where blocking might occur. 10) Account better for memory deficits, so the pageout daemon will be able to make enough memory available (experimental.) 11) Fix some vnode locking problems. (From Tor, I think.) 12) Add a check in ufs_lookup, to avoid lots of unneeded calls to bcmp. (experimental.) 13) Significantly shrink, cleanup, and make slightly faster the vm_fault.c code. Use generation counts, get rid of unneded collpase operations, and clean up the cluster code. 14) Make vm_zone more suitable for TSM. This commit is partially as a result of discussions and contributions from other people, including DG, Tor Egge, PHK, and probably others that I have forgotten to attribute (so let me know, if I forgot.) This is not the infamous, final cleanup of the vnode stuff, but a necessary step. Vnode mgmt should be correct, but things might still change, and there is still some missing stuff (like ioopt, and physical backing of non-merged cache files, debugging of layering concepts.)
Diffstat (limited to 'sys/vm/vm_fault.c')
-rw-r--r--sys/vm/vm_fault.c259
1 files changed, 89 insertions, 170 deletions
diff --git a/sys/vm/vm_fault.c b/sys/vm/vm_fault.c
index 65dcaa5..62cda5a 100644
--- a/sys/vm/vm_fault.c
+++ b/sys/vm/vm_fault.c
@@ -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.74 1998/01/12 01:44:25 dyson Exp $
+ * $Id: vm_fault.c,v 1.75 1998/01/17 09:16:49 dyson Exp $
*/
/*
@@ -131,12 +131,13 @@ vm_fault(vm_map_t map, vm_offset_t vaddr, vm_prot_t fault_type, int fault_flags)
vm_prot_t prot;
int result;
boolean_t wired;
- boolean_t su;
boolean_t lookup_still_valid;
+ int map_generation;
vm_page_t old_m;
vm_object_t next_object;
vm_page_t marray[VM_FAULT_READ];
int hardfault = 0;
+ int faultcount;
struct vnode *vp = NULL;
struct proc *p = curproc; /* XXX */
@@ -184,6 +185,7 @@ vm_fault(vm_map_t map, vm_offset_t vaddr, vm_prot_t fault_type, int fault_flags)
RetryFault:;
+ faultcount = 0;
/*
* Find the backing store object and offset into it to begin the
@@ -191,7 +193,7 @@ RetryFault:;
*/
if ((result = vm_map_lookup(&map, vaddr,
fault_type, &entry, &first_object,
- &first_pindex, &prot, &wired, &su)) != KERN_SUCCESS) {
+ &first_pindex, &prot, &wired)) != KERN_SUCCESS) {
if ((result != KERN_PROTECTION_FAILURE) ||
((fault_flags & VM_FAULT_WIRE_MASK) != VM_FAULT_USER_WIRE)) {
return result;
@@ -206,7 +208,7 @@ RetryFault:;
*/
result = vm_map_lookup(&map, vaddr,
VM_PROT_READ|VM_PROT_WRITE|VM_PROT_OVERRIDE_WRITE,
- &entry, &first_object, &first_pindex, &prot, &wired, &su);
+ &entry, &first_object, &first_pindex, &prot, &wired);
if (result != KERN_SUCCESS) {
return result;
}
@@ -220,6 +222,8 @@ RetryFault:;
entry->max_protection &= ~VM_PROT_WRITE;
}
+ map_generation = map->timestamp;
+
if (entry->eflags & MAP_ENTRY_NOFAULT) {
panic("vm_fault: fault on nofault entry, addr: %lx",
vaddr);
@@ -363,15 +367,20 @@ readrest:
if (object->type != OBJT_DEFAULT &&
(((fault_flags & VM_FAULT_WIRE_MASK) == 0) || wired)) {
int rv;
- int faultcount;
int reqpage;
int ahead, behind;
- ahead = VM_FAULT_READ_AHEAD;
- behind = VM_FAULT_READ_BEHIND;
if (first_object->behavior == OBJ_RANDOM) {
ahead = 0;
behind = 0;
+ } else {
+ behind = (vaddr - entry->start) >> PAGE_SHIFT;
+ if (behind > VM_FAULT_READ_BEHIND)
+ behind = VM_FAULT_READ_BEHIND;
+
+ ahead = ((entry->end - vaddr) >> PAGE_SHIFT) - 1;
+ if (ahead > VM_FAULT_READ_AHEAD)
+ ahead = VM_FAULT_READ_AHEAD;
}
if ((first_object->type != OBJT_DEVICE) &&
@@ -568,7 +577,7 @@ readrest:
* first object. Note that we must mark the page dirty in the
* first object so that it will go out to swap when needed.
*/
- if (lookup_still_valid &&
+ if (map_generation == map->timestamp &&
/*
* Only one shadow object
*/
@@ -589,9 +598,18 @@ readrest:
/*
* We don't chase down the shadow chain
*/
- (object == first_object->backing_object)) {
+ (object == first_object->backing_object) &&
/*
+ * grab the lock if we need to
+ */
+ (lookup_still_valid ||
+ (((entry->eflags & MAP_ENTRY_IS_A_MAP) == 0) &&
+ lockmgr(&map->lock,
+ LK_EXCLUSIVE|LK_NOWAIT, (void *)0, curproc) == 0))) {
+
+ lookup_still_valid = 1;
+ /*
* get rid of the unnecessary page
*/
vm_page_protect(first_m, VM_PROT_NONE);
@@ -611,91 +629,12 @@ readrest:
vm_page_copy(m, first_m);
}
- /*
- * This code handles the case where there are two references to the
- * backing object, and one reference is getting a copy of the
- * page. If the other reference is the only other object that
- * points to the backing object, then perform a virtual copy
- * from the backing object to the other object after the
- * page is copied to the current first_object. If the other
- * object already has the page, we destroy it in the backing object
- * performing an optimized collapse-type operation. We don't
- * bother removing the page from the backing object's swap space.
- */
- if (lookup_still_valid &&
- /*
- * make sure that we have two shadow objs
- */
- (object->shadow_count == 2) &&
- /*
- * And no COW refs -- note that there are sometimes
- * temp refs to objs, but ignore that case -- we just
- * punt.
- */
- (object->ref_count == 2) &&
- /*
- * Noone else can look us up
- */
- (object->handle == NULL) &&
- /*
- * Not something that can be referenced elsewhere
- */
- ((object->type == OBJT_DEFAULT) ||
- (object->type == OBJT_SWAP)) &&
- /*
- * We don't bother chasing down object chain
- */
- (object == first_object->backing_object)) {
-
- vm_object_t other_object;
- vm_pindex_t other_pindex, other_pindex_offset;
- vm_page_t tm;
-
- other_object = TAILQ_FIRST(&object->shadow_head);
- if (other_object == first_object)
- other_object = TAILQ_NEXT(other_object, shadow_list);
- if (!other_object)
- panic("vm_fault: other object missing");
- if (other_object &&
- (other_object->type == OBJT_DEFAULT) &&
- (other_object->paging_in_progress == 0)) {
- other_pindex_offset =
- OFF_TO_IDX(other_object->backing_object_offset);
- if (pindex >= other_pindex_offset) {
- other_pindex = pindex - other_pindex_offset;
- /*
- * If the other object has the page, just free it.
- */
- if ((tm = vm_page_lookup(other_object, other_pindex))) {
- if ((tm->flags & PG_BUSY) == 0 &&
- tm->busy == 0 &&
- tm->valid == VM_PAGE_BITS_ALL) {
- /*
- * get rid of the unnecessary page
- */
- vm_page_protect(m, VM_PROT_NONE);
- PAGE_WAKEUP(m);
- vm_page_free(m);
- m = NULL;
- tm->dirty = VM_PAGE_BITS_ALL;
- first_m->dirty = VM_PAGE_BITS_ALL;
- }
- } else {
- /*
- * If the other object doesn't have the page,
- * then we move it there.
- */
- vm_page_rename(m, other_object, other_pindex);
- m->dirty = VM_PAGE_BITS_ALL;
- m->valid = VM_PAGE_BITS_ALL;
- }
- }
- }
- }
-
if (m) {
- if (m->queue != PQ_ACTIVE)
+ if (m->queue != PQ_ACTIVE) {
vm_page_activate(m);
+ m->act_count = 0;
+ }
+
/*
* We no longer need the old page or object.
*/
@@ -712,16 +651,6 @@ readrest:
object = first_object;
pindex = first_pindex;
- /*
- * Now that we've gotten the copy out of the way,
- * let's try to collapse the top object.
- *
- * But we have to play ugly games with
- * paging_in_progress to do that...
- */
- vm_object_pip_wakeup(object);
- vm_object_collapse(object);
- object->paging_in_progress++;
} else {
prot &= ~VM_PROT_WRITE;
}
@@ -732,7 +661,8 @@ readrest:
* lookup.
*/
- if (!lookup_still_valid) {
+ if (!lookup_still_valid &&
+ (map->timestamp != map_generation)) {
vm_object_t retry_object;
vm_pindex_t retry_pindex;
vm_prot_t retry_prot;
@@ -751,7 +681,8 @@ readrest:
* and will merely take another fault.
*/
result = vm_map_lookup(&map, vaddr, fault_type & ~VM_PROT_WRITE,
- &entry, &retry_object, &retry_pindex, &retry_prot, &wired, &su);
+ &entry, &retry_object, &retry_pindex, &retry_prot, &wired);
+ map_generation = map->timestamp;
/*
* If we don't need the page any longer, put it on the active
@@ -808,8 +739,9 @@ readrest:
m->flags &= ~PG_ZERO;
pmap_enter(map->pmap, vaddr, VM_PAGE_TO_PHYS(m), prot, wired);
- if (((fault_flags & VM_FAULT_WIRE_MASK) == 0) && (wired == 0))
- pmap_prefault(map->pmap, vaddr, entry, first_object);
+ if (((fault_flags & VM_FAULT_WIRE_MASK) == 0) && (wired == 0)) {
+ pmap_prefault(map->pmap, vaddr, entry);
+ }
m->flags |= PG_MAPPED|PG_REFERENCED;
if (fault_flags & VM_FAULT_HOLD)
@@ -912,6 +844,7 @@ vm_fault_user_wire(map, start, end)
* 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);
/*
@@ -1087,12 +1020,10 @@ vm_fault_additional_pages(m, rbehind, rahead, marray, reqpage)
vm_page_t *marray;
int *reqpage;
{
- int i;
+ int i,j;
vm_object_t object;
vm_pindex_t pindex, startpindex, endpindex, tpindex;
- vm_offset_t size;
vm_page_t rtm;
- int treqpage;
int cbehind, cahead;
object = m->object;
@@ -1112,8 +1043,9 @@ vm_fault_additional_pages(m, rbehind, rahead, marray, reqpage)
*/
if (!vm_pager_has_page(object,
- OFF_TO_IDX(object->paging_offset) + pindex, &cbehind, &cahead))
+ OFF_TO_IDX(object->paging_offset) + pindex, &cbehind, &cahead)) {
return 0;
+ }
if ((cbehind == 0) && (cahead == 0)) {
*reqpage = 0;
@@ -1135,91 +1067,78 @@ vm_fault_additional_pages(m, rbehind, rahead, marray, reqpage)
if ((rahead + rbehind) >
((cnt.v_free_count + cnt.v_cache_count) - cnt.v_free_reserved)) {
pagedaemon_wakeup();
- *reqpage = 0;
marray[0] = m;
+ *reqpage = 0;
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
*/
- tpindex = pindex - 1;
- if (tpindex < pindex) {
- if (rbehind > pindex)
+ if (pindex > 0) {
+ if (rbehind > pindex) {
rbehind = pindex;
- startpindex = pindex - rbehind;
- while (tpindex >= startpindex) {
+ startpindex = 0;
+ } else {
+ startpindex = pindex - rbehind;
+ }
+
+ for ( tpindex = pindex - 1; tpindex >= startpindex; tpindex -= 1) {
if (vm_page_lookup( object, tpindex)) {
startpindex = tpindex + 1;
break;
}
if (tpindex == 0)
break;
- tpindex -= 1;
+ }
+
+ for(i = 0, tpindex = startpindex; tpindex < pindex; i++, tpindex++) {
+
+ rtm = vm_page_alloc(object, tpindex, VM_ALLOC_NORMAL);
+ if (rtm == NULL) {
+ for (j = 0; j < i; j++) {
+ FREE_PAGE(marray[j]);
+ }
+ marray[0] = m;
+ *reqpage = 0;
+ return 1;
+ }
+
+ marray[i] = rtm;
}
} else {
- startpindex = pindex;
+ startpindex = 0;
+ i = 0;
}
+ marray[i] = m;
+ /* page offset of the required page */
+ *reqpage = i;
+
+ tpindex = pindex + 1;
+ i++;
+
/*
- * scan forward for the read ahead pages -- in memory or on disk not
- * in same object
+ * scan forward for the read ahead pages
*/
- tpindex = pindex + 1;
- endpindex = pindex + (rahead + 1);
+ endpindex = tpindex + rahead;
if (endpindex > object->size)
endpindex = object->size;
- while (tpindex < endpindex) {
- if ( vm_page_lookup(object, tpindex)) {
- break;
- }
- tpindex += 1;
- }
- endpindex = tpindex;
- /* calculate number of bytes of pages */
- size = endpindex - startpindex;
+ for( ; tpindex < endpindex; i++, tpindex++) {
- /* calculate the page offset of the required page */
- treqpage = pindex - startpindex;
+ if (vm_page_lookup(object, tpindex)) {
+ break;
+ }
- /* see if we have space (again) */
- if ((cnt.v_free_count + cnt.v_cache_count) >
- (cnt.v_free_reserved + size)) {
- /*
- * get our pages and don't block for them
- */
- for (i = 0; i < size; i++) {
- if (i != treqpage) {
- rtm = vm_page_alloc(object,
- startpindex + i,
- VM_ALLOC_NORMAL);
- if (rtm == NULL) {
- if (i < treqpage) {
- int j;
- for (j = 0; j < i; j++) {
- FREE_PAGE(marray[j]);
- }
- *reqpage = 0;
- marray[0] = m;
- return 1;
- } else {
- size = i;
- *reqpage = treqpage;
- return size;
- }
- }
- marray[i] = rtm;
- } else {
- marray[i] = m;
- }
+ rtm = vm_page_alloc(object, tpindex, VM_ALLOC_NORMAL);
+ if (rtm == NULL) {
+ break;
}
- *reqpage = treqpage;
- return size;
+ marray[i] = rtm;
}
- *reqpage = 0;
- marray[0] = m;
- return 1;
+
+ /* return number of bytes of pages */
+ return i;
}
OpenPOWER on IntegriCloud