diff options
Diffstat (limited to 'sys/vm/vm_object.c')
-rw-r--r-- | sys/vm/vm_object.c | 246 |
1 files changed, 143 insertions, 103 deletions
diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c index a1477f2..86c71c8 100644 --- a/sys/vm/vm_object.c +++ b/sys/vm/vm_object.c @@ -61,7 +61,7 @@ * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. * - * $Id: vm_object.c,v 1.137 1999/01/08 17:31:26 eivind Exp $ + * $Id: vm_object.c,v 1.138 1999/01/10 01:58:28 eivind Exp $ */ /* @@ -134,9 +134,12 @@ static long object_bypasses; static int next_index; static vm_zone_t obj_zone; static struct vm_zone obj_zone_store; +static int object_hash_rand; #define VM_OBJECTS_INIT 256 static struct vm_object vm_objects_init[VM_OBJECTS_INIT]; +#if 0 static int objidnumber; +#endif void _vm_object_allocate(type, size, object) @@ -152,7 +155,9 @@ _vm_object_allocate(type, size, object) object->size = size; object->ref_count = 1; object->flags = 0; +#if 0 object->id = ++objidnumber; +#endif if ((object->type == OBJT_DEFAULT) || (object->type == OBJT_SWAP)) vm_object_set_flag(object, OBJ_ONEMAPPING); object->behavior = OBJ_NORMAL; @@ -168,16 +173,25 @@ _vm_object_allocate(type, size, object) incr = size; next_index = (next_index + incr) & PQ_L2_MASK; object->handle = NULL; - object->paging_offset = (vm_ooffset_t) 0; object->backing_object = NULL; object->backing_object_offset = (vm_ooffset_t) 0; +#if 0 object->page_hint = NULL; +#endif + /* + * Try to generate a number that will spread objects out in the + * hash table. We 'wipe' new objects across the hash in 128 page + * increments plus 1 more to offset it a little more by the time + * it wraps around. + */ + object->hash_rand = object_hash_rand - 129; object->last_read = 0; object->generation++; TAILQ_INSERT_TAIL(&vm_object_list, object, object_list); vm_object_count++; + object_hash_rand = object->hash_rand; } /* @@ -336,25 +350,15 @@ vm_object_deallocate(object) robject->ref_count++; - retry: - if (robject->paging_in_progress || - object->paging_in_progress) { + while ( + robject->paging_in_progress || + object->paging_in_progress + ) { vm_object_pip_sleep(robject, "objde1"); - if (robject->paging_in_progress && - robject->type == OBJT_SWAP) { - swap_pager_sync(); - goto retry; - } - vm_object_pip_sleep(object, "objde2"); - if (object->paging_in_progress && - object->type == OBJT_SWAP) { - swap_pager_sync(); - } - goto retry; } - if( robject->ref_count == 1) { + if (robject->ref_count == 1) { robject->ref_count--; object = robject; goto doterm; @@ -396,6 +400,7 @@ doterm: * up all previously used resources. * * The object must be locked. + * This routine may block. */ void vm_object_terminate(object) @@ -444,13 +449,13 @@ vm_object_terminate(object) /* * Now free any remaining pages. For internal objects, this also * removes them from paging queues. Don't free wired pages, just - * remove them from the object. + * remove them from the object. */ s = splvm(); while ((p = TAILQ_FIRST(&object->memq)) != NULL) { #if !defined(MAX_PERF) if (p->busy || (p->flags & PG_BUSY)) - printf("vm_object_terminate: freeing busy page\n"); + panic("vm_object_terminate: freeing busy page %p\n", p); #endif if (p->wire_count == 0) { vm_page_busy(p); @@ -566,9 +571,7 @@ rescan: } s = splvm(); - while ((p->flags & PG_BUSY) || p->busy) { - vm_page_flag_set(p, PG_WANTED | PG_REFERENCED); - tsleep(p, PVM, "vpcwai", 0); + while (vm_page_sleep_busy(p, TRUE, "vpcwai")) { if (object->generation != curgeneration) { splx(s); goto rescan; @@ -763,6 +766,12 @@ vm_object_pmap_remove(object, start, end) * vm_object_madvise: * * Implements the madvise function at the object/page level. + * + * Currently, madvise() functions are limited to the default and + * swap object types only, and also limited to only the unshared portions + * of a process's address space. MADV_FREE, certainly, could never be + * run on anything else. The others are more flexible and the code could + * be adjusted in the future to handle expanded cases for them. */ void vm_object_madvise(object, pindex, count, advise) @@ -780,22 +789,59 @@ vm_object_madvise(object, pindex, count, advise) end = pindex + count; - for (; pindex < end; pindex += 1) { + /* + * MADV_FREE special case - free any swap backing store (as well + * as resident pages later on). + */ + + if (advise == MADV_FREE) { + tobject = object; + tpindex = pindex; + while ( + (tobject->type == OBJT_DEFAULT || + tobject->type == OBJT_SWAP) && + (tobject->flags & OBJ_ONEMAPPING) + ) { + if (tobject->type == OBJT_SWAP) { + swap_pager_freespace(tobject, tpindex, count); + } + if ((tobject = tobject->backing_object) == NULL) + break; + tpindex += OFF_TO_IDX(tobject->backing_object_offset); + } + } + + /* + * Locate and adjust resident pages + */ + + for (; pindex < end; pindex += 1) { relookup: tobject = object; tpindex = pindex; shadowlookup: + + if (tobject->type != OBJT_DEFAULT && + tobject->type != OBJT_SWAP + ) { + continue; + } + + if ((tobject->flags & OBJ_ONEMAPPING) == 0) + continue; + m = vm_page_lookup(tobject, tpindex); + if (m == NULL) { - if (tobject->type != OBJT_DEFAULT) { - continue; - } - tobject = tobject->backing_object; + if (tobject == NULL) + continue; +#if 0 if ((tobject == NULL) || (tobject->ref_count != 1)) { continue; } +#endif tpindex += OFF_TO_IDX(tobject->backing_object_offset); goto shadowlookup; } @@ -805,12 +851,15 @@ shadowlookup: * we skip it. Things can break if we mess with pages * in any of the below states. */ - if (m->hold_count || m->wire_count || - m->valid != VM_PAGE_BITS_ALL) { + if ( + m->hold_count || + m->wire_count || + m->valid != VM_PAGE_BITS_ALL + ) { continue; } - if (vm_page_sleep(m, "madvpo", &m->busy)) + if (vm_page_sleep_busy(m, TRUE, "madvpo")) goto relookup; if (advise == MADV_WILLNEED) { @@ -818,15 +867,25 @@ shadowlookup: } else if (advise == MADV_DONTNEED) { vm_page_deactivate(m); } else if (advise == MADV_FREE) { - pmap_clear_modify(VM_PAGE_TO_PHYS(m)); - m->dirty = 0; /* - * Force a demand zero if attempt to read from swap. - * We currently don't handle vnode files correctly, - * and will reread stale contents unnecessarily. + * If MADV_FREE_FORCE_FREE is defined, we attempt to + * immediately free the page. Otherwise we just + * destroy any swap backing store, mark it clean, + * and stuff it into the cache. */ - if (object->type == OBJT_SWAP) - swap_pager_dmzspace(tobject, m->pindex, 1); + pmap_clear_modify(VM_PAGE_TO_PHYS(m)); + m->dirty = 0; + +#ifdef MADV_FREE_FORCE_FREE + if (tobject->resident_page_count > 1) { + vm_page_busy(m); + vm_page_protect(m, VM_PROT_NONE); + vm_page_free(m); + } else +#endif + { + vm_page_cache(m); + } } } } @@ -900,8 +959,7 @@ vm_object_qcollapse(object) register vm_object_t object; { register vm_object_t backing_object; - register vm_pindex_t backing_offset_index, paging_offset_index; - vm_pindex_t backing_object_paging_offset_index; + register vm_pindex_t backing_offset_index; vm_pindex_t new_pindex; register vm_page_t p, pp; register vm_size_t size; @@ -913,27 +971,39 @@ vm_object_qcollapse(object) backing_object->ref_count += 2; backing_offset_index = OFF_TO_IDX(object->backing_object_offset); - backing_object_paging_offset_index = OFF_TO_IDX(backing_object->paging_offset); - paging_offset_index = OFF_TO_IDX(object->paging_offset); size = object->size; + p = TAILQ_FIRST(&backing_object->memq); while (p) { vm_page_t next; + /* + * setup for loop. + * loop if the page isn't trivial. + */ + next = TAILQ_NEXT(p, listq); if ((p->flags & (PG_BUSY | PG_FICTITIOUS)) || !p->valid || p->hold_count || p->wire_count || p->busy) { p = next; continue; } + + /* + * busy the page and move it from the backing store to the + * parent object. + */ + vm_page_busy(p); + KASSERT(p->object == object, ("vm_object_qcollapse(): object mismatch")); + new_pindex = p->pindex - backing_offset_index; if (p->pindex < backing_offset_index || new_pindex >= size) { if (backing_object->type == OBJT_SWAP) swap_pager_freespace(backing_object, - backing_object_paging_offset_index+p->pindex, + p->pindex, 1); vm_page_protect(p, VM_PROT_NONE); vm_page_free(p); @@ -941,16 +1011,16 @@ vm_object_qcollapse(object) pp = vm_page_lookup(object, new_pindex); if (pp != NULL || (object->type == OBJT_SWAP && vm_pager_has_page(object, - paging_offset_index + new_pindex, NULL, NULL))) { + new_pindex, NULL, NULL))) { if (backing_object->type == OBJT_SWAP) swap_pager_freespace(backing_object, - backing_object_paging_offset_index + p->pindex, 1); + p->pindex, 1); vm_page_protect(p, VM_PROT_NONE); vm_page_free(p); } else { if (backing_object->type == OBJT_SWAP) swap_pager_freespace(backing_object, - backing_object_paging_offset_index + p->pindex, 1); + p->pindex, 1); if ((p->queue - p->pc) == PQ_CACHE) vm_page_deactivate(p); @@ -958,7 +1028,7 @@ vm_object_qcollapse(object) vm_page_protect(p, VM_PROT_NONE); vm_page_rename(p, object, new_pindex); - p->dirty = VM_PAGE_BITS_ALL; + /* page automatically made dirty by rename */ } } p = next; @@ -1049,9 +1119,10 @@ vm_object_collapse(object) */ while ((p = TAILQ_FIRST(&backing_object->memq)) != 0) { - - new_pindex = p->pindex - backing_offset_index; + if (vm_page_sleep_busy(p, TRUE, "vmocol")) + continue; vm_page_busy(p); + new_pindex = p->pindex - backing_offset_index; /* * If the parent has a page here, or if this @@ -1068,7 +1139,7 @@ vm_object_collapse(object) } else { pp = vm_page_lookup(object, new_pindex); if (pp != NULL || (object->type == OBJT_SWAP && vm_pager_has_page(object, - OFF_TO_IDX(object->paging_offset) + new_pindex, NULL, NULL))) { + new_pindex, NULL, NULL))) { vm_page_protect(p, VM_PROT_NONE); vm_page_free(p); } else { @@ -1077,7 +1148,7 @@ vm_object_collapse(object) else vm_page_protect(p, VM_PROT_NONE); vm_page_rename(p, object, new_pindex); - p->dirty = VM_PAGE_BITS_ALL; + /* page automatically made dirty by rename */ } } } @@ -1088,52 +1159,22 @@ vm_object_collapse(object) if (backing_object->type == OBJT_SWAP) { vm_object_pip_add(backing_object, 1); - if (object->type == OBJT_SWAP) { - vm_object_pip_add(object, 1); - /* - * copy shadow object pages into ours - * and destroy unneeded pages in - * shadow object. - */ - swap_pager_copy( - backing_object, - OFF_TO_IDX(backing_object->paging_offset), - object, - OFF_TO_IDX(object->paging_offset), - OFF_TO_IDX(object->backing_object_offset), TRUE); - vm_object_pip_wakeup(object); - } else { - vm_object_pip_add(object, 1); - /* - * move the shadow backing_object's pager data to - * "object" and convert "object" type to OBJT_SWAP. - */ - object->type = OBJT_SWAP; - object->un_pager.swp.swp_nblocks = - backing_object->un_pager.swp.swp_nblocks; - object->un_pager.swp.swp_allocsize = - backing_object->un_pager.swp.swp_allocsize; - object->un_pager.swp.swp_blocks = - backing_object->un_pager.swp.swp_blocks; - object->un_pager.swp.swp_poip = /* XXX */ - backing_object->un_pager.swp.swp_poip; - object->paging_offset = backing_object->paging_offset + backing_offset; - TAILQ_INSERT_TAIL(&swap_pager_un_object_list, object, pager_object_list); - - /* - * Convert backing object from OBJT_SWAP to - * OBJT_DEFAULT. XXX - only the TAILQ_REMOVE is - * actually necessary. - */ - backing_object->type = OBJT_DEFAULT; - TAILQ_REMOVE(&swap_pager_un_object_list, backing_object, pager_object_list); - /* - * free unnecessary blocks - */ - swap_pager_freespace(object, 0, - OFF_TO_IDX(object->paging_offset)); - vm_object_pip_wakeup(object); - } + + /* + * scrap the paging_offset junk and do a + * discrete copy. This also removes major + * assumptions about how the swap-pager + * works from where it doesn't belong. The + * new swapper is able to optimize the + * destroy-source case. + */ + + vm_object_pip_add(object, 1); + swap_pager_copy( + backing_object, + object, + OFF_TO_IDX(object->backing_object_offset), TRUE); + vm_object_pip_wakeup(object); vm_object_pip_wakeup(backing_object); } @@ -1223,7 +1264,7 @@ vm_object_collapse(object) vm_page_busy(pp); if ((pp->valid == 0) && - !vm_pager_has_page(object, OFF_TO_IDX(object->paging_offset) + new_pindex, NULL, NULL)) { + !vm_pager_has_page(object, new_pindex, NULL, NULL)) { /* * Page still needed. Can't go any * further. @@ -1318,7 +1359,7 @@ again: * interrupt -- minimize the spl transitions */ - if (vm_page_sleep(p, "vmopar", &p->busy)) + if (vm_page_sleep_busy(p, TRUE, "vmopar")) goto again; if (clean_only && p->valid) { @@ -1349,7 +1390,7 @@ again: * The busy flags are only cleared at * interrupt -- minimize the spl transitions */ - if (vm_page_sleep(p, "vmopar", &p->busy)) + if (vm_page_sleep_busy(p, TRUE, "vmopar")) goto again; if (clean_only && p->valid) { @@ -1589,11 +1630,10 @@ DB_SHOW_COMMAND(object, vm_object_print_static) object, (int)object->type, (u_long)object->size, object->resident_page_count, object->ref_count, object->flags); /* - * XXX no %qd in kernel. Truncate object->paging_offset and - * object->backing_object_offset. + * XXX no %qd in kernel. Truncate object->backing_object_offset. */ - db_iprintf(" sref=%d, offset=0x%lx, backing_object(%d)=(%p)+0x%lx\n", - object->shadow_count, (long)object->paging_offset, + db_iprintf(" sref=%d, backing_object(%d)=(%p)+0x%lx\n", + object->shadow_count, object->backing_object ? object->backing_object->ref_count : 0, object->backing_object, (long)object->backing_object_offset); |