diff options
author | alc <alc@FreeBSD.org> | 2007-03-27 08:55:17 +0000 |
---|---|---|
committer | alc <alc@FreeBSD.org> | 2007-03-27 08:55:17 +0000 |
commit | ecbefa2cc582770cbe525b558380fa91de7c1790 (patch) | |
tree | 1c8d43ff5e27c6d7516c25f0fbdedffedbf2c63d | |
parent | c93478d4b19976b89920cf5bd05cfcaa7f6a95f8 (diff) | |
download | FreeBSD-src-ecbefa2cc582770cbe525b558380fa91de7c1790.zip FreeBSD-src-ecbefa2cc582770cbe525b558380fa91de7c1790.tar.gz |
Prevent a race between vm_object_collapse() and vm_object_split() from
causing a crash.
Suppose that we have two objects, obj and backing_obj, where
backing_obj is obj's backing object. Further, suppose that
backing_obj has a reference count of two. One being the reference
held by obj and the other by a map entry. Now, suppose that the map
entry is deallocated and its reference removed by
vm_object_deallocate(). vm_object_deallocate() recognizes that the
only remaining reference is from a shadow object, obj, and calls
vm_object_collapse() on obj. vm_object_collapse() executes
if (backing_object->ref_count == 1) {
/*
* If there is exactly one reference to the backing
* object, we can collapse it into the parent.
*/
vm_object_backing_scan(object, OBSC_COLLAPSE_WAIT);
vm_object_backing_scan(OBSC_COLLAPSE_WAIT) executes
if (op & OBSC_COLLAPSE_WAIT) {
vm_object_set_flag(backing_object, OBJ_DEAD);
}
Finally, suppose that either vm_object_backing_scan() or
vm_object_collapse() sleeps releasing its locks. At this instant,
another thread executes vm_object_split(). It crashes in
vm_object_reference_locked() on the assertion that the object is not
dead. If, however, assertions are not enabled, it crashes much later,
after the object has been recycled, in vm_object_deallocate() because
the shadow count and shadow list are inconsistent.
Reviewed by: tegge
Reported by: jhb
MFC after: 1 week
-rw-r--r-- | sys/vm/vm_object.c | 8 |
1 files changed, 8 insertions, 0 deletions
diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c index e680a22..dfcade1 100644 --- a/sys/vm/vm_object.c +++ b/sys/vm/vm_object.c @@ -1317,6 +1317,14 @@ vm_object_split(vm_map_entry_t entry) source = orig_object->backing_object; if (source != NULL) { VM_OBJECT_LOCK(source); + if ((source->flags & OBJ_DEAD) != 0) { + VM_OBJECT_UNLOCK(source); + VM_OBJECT_UNLOCK(orig_object); + VM_OBJECT_UNLOCK(new_object); + vm_object_deallocate(new_object); + VM_OBJECT_LOCK(orig_object); + return; + } LIST_INSERT_HEAD(&source->shadow_head, new_object, shadow_list); source->shadow_count++; |