summaryrefslogtreecommitdiff
path: root/vm/vm_fault.c
diff options
context:
space:
mode:
authorJustus Winter <4winter@informatik.uni-hamburg.de>2015-08-16 12:54:41 +0200
committerJustus Winter <4winter@informatik.uni-hamburg.de>2015-09-14 14:45:05 +0200
commit22778b589af94261c2d8d0665220770d0b56d1a8 (patch)
tree97bdb1c058f030d30dfe0d566630010572a4fb35 /vm/vm_fault.c
parent81747ac6d3e846d1955edaa94dee9065e541b7d8 (diff)
vm: fix locking issues
Avoid accessing fields of `vm_object' objects without having it locked. These problems have been found using a code transformation done by Coccinelle that instrumented all accesses with a runtime check, and manual inspection. * vm/memory_object.c (memory_object_data_supply): Avoid accessing fields without the lock. * vm/vm_fault.c (vm_fault_page): Likewise. * vm/vm_map.c (vm_map_submap): Properly lock `object'. (vm_map_copy_overwrite): Avoid accessing fields without the lock. (vm_map_copyin): Lock `src_object'. * vm/vm_object.c (_vm_object_setup): Likewise. (vm_object_allocate): Likewise. (vm_object_terminate): Avoid accessing fields without the lock. (vm_object_copy_slowly): Lock `new_object'. (vm_object_copy_delayed): Lock `src_object' earlier, lock `new_copy'. (vm_object_shadow): Lock `result'. (vm_object_enter): Properly lock `object'. Avoid accessing fields without the lock. * vm/vm_pageout.c (vm_pageout_setup): Properly lock `old_object'.
Diffstat (limited to 'vm/vm_fault.c')
-rw-r--r--vm/vm_fault.c39
1 files changed, 30 insertions, 9 deletions
diff --git a/vm/vm_fault.c b/vm/vm_fault.c
index 46779f6..101ebce 100644
--- a/vm/vm_fault.c
+++ b/vm/vm_fault.c
@@ -229,6 +229,17 @@ vm_fault_return_t vm_fault_page(
boolean_t look_for_page;
vm_prot_t access_required;
+ /* We need to unlock an object before making requests to a
+ memory manager. We use this object to temporarily store
+ object attributes needed for the request to avoid accessing
+ the object while it is unlocked. */
+ struct
+ {
+ struct ipc_port * pager;
+ pager_request_t pager_request;
+ vm_offset_t paging_offset;
+ } obj;
+
if (resume) {
vm_fault_state_t *state =
(vm_fault_state_t *) current_thread()->ith_other;
@@ -510,11 +521,16 @@ vm_fault_return_t vm_fault_page(
new_unlock_request = m->unlock_request =
(access_required | m->unlock_request);
+ obj.pager = object->pager;
+ obj.pager_request =
+ object->pager_request;
+ obj.paging_offset =
+ object->paging_offset;
vm_object_unlock(object);
if ((rc = memory_object_data_unlock(
- object->pager,
- object->pager_request,
- offset + object->paging_offset,
+ obj.pager,
+ obj.pager_request,
+ offset + obj.paging_offset,
PAGE_SIZE,
new_unlock_request))
!= KERN_SUCCESS) {
@@ -633,6 +649,11 @@ vm_fault_return_t vm_fault_page(
m->absent = TRUE;
object->absent_count++;
+ /* Save attributes for the request. */
+ obj.pager = object->pager;
+ obj.pager_request = object->pager_request;
+ obj.paging_offset = object->paging_offset;
+
/*
* We have a busy page, so we can
* release the object lock.
@@ -647,16 +668,16 @@ vm_fault_return_t vm_fault_page(
vm_stat_sample(SAMPLED_PC_VM_PAGEIN_FAULTS);
current_task()->pageins++;
- if ((rc = memory_object_data_request(object->pager,
- object->pager_request,
- m->offset + object->paging_offset,
+ if ((rc = memory_object_data_request(obj.pager,
+ obj.pager_request,
+ m->offset + obj.paging_offset,
PAGE_SIZE, access_required)) != KERN_SUCCESS) {
if (rc != MACH_SEND_INTERRUPTED)
printf("%s(0x%p, 0x%p, 0x%lx, 0x%x, 0x%x) failed, %x\n",
"memory_object_data_request",
- object->pager,
- object->pager_request,
- m->offset + object->paging_offset,
+ obj.pager,
+ obj.pager_request,
+ m->offset + obj.paging_offset,
PAGE_SIZE, access_required, rc);
/*
* Don't want to leave a busy page around,