Index: sys/vm/vm_fault.c =================================================================== --- sys/vm/vm_fault.c +++ sys/vm/vm_fault.c @@ -137,7 +137,12 @@ vm_page_xunbusy(fs->m); vm_page_lock(fs->m); - vm_page_deactivate(fs->m); + if (fs->m->valid == 0) { + if (fs->m->wire_count == 0) + vm_page_free(fs->m); + } else { + vm_page_deactivate(fs->m); + } vm_page_unlock(fs->m); fs->m = NULL; } @@ -292,7 +297,8 @@ struct faultstate fs; struct vnode *vp; vm_page_t m; - int ahead, behind, cluster_offset, error, locked; + int ahead, behind, cluster_offset, dead, error, locked, rv; + u_char behavior; hardfault = 0; growstack = TRUE; @@ -412,7 +418,7 @@ fs.lookup_still_valid = TRUE; - fs.first_m = NULL; + fs.m = fs.first_m = NULL; /* * Search for the page at object/offset. @@ -421,11 +427,20 @@ fs.pindex = fs.first_pindex; while (TRUE) { /* - * If the object is dead, we stop here + * If the object is marked for imminent termination, + * we retry here, since the collapse pass has raced + * with us. Otherwise, if we see terminally dead + * object, return fail. */ - if (fs.object->flags & OBJ_DEAD) { + if ((fs.object->flags & OBJ_DEAD) != 0) { + dead = fs.object->type == OBJT_DEAD; + if (fs.m != NULL && fs.m != fs.first_m) + release_page(&fs); unlock_and_deallocate(&fs); - return (KERN_PROTECTION_FAILURE); + if (dead) + return (KERN_PROTECTION_FAILURE); + pause("vmf_de", 1); + goto RetryFault; } /* @@ -551,9 +566,18 @@ * zero-filled pages. */ if (fs.object->type != OBJT_DEFAULT) { - int rv; - u_char behavior = vm_map_entry_behavior(fs.entry); - + if (!fs.lookup_still_valid) { + locked = vm_map_trylock_read(fs.map); + if (locked) + fs.lookup_still_valid = TRUE; + if (!locked || fs.map->timestamp != + map_generation) { + release_page(&fs); + unlock_and_deallocate(&fs); + goto RetryFault; + } + } + behavior = vm_map_entry_behavior(fs.entry); era = fs.entry->read_ahead; if (behavior == MAP_ENTRY_BEHAV_RANDOM || P_KILLED(curproc)) { @@ -604,6 +628,7 @@ } ahead = ulmin(ahead, atop(fs.entry->end - vaddr) - 1); if (era != nera) + /* XXX only read-lock on map */ fs.entry->read_ahead = nera; /* @@ -821,6 +846,7 @@ if (vm_page_rename(fs.m, fs.first_object, fs.first_pindex)) { VM_OBJECT_WUNLOCK(fs.first_object); + release_page(&fs); unlock_and_deallocate(&fs); goto RetryFault; } Index: sys/vm/vm_object.c =================================================================== --- sys/vm/vm_object.c +++ sys/vm/vm_object.c @@ -1584,7 +1584,7 @@ continue; } - KASSERT(pp == NULL || pp->valid != 0, + KASSERT(pp == NULL || pp->wire_count > 0 || pp->valid != 0, ("unbusy invalid page %p", pp)); if (pp != NULL || vm_pager_has_page(object, new_pindex, NULL, @@ -1669,11 +1669,14 @@ void vm_object_collapse(vm_object_t object) { + vm_object_t backing_object, new_backing_object; + VM_OBJECT_ASSERT_WLOCKED(object); - - while (TRUE) { - vm_object_t backing_object; + if ((object->flags & OBJ_DEAD) != 0) + return; + vm_object_pip_add(object, 1); + while (TRUE) { /* * Verify that the conditions are right for collapse: * @@ -1699,14 +1702,14 @@ break; } - if ( - object->paging_in_progress != 0 || - backing_object->paging_in_progress != 0 - ) { + if (object->paging_in_progress > 1 /* one ref is from us */ || + backing_object->paging_in_progress != 0) { vm_object_qcollapse(object); VM_OBJECT_WUNLOCK(backing_object); break; } + vm_object_pip_add(backing_object, 1); + /* * We know that we can either collapse the backing object (if * the parent is the only reference to it) or (perhaps) have @@ -1789,6 +1792,7 @@ KASSERT(backing_object->ref_count == 1, ( "backing_object %p was somehow re-referenced during collapse!", backing_object)); + vm_object_pip_wakeup(backing_object); backing_object->type = OBJT_DEAD; backing_object->ref_count = 0; VM_OBJECT_WUNLOCK(backing_object); @@ -1796,14 +1800,13 @@ object_collapses++; } else { - vm_object_t new_backing_object; - /* * If we do not entirely shadow the backing object, * there is nothing we can do so we give up. */ if (object->resident_page_count != object->size && !vm_object_scan_all_shadowed(object)) { + vm_object_pip_wakeup(backing_object); VM_OBJECT_WUNLOCK(backing_object); break; } @@ -1836,6 +1839,7 @@ * its ref_count was at least 2, it will not vanish. */ backing_object->ref_count--; + vm_object_pip_wakeup(backing_object); VM_OBJECT_WUNLOCK(backing_object); object_bypasses++; } @@ -1844,6 +1848,7 @@ * Try again with this object's new backing object. */ } + vm_object_pip_wakeup(object); } /* Index: sys/vm/vm_page.c =================================================================== --- sys/vm/vm_page.c +++ sys/vm/vm_page.c @@ -1944,8 +1944,10 @@ m < &m_ret[npages]; m++) { if ((req & VM_ALLOC_WIRED) != 0) m->wire_count = 0; - if (m >= m_tmp) + if (m >= m_tmp) { m->object = NULL; + m->oflags |= VPO_UNMANAGED; + } vm_page_free(m); } return (NULL); @@ -3288,7 +3290,8 @@ cache_was_empty = vm_radix_is_empty(&object->cache); if (vm_radix_insert(&object->cache, m)) { mtx_unlock(&vm_page_queue_free_mtx); - if (object->resident_page_count == 0) + if (object->type == OBJT_VNODE && + object->resident_page_count == 0) vdrop(object->handle); m->object = NULL; vm_page_free(m);