Changeset View
Changeset View
Standalone View
Standalone View
head/sys/vm/vm_object.c
Show First 20 Lines • Show All 524 Lines • ▼ Show 20 Lines | |||||
* are gone, storage associated with this object | * are gone, storage associated with this object | ||||
* may be relinquished. | * may be relinquished. | ||||
* | * | ||||
* No object may be locked. | * No object may be locked. | ||||
*/ | */ | ||||
void | void | ||||
vm_object_deallocate(vm_object_t object) | vm_object_deallocate(vm_object_t object) | ||||
{ | { | ||||
vm_object_t temp; | vm_object_t robject, temp; | ||||
bool released; | bool released; | ||||
while (object != NULL) { | while (object != NULL) { | ||||
VM_OBJECT_RLOCK(object); | VM_OBJECT_RLOCK(object); | ||||
if (object->type == OBJT_VNODE) { | if (object->type == OBJT_VNODE) { | ||||
vm_object_vndeallocate(object); | vm_object_vndeallocate(object); | ||||
return; | return; | ||||
} | } | ||||
Show All 18 Lines | KASSERT(object->ref_count != 0, | ||||
("vm_object_deallocate: object deallocated too many times: %d", object->type)); | ("vm_object_deallocate: object deallocated too many times: %d", object->type)); | ||||
refcount_release(&object->ref_count); | refcount_release(&object->ref_count); | ||||
if (object->ref_count > 1) { | if (object->ref_count > 1) { | ||||
VM_OBJECT_WUNLOCK(object); | VM_OBJECT_WUNLOCK(object); | ||||
return; | return; | ||||
} else if (object->ref_count == 1) { | } else if (object->ref_count == 1) { | ||||
if (object->shadow_count == 0 && | if (object->shadow_count == 0 && | ||||
object->handle == NULL && | |||||
(object->flags & OBJ_ANON) != 0) { | (object->flags & OBJ_ANON) != 0) { | ||||
vm_object_set_flag(object, OBJ_ONEMAPPING); | vm_object_set_flag(object, OBJ_ONEMAPPING); | ||||
} else if ((object->shadow_count == 1) && | } else if (object->shadow_count == 1) { | ||||
(object->handle == NULL) && | KASSERT((object->flags & OBJ_ANON) != 0, | ||||
(object->flags & OBJ_ANON) != 0) { | ("obj %p with shadow_count > 0 is not anon", | ||||
vm_object_t robject; | object)); | ||||
robject = LIST_FIRST(&object->shadow_head); | robject = LIST_FIRST(&object->shadow_head); | ||||
KASSERT(robject != NULL, | KASSERT(robject != NULL, | ||||
("vm_object_deallocate: ref_count: %d, shadow_count: %d", | ("vm_object_deallocate: ref_count: %d, " | ||||
object->ref_count, | "shadow_count: %d", object->ref_count, | ||||
object->shadow_count)); | object->shadow_count)); | ||||
KASSERT((robject->flags & OBJ_TMPFS_NODE) == 0, | KASSERT((robject->flags & OBJ_TMPFS_NODE) == 0, | ||||
("shadowed tmpfs v_object %p", object)); | ("shadowed tmpfs v_object %p", object)); | ||||
if (!VM_OBJECT_TRYWLOCK(robject)) { | if (!VM_OBJECT_TRYWLOCK(robject)) { | ||||
/* | /* | ||||
* Avoid a potential deadlock. | * Avoid a potential deadlock. | ||||
*/ | */ | ||||
refcount_acquire(&object->ref_count); | refcount_acquire(&object->ref_count); | ||||
VM_OBJECT_WUNLOCK(object); | VM_OBJECT_WUNLOCK(object); | ||||
/* | /* | ||||
* More likely than not the thread | * More likely than not the thread | ||||
* holding robject's lock has lower | * holding robject's lock has lower | ||||
* priority than the current thread. | * priority than the current thread. | ||||
* Let the lower priority thread run. | * Let the lower priority thread run. | ||||
*/ | */ | ||||
pause("vmo_de", 1); | pause("vmo_de", 1); | ||||
continue; | continue; | ||||
} | } | ||||
/* | /* | ||||
* Collapse object into its shadow unless its | * Collapse object into its shadow unless its | ||||
* shadow is dead. In that case, object will | * shadow is dead. In that case, object will | ||||
* be deallocated by the thread that is | * be deallocated by the thread that is | ||||
* deallocating its shadow. | * deallocating its shadow. | ||||
*/ | */ | ||||
if ((robject->flags & | if ((robject->flags & | ||||
(OBJ_DEAD | OBJ_ANON)) == OBJ_ANON && | (OBJ_DEAD | OBJ_ANON)) == OBJ_ANON) { | ||||
robject->handle == NULL) { | |||||
refcount_acquire(&robject->ref_count); | refcount_acquire(&robject->ref_count); | ||||
retry: | retry: | ||||
if (REFCOUNT_COUNT(robject->paging_in_progress) > 0) { | if (REFCOUNT_COUNT(robject->paging_in_progress) > 0) { | ||||
VM_OBJECT_WUNLOCK(object); | VM_OBJECT_WUNLOCK(object); | ||||
vm_object_pip_wait(robject, | vm_object_pip_wait(robject, | ||||
"objde1"); | "objde1"); | ||||
temp = robject->backing_object; | temp = robject->backing_object; | ||||
▲ Show 20 Lines • Show All 682 Lines • ▼ Show 20 Lines | vm_object_shadow( | ||||
* Don't create the new object if the old object isn't shared. | * Don't create the new object if the old object isn't shared. | ||||
* | * | ||||
* If we hold the only reference we can guarantee that it won't | * If we hold the only reference we can guarantee that it won't | ||||
* increase while we have the map locked. Otherwise the race is | * increase while we have the map locked. Otherwise the race is | ||||
* harmless and we will end up with an extra shadow object that | * harmless and we will end up with an extra shadow object that | ||||
* will be collapsed later. | * will be collapsed later. | ||||
*/ | */ | ||||
if (source != NULL && source->ref_count == 1 && | if (source != NULL && source->ref_count == 1 && | ||||
source->handle == NULL && (source->flags & OBJ_ANON) != 0) | (source->flags & OBJ_ANON) != 0) | ||||
return; | return; | ||||
/* | /* | ||||
* Allocate a new object with the given length. | * Allocate a new object with the given length. | ||||
*/ | */ | ||||
result = vm_object_allocate_anon(atop(length)); | result = vm_object_allocate_anon(atop(length)); | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 432 Lines • ▼ Show 20 Lines | while (TRUE) { | ||||
/* | /* | ||||
* we check the backing object first, because it is most likely | * we check the backing object first, because it is most likely | ||||
* not collapsable. | * not collapsable. | ||||
*/ | */ | ||||
if ((backing_object->flags & OBJ_ANON) == 0) | if ((backing_object->flags & OBJ_ANON) == 0) | ||||
break; | break; | ||||
VM_OBJECT_WLOCK(backing_object); | VM_OBJECT_WLOCK(backing_object); | ||||
if (backing_object->handle != NULL || | if ((backing_object->flags & OBJ_DEAD) != 0 || | ||||
(backing_object->flags & OBJ_DEAD) != 0 || | (object->flags & (OBJ_DEAD | OBJ_ANON)) != OBJ_ANON) { | ||||
object->handle != NULL || | |||||
(object->flags & OBJ_DEAD) != 0) { | |||||
VM_OBJECT_WUNLOCK(backing_object); | VM_OBJECT_WUNLOCK(backing_object); | ||||
break; | break; | ||||
} | } | ||||
if (REFCOUNT_COUNT(object->paging_in_progress) > 0 || | if (REFCOUNT_COUNT(object->paging_in_progress) > 0 || | ||||
REFCOUNT_COUNT(backing_object->paging_in_progress) > 0) { | REFCOUNT_COUNT(backing_object->paging_in_progress) > 0) { | ||||
vm_object_qcollapse(object); | vm_object_qcollapse(object); | ||||
VM_OBJECT_WUNLOCK(backing_object); | VM_OBJECT_WUNLOCK(backing_object); | ||||
▲ Show 20 Lines • Show All 778 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
vm_object_t object; | vm_object_t object; | ||||
/* | /* | ||||
* make sure that internal objs are in a map somewhere | * make sure that internal objs are in a map somewhere | ||||
* and none have zero ref counts. | * and none have zero ref counts. | ||||
*/ | */ | ||||
TAILQ_FOREACH(object, &vm_object_list, object_list) { | TAILQ_FOREACH(object, &vm_object_list, object_list) { | ||||
if (object->handle == NULL && | if ((object->flags & OBJ_ANON) != 0) { | ||||
(object->type == OBJT_DEFAULT || object->type == OBJT_SWAP)) { | |||||
if (object->ref_count == 0) { | if (object->ref_count == 0) { | ||||
db_printf("vmochk: internal obj has zero ref count: %ld\n", | db_printf("vmochk: internal obj has zero ref count: %ld\n", | ||||
(long)object->size); | (long)object->size); | ||||
} | } | ||||
if (!vm_object_in_map(object)) { | if (!vm_object_in_map(object)) { | ||||
db_printf( | db_printf( | ||||
"vmochk: internal obj is not in a map: " | "vmochk: internal obj is not in a map: " | ||||
"ref: %d, size: %lu: 0x%lx, backing_object: %p\n", | "ref: %d, size: %lu: 0x%lx, backing_object: %p\n", | ||||
▲ Show 20 Lines • Show All 148 Lines • Show Last 20 Lines |