Changeset View
Changeset View
Standalone View
Standalone View
sys/vm/vm_object.c
Show First 20 Lines • Show All 693 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* vm_object_terminate_pages removes any remaining pageable pages | * vm_object_terminate_pages removes any remaining pageable pages | ||||
* from the object and resets the object to an empty state. | * from the object and resets the object to an empty state. | ||||
*/ | */ | ||||
static void | static void | ||||
vm_object_terminate_pages(vm_object_t object) | vm_object_terminate_pages(vm_object_t object) | ||||
{ | { | ||||
vm_page_t p, p_next; | vm_page_t p, p_next; | ||||
struct mtx *mtx; | |||||
VM_OBJECT_ASSERT_WLOCKED(object); | VM_OBJECT_ASSERT_WLOCKED(object); | ||||
mtx = NULL; | |||||
/* | /* | ||||
* Free any remaining pageable pages. This also removes them from the | * Free any remaining pageable pages. This also removes them from the | ||||
* paging queues. However, don't free wired pages, just remove them | * paging queues. However, don't free wired pages, just remove them | ||||
* from the object. Rather than incrementally removing each page from | * from the object. Rather than incrementally removing each page from | ||||
* the object, the page and object are reset to any empty state. | * the object, the page and object are reset to any empty state. | ||||
*/ | */ | ||||
TAILQ_FOREACH_SAFE(p, &object->memq, listq, p_next) { | TAILQ_FOREACH_SAFE(p, &object->memq, listq, p_next) { | ||||
vm_page_assert_unbusied(p); | vm_page_assert_unbusied(p); | ||||
if ((object->flags & OBJ_UNMANAGED) == 0) | KASSERT(p->object == object && | ||||
(p->ref_count & VPRC_OBJREF) != 0, | |||||
("vm_object_terminate_pages: page %p is inconsistent", p)); | |||||
p->object = NULL; | |||||
if (VPRC_WIRE_COUNT(p->ref_count) == 0) | |||||
/* | /* | ||||
* vm_page_free_prep() only needs the page | * We hold the object lock and the page is unmapped and | ||||
* lock for managed pages. | * unbusied, so new wirings cannot be created. As an | ||||
* optimization, clear the reference count field using | |||||
* a regular store. | |||||
*/ | */ | ||||
vm_page_change_lock(p, &mtx); | atomic_store_rel_int(&p->ref_count, 0); | ||||
p->object = NULL; | else if (vm_page_drop(p, VPRC_OBJREF) != VPRC_OBJREF) | ||||
if (vm_page_wired(p)) | |||||
continue; | continue; | ||||
VM_CNT_INC(v_pfree); | VM_CNT_INC(v_pfree); | ||||
vm_page_free(p); | vm_page_free(p); | ||||
} | } | ||||
if (mtx != NULL) | |||||
mtx_unlock(mtx); | |||||
/* | /* | ||||
* If the object contained any pages, then reset it to an empty state. | * If the object contained any pages, then reset it to an empty state. | ||||
* None of the object's fields, including "resident_page_count", were | * None of the object's fields, including "resident_page_count", were | ||||
* modified by the preceding loop. | * modified by the preceding loop. | ||||
*/ | */ | ||||
if (object->resident_page_count != 0) { | if (object->resident_page_count != 0) { | ||||
vm_radix_reclaim_allnodes(&object->rtree); | vm_radix_reclaim_allnodes(&object->rtree); | ||||
▲ Show 20 Lines • Show All 845 Lines • ▼ Show 20 Lines | KASSERT(p->object == backing_object, | ||||
("vm_object_collapse_scan: object mismatch")); | ("vm_object_collapse_scan: object mismatch")); | ||||
if (p->pindex < backing_offset_index || | if (p->pindex < backing_offset_index || | ||||
new_pindex >= object->size) { | new_pindex >= object->size) { | ||||
if (backing_object->type == OBJT_SWAP) | if (backing_object->type == OBJT_SWAP) | ||||
swap_pager_freespace(backing_object, p->pindex, | swap_pager_freespace(backing_object, p->pindex, | ||||
1); | 1); | ||||
/* | |||||
* Page is out of the parent object's range, we can | |||||
* simply destroy it. | |||||
*/ | |||||
vm_page_lock(p); | |||||
KASSERT(!pmap_page_is_mapped(p), | KASSERT(!pmap_page_is_mapped(p), | ||||
("freeing mapped page %p", p)); | ("freeing mapped page %p", p)); | ||||
if (vm_page_remove(p)) | if (vm_page_remove(p)) | ||||
vm_page_free(p); | vm_page_free(p); | ||||
vm_page_unlock(p); | |||||
continue; | continue; | ||||
} | } | ||||
pp = vm_page_lookup(object, new_pindex); | pp = vm_page_lookup(object, new_pindex); | ||||
if (pp != NULL && vm_page_busied(pp)) { | if (pp != NULL && vm_page_busied(pp)) { | ||||
/* | /* | ||||
* The page in the parent is busy and possibly not | * The page in the parent is busy and possibly not | ||||
* (yet) valid. Until its state is finalized by the | * (yet) valid. Until its state is finalized by the | ||||
Show All 20 Lines | if (pp != NULL || vm_pager_has_page(object, new_pindex, NULL, | ||||
* The page already exists in the parent OR swap exists | * The page already exists in the parent OR swap exists | ||||
* for this location in the parent. Leave the parent's | * for this location in the parent. Leave the parent's | ||||
* page alone. Destroy the original page from the | * page alone. Destroy the original page from the | ||||
* backing object. | * backing object. | ||||
*/ | */ | ||||
if (backing_object->type == OBJT_SWAP) | if (backing_object->type == OBJT_SWAP) | ||||
swap_pager_freespace(backing_object, p->pindex, | swap_pager_freespace(backing_object, p->pindex, | ||||
1); | 1); | ||||
vm_page_lock(p); | |||||
KASSERT(!pmap_page_is_mapped(p), | KASSERT(!pmap_page_is_mapped(p), | ||||
("freeing mapped page %p", p)); | ("freeing mapped page %p", p)); | ||||
if (vm_page_remove(p)) | if (vm_page_remove(p)) | ||||
vm_page_free(p); | vm_page_free(p); | ||||
vm_page_unlock(p); | |||||
continue; | continue; | ||||
} | } | ||||
/* | /* | ||||
* Page does not exist in parent, rename the page from the | * Page does not exist in parent, rename the page from the | ||||
* backing object to the main object. | * backing object to the main object. | ||||
* | * | ||||
* If the page was mapped to a process, it can remain mapped | * If the page was mapped to a process, it can remain mapped | ||||
▲ Show 20 Lines • Show All 284 Lines • ▼ Show 20 Lines | for (; p != NULL && (p->pindex < end || end == 0); p = next) { | ||||
*/ | */ | ||||
vm_page_change_lock(p, &mtx); | vm_page_change_lock(p, &mtx); | ||||
if (vm_page_xbusied(p)) { | if (vm_page_xbusied(p)) { | ||||
VM_OBJECT_WUNLOCK(object); | VM_OBJECT_WUNLOCK(object); | ||||
vm_page_busy_sleep(p, "vmopax", true); | vm_page_busy_sleep(p, "vmopax", true); | ||||
VM_OBJECT_WLOCK(object); | VM_OBJECT_WLOCK(object); | ||||
goto again; | goto again; | ||||
} | } | ||||
wired: | |||||
if (vm_page_wired(p)) { | if (vm_page_wired(p)) { | ||||
if ((options & OBJPR_NOTMAPPED) == 0 && | if ((options & OBJPR_NOTMAPPED) == 0 && | ||||
object->ref_count != 0) | object->ref_count != 0) | ||||
pmap_remove_all(p); | pmap_remove_all(p); | ||||
if ((options & OBJPR_CLEANONLY) == 0) { | if ((options & OBJPR_CLEANONLY) == 0) { | ||||
p->valid = 0; | p->valid = 0; | ||||
vm_page_undirty(p); | vm_page_undirty(p); | ||||
} | } | ||||
continue; | continue; | ||||
} | } | ||||
if (vm_page_busied(p)) { | if (vm_page_busied(p)) { | ||||
VM_OBJECT_WUNLOCK(object); | VM_OBJECT_WUNLOCK(object); | ||||
vm_page_busy_sleep(p, "vmopar", false); | vm_page_busy_sleep(p, "vmopar", false); | ||||
VM_OBJECT_WLOCK(object); | VM_OBJECT_WLOCK(object); | ||||
goto again; | goto again; | ||||
} | } | ||||
KASSERT((p->flags & PG_FICTITIOUS) == 0, | KASSERT((p->flags & PG_FICTITIOUS) == 0, | ||||
("vm_object_page_remove: page %p is fictitious", p)); | ("vm_object_page_remove: page %p is fictitious", p)); | ||||
if ((options & OBJPR_CLEANONLY) != 0 && p->valid != 0) { | if ((options & OBJPR_CLEANONLY) != 0 && p->valid != 0) { | ||||
if ((options & OBJPR_NOTMAPPED) == 0 && | if ((options & OBJPR_NOTMAPPED) == 0 && | ||||
object->ref_count != 0) | object->ref_count != 0 && | ||||
pmap_remove_write(p); | !vm_page_try_remove_write(p)) | ||||
goto wired; | |||||
if (p->dirty != 0) | if (p->dirty != 0) | ||||
continue; | continue; | ||||
} | } | ||||
if ((options & OBJPR_NOTMAPPED) == 0 && object->ref_count != 0) | if ((options & OBJPR_NOTMAPPED) == 0 && | ||||
pmap_remove_all(p); | object->ref_count != 0 && !vm_page_try_remove_all(p)) | ||||
goto wired; | |||||
if (vm_page_remove(p)) | |||||
vm_page_free(p); | vm_page_free(p); | ||||
} | } | ||||
if (mtx != NULL) | if (mtx != NULL) | ||||
mtx_unlock(mtx); | mtx_unlock(mtx); | ||||
vm_object_pip_wakeup(object); | vm_object_pip_wakeup(object); | ||||
} | } | ||||
/* | /* | ||||
* vm_object_page_noreuse: | * vm_object_page_noreuse: | ||||
▲ Show 20 Lines • Show All 272 Lines • ▼ Show 20 Lines | if (m == NULL || pindex < m->pindex) { | ||||
VM_OBJECT_RLOCK(tobject); | VM_OBJECT_RLOCK(tobject); | ||||
} | } | ||||
} while ((tm = vm_page_lookup(tobject, tpindex)) == | } while ((tm = vm_page_lookup(tobject, tpindex)) == | ||||
NULL); | NULL); | ||||
} else { | } else { | ||||
tm = m; | tm = m; | ||||
m = TAILQ_NEXT(m, listq); | m = TAILQ_NEXT(m, listq); | ||||
} | } | ||||
vm_page_lock(tm); | |||||
if (vm_page_xbusied(tm)) { | if (vm_page_xbusied(tm)) { | ||||
vm_page_lock(tm); | |||||
for (tobject = object; locked_depth >= 1; | for (tobject = object; locked_depth >= 1; | ||||
locked_depth--) { | locked_depth--) { | ||||
t1object = tobject->backing_object; | t1object = tobject->backing_object; | ||||
VM_OBJECT_RUNLOCK(tobject); | VM_OBJECT_RUNLOCK(tobject); | ||||
tobject = t1object; | tobject = t1object; | ||||
} | } | ||||
vm_page_busy_sleep(tm, "unwbo", true); | vm_page_busy_sleep(tm, "unwbo", true); | ||||
goto again; | goto again; | ||||
} | } | ||||
vm_page_unwire(tm, queue); | vm_page_unwire(tm, queue); | ||||
vm_page_unlock(tm); | |||||
next_page: | next_page: | ||||
pindex++; | pindex++; | ||||
} | } | ||||
/* Release the accumulated object locks. */ | /* Release the accumulated object locks. */ | ||||
for (tobject = object; locked_depth >= 1; locked_depth--) { | for (tobject = object; locked_depth >= 1; locked_depth--) { | ||||
t1object = tobject->backing_object; | t1object = tobject->backing_object; | ||||
VM_OBJECT_RUNLOCK(tobject); | VM_OBJECT_RUNLOCK(tobject); | ||||
tobject = t1object; | tobject = t1object; | ||||
▲ Show 20 Lines • Show All 408 Lines • Show Last 20 Lines |