Only keep anonymous objects on shadow lists. This eliminates locking of

globally visible objects when they are part of a backing chain.

Reviewed by:	kib, markj
Differential Revision:	https://reviews.freebsd.org/D22423
This commit is contained in:
Jeff Roberson 2019-11-20 00:31:14 +00:00
parent 7f935055d3
commit 51b867e56b
2 changed files with 105 additions and 55 deletions

View File

@ -118,6 +118,7 @@ static boolean_t vm_object_page_remove_write(vm_page_t p, int flags,
boolean_t *allclean);
static void vm_object_qcollapse(vm_object_t object);
static void vm_object_vndeallocate(vm_object_t object);
static void vm_object_backing_remove(vm_object_t object);
/*
* Virtual memory objects maintain the actual data
@ -651,11 +652,7 @@ vm_object_deallocate(vm_object_t object)
if (temp != NULL) {
KASSERT((object->flags & OBJ_TMPFS_NODE) == 0,
("shadowed tmpfs v_object 2 %p", object));
VM_OBJECT_WLOCK(temp);
LIST_REMOVE(object, shadow_list);
temp->shadow_count--;
VM_OBJECT_WUNLOCK(temp);
object->backing_object = NULL;
vm_object_backing_remove(object);
}
/*
* Don't double-terminate, we could be in a termination
@ -695,6 +692,70 @@ vm_object_destroy(vm_object_t object)
uma_zfree(obj_zone, object);
}
static void
vm_object_backing_remove_locked(vm_object_t object)
{
vm_object_t backing_object;
backing_object = object->backing_object;
VM_OBJECT_ASSERT_WLOCKED(object);
VM_OBJECT_ASSERT_WLOCKED(backing_object);
if ((object->flags & OBJ_SHADOWLIST) != 0) {
LIST_REMOVE(object, shadow_list);
backing_object->shadow_count--;
object->flags &= ~OBJ_SHADOWLIST;
}
object->backing_object = NULL;
}
static void
vm_object_backing_remove(vm_object_t object)
{
vm_object_t backing_object;
VM_OBJECT_ASSERT_WLOCKED(object);
if ((object->flags & OBJ_SHADOWLIST) != 0) {
backing_object = object->backing_object;
VM_OBJECT_WLOCK(backing_object);
vm_object_backing_remove_locked(object);
VM_OBJECT_WUNLOCK(backing_object);
} else
object->backing_object = NULL;
}
static void
vm_object_backing_insert_locked(vm_object_t object, vm_object_t backing_object)
{
VM_OBJECT_ASSERT_WLOCKED(object);
if ((backing_object->flags & OBJ_ANON) != 0) {
VM_OBJECT_ASSERT_WLOCKED(backing_object);
LIST_INSERT_HEAD(&backing_object->shadow_head, object,
shadow_list);
backing_object->shadow_count++;
object->flags |= OBJ_SHADOWLIST;
}
object->backing_object = backing_object;
}
static void
vm_object_backing_insert(vm_object_t object, vm_object_t backing_object)
{
VM_OBJECT_ASSERT_WLOCKED(object);
if ((backing_object->flags & OBJ_ANON) != 0) {
VM_OBJECT_WLOCK(backing_object);
vm_object_backing_insert_locked(object, backing_object);
VM_OBJECT_WUNLOCK(backing_object);
} else
object->backing_object = backing_object;
}
/*
* vm_object_terminate_pages removes any remaining pageable pages
* from the object and resets the object to an empty state.
@ -1249,6 +1310,12 @@ vm_object_shadow(
*/
result = vm_object_allocate_anon(atop(length));
/*
* Store the offset into the source object, and fix up the offset into
* the new object.
*/
result->backing_object_offset = *offset;
/*
* The new object shadows the source object, adding a reference to it.
* Our caller changes his reference to point to the new object,
@ -1259,26 +1326,18 @@ vm_object_shadow(
* in order to maintain page coloring consistency in the combined
* shadowed object.
*/
result->backing_object = source;
/*
* Store the offset into the source object, and fix up the offset into
* the new object.
*/
result->backing_object_offset = *offset;
if (source != NULL) {
VM_OBJECT_WLOCK(source);
VM_OBJECT_WLOCK(result);
vm_object_backing_insert(result, source);
result->domain = source->domain;
LIST_INSERT_HEAD(&source->shadow_head, result, shadow_list);
source->shadow_count++;
#if VM_NRESERVLEVEL > 0
result->flags |= source->flags & OBJ_COLORED;
result->pg_color = (source->pg_color + OFF_TO_IDX(*offset)) &
((1 << (VM_NFREEORDER - 1)) - 1);
#endif
VM_OBJECT_WUNLOCK(source);
VM_OBJECT_WUNLOCK(result);
}
/*
* Return the new things
*/
@ -1326,24 +1385,26 @@ vm_object_split(vm_map_entry_t entry)
new_object->domain = orig_object->domain;
source = orig_object->backing_object;
if (source != NULL) {
VM_OBJECT_WLOCK(source);
if ((source->flags & OBJ_DEAD) != 0) {
if ((source->flags & (OBJ_ANON | OBJ_DEAD)) != 0) {
VM_OBJECT_WLOCK(source);
if ((source->flags & OBJ_DEAD) != 0) {
VM_OBJECT_WUNLOCK(source);
VM_OBJECT_WUNLOCK(orig_object);
VM_OBJECT_WUNLOCK(new_object);
vm_object_deallocate(new_object);
VM_OBJECT_WLOCK(orig_object);
return;
}
vm_object_backing_insert_locked(new_object, source);
vm_object_reference_locked(source); /* for new_object */
vm_object_clear_flag(source, OBJ_ONEMAPPING);
VM_OBJECT_WUNLOCK(source);
VM_OBJECT_WUNLOCK(orig_object);
VM_OBJECT_WUNLOCK(new_object);
vm_object_deallocate(new_object);
VM_OBJECT_WLOCK(orig_object);
return;
} else {
vm_object_backing_insert(new_object, source);
vm_object_reference(source);
}
LIST_INSERT_HEAD(&source->shadow_head,
new_object, shadow_list);
source->shadow_count++;
vm_object_reference_locked(source); /* for new_object */
vm_object_clear_flag(source, OBJ_ONEMAPPING);
VM_OBJECT_WUNLOCK(source);
new_object->backing_object_offset =
orig_object->backing_object_offset + entry->offset;
new_object->backing_object = source;
}
if (orig_object->cred != NULL) {
new_object->cred = orig_object->cred;
@ -1756,20 +1817,15 @@ vm_object_collapse(vm_object_t object)
* backing_object->backing_object moves from within
* backing_object to within object.
*/
LIST_REMOVE(object, shadow_list);
backing_object->shadow_count--;
if (backing_object->backing_object) {
VM_OBJECT_WLOCK(backing_object->backing_object);
LIST_REMOVE(backing_object, shadow_list);
LIST_INSERT_HEAD(
&backing_object->backing_object->shadow_head,
object, shadow_list);
/*
* The shadow_count has not changed.
*/
VM_OBJECT_WUNLOCK(backing_object->backing_object);
vm_object_backing_remove_locked(object);
new_backing_object = backing_object->backing_object;
if (new_backing_object != NULL) {
VM_OBJECT_WLOCK(new_backing_object);
vm_object_backing_remove_locked(backing_object);
vm_object_backing_insert_locked(object,
new_backing_object);
VM_OBJECT_WUNLOCK(new_backing_object);
}
object->backing_object = backing_object->backing_object;
object->backing_object_offset +=
backing_object->backing_object_offset;
@ -1807,20 +1863,13 @@ vm_object_collapse(vm_object_t object)
* chain. Deallocating backing_object will not remove
* it, since its reference count is at least 2.
*/
LIST_REMOVE(object, shadow_list);
backing_object->shadow_count--;
vm_object_backing_remove_locked(object);
new_backing_object = backing_object->backing_object;
if ((object->backing_object = new_backing_object) != NULL) {
VM_OBJECT_WLOCK(new_backing_object);
LIST_INSERT_HEAD(
&new_backing_object->shadow_head,
object,
shadow_list
);
new_backing_object->shadow_count++;
vm_object_reference_locked(new_backing_object);
VM_OBJECT_WUNLOCK(new_backing_object);
if (new_backing_object != NULL) {
vm_object_backing_insert(object,
new_backing_object);
vm_object_reference(new_backing_object);
object->backing_object_offset +=
backing_object->backing_object_offset;
}

View File

@ -192,6 +192,7 @@ struct vm_object {
#define OBJ_TMPFS_NODE 0x0200 /* object belongs to tmpfs VREG node */
#define OBJ_COLORED 0x1000 /* pg_color is defined */
#define OBJ_ONEMAPPING 0x2000 /* One USE (a single, non-forked) mapping flag */
#define OBJ_SHADOWLIST 0x4000 /* Object is on the shadow list. */
#define OBJ_TMPFS 0x8000 /* has tmpfs vnode allocated */
/*