summaryrefslogtreecommitdiff
path: root/debian/patches
diff options
context:
space:
mode:
authorJustus Winter <4winter@informatik.uni-hamburg.de>2015-08-17 16:23:35 +0200
committerJustus Winter <4winter@informatik.uni-hamburg.de>2015-08-17 16:23:35 +0200
commit45d879095b37af88af8c1b18ae28b4a1a17c48bf (patch)
treeebe704426bc1a734c90bbf345919e1bf715d3795 /debian/patches
parent614bdbf121888c390a4e9b4291d5e30a4932bf75 (diff)
add patch series
Diffstat (limited to 'debian/patches')
-rw-r--r--debian/patches/fix-locking0001-kern-disable-the-simple-lock-checks-while-debugging.patch107
-rw-r--r--debian/patches/fix-locking0002-kern-improve-simple-lock-debugging.patch133
-rw-r--r--debian/patches/fix-locking0003-kern-keep-track-of-the-writer-when-debugging-locks.patch163
-rw-r--r--debian/patches/fix-locking0004-vm-fix-locking-issues.patch586
-rw-r--r--debian/patches/series4
5 files changed, 993 insertions, 0 deletions
diff --git a/debian/patches/fix-locking0001-kern-disable-the-simple-lock-checks-while-debugging.patch b/debian/patches/fix-locking0001-kern-disable-the-simple-lock-checks-while-debugging.patch
new file mode 100644
index 0000000..b8e22e0
--- /dev/null
+++ b/debian/patches/fix-locking0001-kern-disable-the-simple-lock-checks-while-debugging.patch
@@ -0,0 +1,107 @@
+From bdc9b8583e6336bb3a44a80f10bac8b7b369719c Mon Sep 17 00:00:00 2001
+From: Justus Winter <4winter@informatik.uni-hamburg.de>
+Date: Sat, 15 Aug 2015 16:43:24 +0200
+Subject: [PATCH gnumach 1/4] kern: disable the simple lock checks while
+ debugging
+
+* kern/lock.c (do_check_simple_locks): New variable.
+(check_simple_locks): Make check conditional.
+(check_simple_locks_{en,dis}able): New functions.
+* kern/lock.h (check_simple_locks_{en,dis}able): New declarations.
+* ddb/db_trap.c (db_task_trap): Disable simple lock checks.
+---
+ ddb/db_trap.c | 4 ++++
+ kern/lock.c | 14 +++++++++++++-
+ kern/lock.h | 6 ++++++
+ 3 files changed, 23 insertions(+), 1 deletion(-)
+
+diff --git a/ddb/db_trap.c b/ddb/db_trap.c
+index 7e10731..cbb6bde 100644
+--- a/ddb/db_trap.c
++++ b/ddb/db_trap.c
+@@ -45,6 +45,7 @@
+ #include <ddb/db_trap.h>
+ #include <ddb/db_run.h>
+ #include <machine/db_interface.h>
++#include <kern/lock.h>
+
+
+ extern jmp_buf_t *db_recover;
+@@ -65,6 +66,8 @@ db_task_trap(
+ boolean_t watchpt;
+ task_t task_space;
+
++ check_simple_locks_disable();
++
+ task_space = db_target_space(current_thread(), user_space);
+ bkpt = IS_BREAKPOINT_TRAP(type, code);
+ watchpt = IS_WATCHPOINT_TRAP(type, code);
+@@ -97,6 +100,7 @@ db_task_trap(
+ db_command_loop();
+ }
+
++ check_simple_locks_enable();
+ db_restart_at_pc(watchpt, task_space);
+ }
+
+diff --git a/kern/lock.c b/kern/lock.c
+index 3c74fec..d894b06 100644
+--- a/kern/lock.c
++++ b/kern/lock.c
+@@ -136,9 +136,21 @@ struct simple_locks_info {
+ void *ra;
+ } simple_locks_info[NSLINFO];
+
++int do_check_simple_locks = 1;
++
+ void check_simple_locks(void)
+ {
+- assert(simple_locks_taken == 0);
++ assert(! do_check_simple_locks || simple_locks_taken == 0);
++}
++
++void check_simple_locks_enable(void)
++{
++ do_check_simple_locks = 1;
++}
++
++void check_simple_locks_disable(void)
++{
++ do_check_simple_locks = 0;
+ }
+
+ /* Need simple lock sanity checking code if simple locks are being
+diff --git a/kern/lock.h b/kern/lock.h
+index 435ee1d..0eba0ad 100644
+--- a/kern/lock.h
++++ b/kern/lock.h
+@@ -81,6 +81,8 @@ class simple_lock_data_t name;
+ #define simple_lock_taken(lock) (simple_lock_assert(lock), \
+ 1) /* always succeeds */
+ #define check_simple_locks()
++#define check_simple_locks_enable()
++#define check_simple_locks_disable()
+
+ #else /* NCPUS > 1 */
+ /*
+@@ -97,6 +99,8 @@ extern boolean_t simple_lock_try(simple_lock_t);
+ (lock)->lock_data)
+
+ extern void check_simple_locks(void);
++extern void check_simple_locks_enable(void);
++extern void check_simple_locks_disable(void);
+
+ #endif /* NCPUS > 1 */
+
+@@ -121,6 +125,8 @@ class struct simple_lock_data_empty name;
+ #define simple_lock_taken(l) (simple_lock_assert(l), \
+ 1) /* always succeeds */
+ #define check_simple_locks()
++#define check_simple_locks_enable()
++#define check_simple_locks_disable()
+ #define simple_lock_pause()
+
+ #endif /* MACH_SLOCKS */
+--
+2.1.4
+
diff --git a/debian/patches/fix-locking0002-kern-improve-simple-lock-debugging.patch b/debian/patches/fix-locking0002-kern-improve-simple-lock-debugging.patch
new file mode 100644
index 0000000..ceaced4
--- /dev/null
+++ b/debian/patches/fix-locking0002-kern-improve-simple-lock-debugging.patch
@@ -0,0 +1,133 @@
+From 347cb29151859a56a6c5f0f355a43033e5e035a5 Mon Sep 17 00:00:00 2001
+From: Justus Winter <4winter@informatik.uni-hamburg.de>
+Date: Sat, 15 Aug 2015 17:04:08 +0200
+Subject: [PATCH gnumach 2/4] kern: improve simple lock debugging
+
+Do not bother saving the return address when acquire a simple lock.
+Save the location as provided by the compiler as string instead. Also
+save the lock parameter.
+
+* kern/lock.c (struct simple_locks_info): Drop `ra', add `expr', `loc'.
+(simple_lock): Rename to `_simple_lock', add expression and location
+parameters and save them.
+(simple_lock_try): Likewise.
+(simple_unlock): Zero-out the now unused slot in the list of taken locks.
+(db_show_all_slocks): Use the new information.
+* kern/lock.h (simple_lock, simple_lock_try): Provide macro versions
+passing the location and expression as string.
+---
+ kern/lock.c | 32 +++++++++++++++++---------------
+ kern/lock.h | 15 +++++++++++++--
+ 2 files changed, 30 insertions(+), 17 deletions(-)
+
+diff --git a/kern/lock.c b/kern/lock.c
+index d894b06..de22795 100644
+--- a/kern/lock.c
++++ b/kern/lock.c
+@@ -133,7 +133,8 @@ unsigned int simple_locks_taken = 0;
+
+ struct simple_locks_info {
+ simple_lock_t l;
+- void *ra;
++ const char *expr;
++ const char *loc;
+ } simple_locks_info[NSLINFO];
+
+ int do_check_simple_locks = 1;
+@@ -162,8 +163,10 @@ void simple_lock_init(
+ l->lock_data = 0;
+ }
+
+-void simple_lock(
+- simple_lock_t l)
++void _simple_lock(
++ simple_lock_t l,
++ const char *expression,
++ const char *location)
+ {
+ struct simple_locks_info *info;
+
+@@ -173,12 +176,14 @@ void simple_lock(
+
+ info = &simple_locks_info[simple_locks_taken++];
+ info->l = l;
+- info->ra =
+- __builtin_extract_return_addr (__builtin_return_address (0));
++ info->expr = expression;
++ info->loc = location;
+ }
+
+-boolean_t simple_lock_try(
+- simple_lock_t l)
++boolean_t _simple_lock_try(
++ simple_lock_t l,
++ const char *expression,
++ const char *location)
+ {
+ struct simple_locks_info *info;
+
+@@ -189,8 +194,8 @@ boolean_t simple_lock_try(
+
+ info = &simple_locks_info[simple_locks_taken++];
+ info->l = l;
+- info->ra =
+- __builtin_extract_return_addr (__builtin_return_address (0));
++ info->expr = expression;
++ info->loc = location;
+
+ return TRUE;
+ }
+@@ -214,6 +219,7 @@ void simple_unlock(
+
+ simple_locks_info[i] = simple_locks_info[simple_locks_taken-1];
+ }
++ simple_locks_info[simple_locks_taken] = (struct simple_locks_info) {0};
+ simple_locks_taken--;
+ }
+
+@@ -628,13 +634,9 @@ void db_show_all_slocks(void)
+
+ for (i = 0; i < simple_locks_taken; i++) {
+ info = &simple_locks_info[i];
+- db_printf("%d: ", i);
++ db_printf("%d: %s (", i, info->expr);
+ db_printsym(info->l, DB_STGY_ANY);
+-#if defined(__i386__)
+- db_printf(" locked by ");
+- db_printsym(info->ra, DB_STGY_PROC);
+-#endif
+- db_printf("\n");
++ db_printf(") locked by %s\n", info->loc);
+ }
+ }
+ #else /* MACH_SLOCKS && NCPUS == 1 */
+diff --git a/kern/lock.h b/kern/lock.h
+index 0eba0ad..e88e182 100644
+--- a/kern/lock.h
++++ b/kern/lock.h
+@@ -90,9 +90,20 @@ class simple_lock_data_t name;
+ */
+
+ extern void simple_lock_init(simple_lock_t);
+-extern void simple_lock(simple_lock_t);
++extern void _simple_lock(simple_lock_t,
++ const char *, const char *);
+ extern void simple_unlock(simple_lock_t);
+-extern boolean_t simple_lock_try(simple_lock_t);
++extern boolean_t _simple_lock_try(simple_lock_t,
++ const char *, const char *);
++
++/* We provide simple_lock and simple_lock_try so that we can save the
++ location. */
++#define XSTR(x) #x
++#define STR(x) XSTR(x)
++#define LOCATION __FILE__ ":" STR(__LINE__)
++
++#define simple_lock(lock) _simple_lock((lock), #lock, LOCATION)
++#define simple_lock_try(lock) _simple_lock_try((lock), #lock, LOCATION)
+
+ #define simple_lock_pause()
+ #define simple_lock_taken(lock) (simple_lock_assert(lock), \
+--
+2.1.4
+
diff --git a/debian/patches/fix-locking0003-kern-keep-track-of-the-writer-when-debugging-locks.patch b/debian/patches/fix-locking0003-kern-keep-track-of-the-writer-when-debugging-locks.patch
new file mode 100644
index 0000000..3e54766
--- /dev/null
+++ b/debian/patches/fix-locking0003-kern-keep-track-of-the-writer-when-debugging-locks.patch
@@ -0,0 +1,163 @@
+From e6c6e15b03639e98df68df35ba0f639bdbc1dc51 Mon Sep 17 00:00:00 2001
+From: Justus Winter <4winter@informatik.uni-hamburg.de>
+Date: Sat, 15 Aug 2015 18:30:28 +0200
+Subject: [PATCH gnumach 3/4] kern: keep track of the writer when debugging
+ locks
+
+* configfrag.ac (MACH_LDEBUG): Adjust comment, we use it to sanity
+check all locks now.
+* kern/lock.c (lock_write): Keep track of the writer thread.
+(lock_done): Clear writer.
+(lock_read_to_write): Keep track of the writer thread.
+(lock_write_to_read): Assert that the current thread holds the lock.
+Clear writer.
+(lock_try_write): Keep track of the writer thread.
+(lock_try_read_to_write): Likewise.
+(lock_set_recursive): Assert that the current thread holds the lock.
+* kern/lock.h (struct lock): New field `writer'.
+(have_read_lock, have_write_lock, have_lock): New macros that can be
+used to assert that the current thread holds the given lock. If
+MACH_LDEBUG is not set, they evaluate to true.
+---
+ configfrag.ac | 2 +-
+ kern/lock.c | 28 +++++++++++++++++++++++++++-
+ kern/lock.h | 14 ++++++++++++++
+ 3 files changed, 42 insertions(+), 2 deletions(-)
+
+diff --git a/configfrag.ac b/configfrag.ac
+index e41a3a1..c0e04b3 100644
+--- a/configfrag.ac
++++ b/configfrag.ac
+@@ -63,7 +63,7 @@ AC_DEFINE([MACH_IPC_DEBUG], [1], [MACH_IPC_DEBUG])
+ # Testing code/printfs.
+ AC_DEFINE([MACH_IPC_TEST], [0], [MACH_IPC_TEST])
+
+-# Sanity-check simple locking.
++# Sanity-check locking.
+ AC_DEFINE([MACH_LDEBUG], [0], [MACH_LDEBUG])
+
+ # MP lock monitoring. Registers use of locks, contention. Depending on
+diff --git a/kern/lock.c b/kern/lock.c
+index de22795..46c78da 100644
+--- a/kern/lock.c
++++ b/kern/lock.c
+@@ -318,6 +318,9 @@ void lock_write(
+ simple_lock(&l->interlock);
+ }
+ }
++#if MACH_LDEBUG
++ l->writer = current_thread();
++#endif /* MACH_LDEBUG */
+ simple_unlock(&l->interlock);
+ }
+
+@@ -334,8 +337,12 @@ void lock_done(
+ else
+ if (l->want_upgrade)
+ l->want_upgrade = FALSE;
+- else
++ else {
+ l->want_write = FALSE;
++#if MACH_LDEBUG
++ l->writer = THREAD_NULL;
++#endif /* MACH_LDEBUG */
++ }
+
+ /*
+ * There is no reason to wakeup a waiting thread
+@@ -452,6 +459,9 @@ boolean_t lock_read_to_write(
+ }
+ }
+
++#if MACH_LDEBUG
++ l->writer = current_thread();
++#endif /* MACH_LDEBUG */
+ simple_unlock(&l->interlock);
+ return FALSE;
+ }
+@@ -460,6 +470,9 @@ void lock_write_to_read(
+ lock_t l)
+ {
+ simple_lock(&l->interlock);
++#if MACH_LDEBUG
++ assert(l->writer == current_thread());
++#endif /* MACH_LDEBUG */
+
+ l->read_count++;
+ if (l->recursion_depth != 0)
+@@ -475,6 +488,9 @@ void lock_write_to_read(
+ thread_wakeup(l);
+ }
+
++#if MACH_LDEBUG
++ l->writer = THREAD_NULL;
++#endif /* MACH_LDEBUG */
+ simple_unlock(&l->interlock);
+ }
+
+@@ -514,6 +530,9 @@ boolean_t lock_try_write(
+ */
+
+ l->want_write = TRUE;
++#if MACH_LDEBUG
++ l->writer = current_thread();
++#endif /* MACH_LDEBUG */
+ simple_unlock(&l->interlock);
+ return TRUE;
+ }
+@@ -590,6 +609,9 @@ boolean_t lock_try_read_to_write(
+ simple_lock(&l->interlock);
+ }
+
++#if MACH_LDEBUG
++ l->writer = current_thread();
++#endif /* MACH_LDEBUG */
+ simple_unlock(&l->interlock);
+ return TRUE;
+ }
+@@ -602,6 +624,10 @@ void lock_set_recursive(
+ lock_t l)
+ {
+ simple_lock(&l->interlock);
++#if MACH_LDEBUG
++ assert(l->writer == current_thread());
++#endif /* MACH_LDEBUG */
++
+ if (!l->want_write) {
+ panic("lock_set_recursive: don't have write lock");
+ }
+diff --git a/kern/lock.h b/kern/lock.h
+index e88e182..2781a48 100644
+--- a/kern/lock.h
++++ b/kern/lock.h
+@@ -174,6 +174,9 @@ struct lock {
+ /* boolean_t */ can_sleep:1, /* Can attempts to lock go to sleep? */
+ recursion_depth:12, /* Depth of recursion */
+ :0;
++#if MACH_LDEBUG
++ struct thread *writer;
++#endif /* MACH_LDEBUG */
+ decl_simple_lock_data(,interlock)
+ /* Hardware interlock field.
+ Last in the structure so that
+@@ -203,6 +206,17 @@ extern boolean_t lock_try_read_to_write(lock_t);
+ extern void lock_set_recursive(lock_t);
+ extern void lock_clear_recursive(lock_t);
+
++/* Lock debugging support. */
++#if ! MACH_LDEBUG
++#define have_read_lock(l) 1
++#define have_write_lock(l) 1
++#else /* MACH_LDEBUG */
++/* XXX: We don't keep track of readers, so this is an approximation. */
++#define have_read_lock(l) ((l)->read_count > 0)
++#define have_write_lock(l) ((l)->writer == current_thread())
++#endif /* MACH_LDEBUG */
++#define have_lock(l) (have_read_lock(l) || have_write_lock(l))
++
+ void db_show_all_slocks(void);
+
+ #endif /* _KERN_LOCK_H_ */
+--
+2.1.4
+
diff --git a/debian/patches/fix-locking0004-vm-fix-locking-issues.patch b/debian/patches/fix-locking0004-vm-fix-locking-issues.patch
new file mode 100644
index 0000000..0de9159
--- /dev/null
+++ b/debian/patches/fix-locking0004-vm-fix-locking-issues.patch
@@ -0,0 +1,586 @@
+From 76a4bcc276ef16e01dced9a5b947f87a286d419c Mon Sep 17 00:00:00 2001
+From: Justus Winter <4winter@informatik.uni-hamburg.de>
+Date: Sun, 16 Aug 2015 12:54:41 +0200
+Subject: [PATCH gnumach 4/4] 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_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'.
+---
+ vm/memory_object.c | 17 +++++++----
+ vm/vm_fault.c | 39 +++++++++++++++++++------
+ vm/vm_map.c | 55 ++++++++++++++++++++++++-----------
+ vm/vm_object.c | 84 +++++++++++++++++++++++++++++++++++++-----------------
+ vm/vm_pageout.c | 9 ++----
+ 5 files changed, 141 insertions(+), 63 deletions(-)
+
+diff --git a/vm/memory_object.c b/vm/memory_object.c
+index 097ed23..0a07429 100644
+--- a/vm/memory_object.c
++++ b/vm/memory_object.c
+@@ -101,6 +101,7 @@ kern_return_t memory_object_data_supply(
+ vm_page_t *page_list;
+ boolean_t was_absent;
+ vm_map_copy_t orig_copy = data_copy;
++ pager_request_t pager_request;
+
+ /*
+ * Look for bogus arguments
+@@ -270,6 +271,7 @@ retry_lookup:
+ /*
+ * Send reply if one was requested.
+ */
++ pager_request = object->pager_request;
+ vm_object_paging_end(object);
+ vm_object_unlock(object);
+
+@@ -279,7 +281,7 @@ retry_lookup:
+ if (IP_VALID(reply_to)) {
+ memory_object_supply_completed(
+ reply_to, reply_to_type,
+- object->pager_request,
++ pager_request,
+ original_offset,
+ original_length,
+ result,
+@@ -788,7 +790,9 @@ MACRO_END
+ continue;
+
+ case MEMORY_OBJECT_LOCK_RESULT_MUST_CLEAN:
+- case MEMORY_OBJECT_LOCK_RESULT_MUST_RETURN:
++ case MEMORY_OBJECT_LOCK_RESULT_MUST_RETURN:;
++ vm_offset_t object_paging_offset;
++
+ /*
+ * The clean and return cases are similar.
+ *
+@@ -811,6 +815,7 @@ MACRO_END
+ PAGEOUT_PAGES;
+ }
+
++ object_paging_offset = object->paging_offset;
+ vm_object_unlock(object);
+
+ /*
+@@ -821,8 +826,7 @@ MACRO_END
+ if (new_object == VM_OBJECT_NULL) {
+ new_object = vm_object_allocate(original_size);
+ new_offset = 0;
+- paging_offset = m->offset +
+- object->paging_offset;
++ paging_offset = m->offset + object_paging_offset;
+ pageout_action = page_lock_result;
+ }
+
+@@ -831,7 +835,7 @@ MACRO_END
+ * new object.
+ */
+ m = vm_pageout_setup(m,
+- m->offset + object->paging_offset,
++ m->offset + object_paging_offset,
+ new_object,
+ new_offset,
+ should_flush);
+@@ -859,11 +863,12 @@ MACRO_END
+ }
+
+ if (IP_VALID(reply_to)) {
++ pager_request_t pager_request = object->pager_request;
+ vm_object_unlock(object);
+
+ /* consumes our naked send-once/send right for reply_to */
+ (void) memory_object_lock_completed(reply_to, reply_to_type,
+- object->pager_request, original_offset, original_size);
++ pager_request, original_offset, original_size);
+
+ vm_object_lock(object);
+ }
+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,
+diff --git a/vm/vm_map.c b/vm/vm_map.c
+index ae3ce21..9098dfd 100644
+--- a/vm/vm_map.c
++++ b/vm/vm_map.c
+@@ -1182,16 +1182,20 @@ kern_return_t vm_map_submap(
+
+ if ((entry->vme_start == start) && (entry->vme_end == end) &&
+ (!entry->is_sub_map) &&
+- ((object = entry->object.vm_object) == vm_submap_object) &&
+- (object->resident_page_count == 0) &&
+- (object->copy == VM_OBJECT_NULL) &&
+- (object->shadow == VM_OBJECT_NULL) &&
+- (!object->pager_created)) {
+- entry->object.vm_object = VM_OBJECT_NULL;
+- vm_object_deallocate(object);
+- entry->is_sub_map = TRUE;
+- vm_map_reference(entry->object.sub_map = submap);
+- result = KERN_SUCCESS;
++ ((object = entry->object.vm_object) == vm_submap_object)) {
++ vm_object_lock(object);
++ if ((object->resident_page_count == 0) &&
++ (object->copy == VM_OBJECT_NULL) &&
++ (object->shadow == VM_OBJECT_NULL) &&
++ (!object->pager_created)) {
++ vm_object_unlock(object);
++ entry->object.vm_object = VM_OBJECT_NULL;
++ vm_object_deallocate(object);
++ entry->is_sub_map = TRUE;
++ vm_map_reference(entry->object.sub_map = submap);
++ result = KERN_SUCCESS;
++ } else
++ vm_object_unlock(object);
+ }
+ vm_map_unlock(map);
+
+@@ -2122,6 +2126,7 @@ start_pass_1:
+ for (entry = tmp_entry;;) {
+ vm_size_t sub_size = (entry->vme_end - entry->vme_start);
+ vm_map_entry_t next = entry->vme_next;
++ vm_object_t object;
+
+ if ( ! (entry->protection & VM_PROT_WRITE)) {
+ vm_map_unlock(dst_map);
+@@ -2157,10 +2162,13 @@ start_pass_1:
+ /*
+ * Check for permanent objects in the destination.
+ */
+-
+- if ((entry->object.vm_object != VM_OBJECT_NULL) &&
+- !entry->object.vm_object->temporary)
+- contains_permanent_objects = TRUE;
++ object = entry->object.vm_object;
++ if ((object != VM_OBJECT_NULL)
++ && ! contains_permanent_objects) {
++ vm_object_lock(object);
++ contains_permanent_objects = object->temporary;
++ vm_object_unlock(object);
++ }
+
+ size -= sub_size;
+ entry = next;
+@@ -2220,6 +2228,7 @@ start_pass_1:
+ vm_map_entry_t copy_entry = vm_map_copy_first_entry(copy);
+ vm_size_t copy_size = (copy_entry->vme_end - copy_entry->vme_start);
+ vm_object_t object;
++ int temporary;
+
+ entry = tmp_entry;
+ size = (entry->vme_end - entry->vme_start);
+@@ -2275,8 +2284,15 @@ start_pass_1:
+ */
+
+ object = entry->object.vm_object;
++ temporary = 0;
++ if (object != VM_OBJECT_NULL) {
++ vm_object_lock(object);
++ temporary = object->temporary;
++ vm_object_unlock(object);
++ }
++
+ if (!entry->is_shared &&
+- ((object == VM_OBJECT_NULL) || object->temporary)) {
++ ((object == VM_OBJECT_NULL) || temporary)) {
+ vm_object_t old_object = entry->object.vm_object;
+ vm_offset_t old_offset = entry->offset;
+
+@@ -3219,11 +3235,15 @@ kern_return_t vm_map_copyin(
+ /*
+ * Attempt non-blocking copy-on-write optimizations.
+ */
+-
++ if (src_object)
++ vm_object_lock(src_object);
+ if (src_destroy &&
+ (src_object == VM_OBJECT_NULL ||
+ (src_object->temporary && !src_object->use_shared_copy)))
+ {
++ if (src_object)
++ vm_object_unlock(src_object);
++
+ /*
+ * If we are destroying the source, and the object
+ * is temporary, and not shared writable,
+@@ -3243,6 +3263,9 @@ kern_return_t vm_map_copyin(
+ goto CopySuccessful;
+ }
+
++ if (src_object)
++ vm_object_unlock(src_object);
++
+ if (!was_wired &&
+ vm_object_copy_temporary(
+ &new_entry->object.vm_object,
+diff --git a/vm/vm_object.c b/vm/vm_object.c
+index deac0c2..1d3e727 100644
+--- a/vm/vm_object.c
++++ b/vm/vm_object.c
+@@ -217,9 +217,11 @@ static void _vm_object_setup(
+ vm_size_t size)
+ {
+ *object = vm_object_template;
+- queue_init(&object->memq);
+ vm_object_lock_init(object);
++ vm_object_lock(object);
++ queue_init(&object->memq);
+ object->size = size;
++ vm_object_unlock(object);
+ }
+
+ vm_object_t _vm_object_allocate(
+@@ -244,8 +246,11 @@ vm_object_t vm_object_allocate(
+ port = ipc_port_alloc_kernel();
+ if (port == IP_NULL)
+ panic("vm_object_allocate");
++
++ vm_object_lock(object);
+ object->pager_name = port;
+ ipc_kobject_set(port, (ipc_kobject_t) object, IKOT_PAGING_NAME);
++ vm_object_unlock(object);
+
+ return object;
+ }
+@@ -540,6 +545,12 @@ void vm_object_terminate(
+ {
+ vm_page_t p;
+ vm_object_t shadow_object;
++ struct ipc_port *pager;
++ pager_request_t pager_request;
++ struct ipc_port *pager_name;
++#if MACH_PAGEMAP
++ vm_external_t existence_info;
++#endif /* MACH_PAGEMAP */
+
+ /*
+ * Make sure the object isn't already being terminated
+@@ -637,20 +648,26 @@ void vm_object_terminate(
+ * using memory_object_terminate.
+ */
+
++ /* Copy attributes while object is locked. */
++ pager = object->pager;
++ pager_request = object->pager_request;
++ pager_name = object->pager_name;
++#if MACH_PAGEMAP
++ existence_info = object->existence_info;
++#endif /* MACH_PAGEMAP */
++
+ vm_object_unlock(object);
+
+- if (object->pager != IP_NULL) {
++ if (pager != IP_NULL) {
+ /* consumes our rights for pager, pager_request, pager_name */
+- memory_object_release(object->pager,
+- object->pager_request,
+- object->pager_name);
+- } else if (object->pager_name != IP_NULL) {
++ memory_object_release(pager, pager_request, pager_name);
++ } else if (pager_name != IP_NULL) {
+ /* consumes our right for pager_name */
+- ipc_port_dealloc_kernel(object->pager_name);
++ ipc_port_dealloc_kernel(pager_name);
+ }
+
+ #if MACH_PAGEMAP
+- vm_external_destroy(object->existence_info);
++ vm_external_destroy(existence_info);
+ #endif /* MACH_PAGEMAP */
+
+ /*
+@@ -1474,14 +1491,11 @@ vm_object_t vm_object_copy_delayed(
+ * must be done carefully, to avoid deadlock.
+ */
+
+- /*
+- * Allocate a new copy object before locking, even
+- * though we may not need it later.
+- */
++ vm_object_lock(src_object);
+
+ new_copy = vm_object_allocate(src_object->size);
+
+- vm_object_lock(src_object);
++ vm_object_lock(new_copy);
+
+ /*
+ * See whether we can reuse the result of a previous
+@@ -1519,7 +1533,7 @@ vm_object_t vm_object_copy_delayed(
+ old_copy->ref_count++;
+ vm_object_unlock(old_copy);
+ vm_object_unlock(src_object);
+-
++ vm_object_unlock(new_copy);
+ vm_object_deallocate(new_copy);
+
+ return old_copy;
+@@ -1574,7 +1588,7 @@ vm_object_t vm_object_copy_delayed(
+ }
+
+ vm_object_unlock(src_object);
+-
++ vm_object_unlock(new_copy);
+ return new_copy;
+ }
+
+@@ -1711,6 +1725,8 @@ void vm_object_shadow(
+ if ((result = vm_object_allocate(length)) == VM_OBJECT_NULL)
+ panic("vm_object_shadow: no object for shadowing");
+
++ vm_object_lock(result);
++
+ /*
+ * The new object shadows the source object, adding
+ * a reference to it. Our caller changes his reference
+@@ -1733,6 +1749,7 @@ void vm_object_shadow(
+
+ *offset = 0;
+ *object = result;
++ vm_object_unlock(result);
+ }
+
+ /*
+@@ -2053,8 +2070,10 @@ restart:
+ object = (po == IKOT_PAGER) ? (vm_object_t) pager->ip_kobject
+ : VM_OBJECT_NULL;
+
+- if ((object != VM_OBJECT_NULL) && !must_init) {
++ if (object != VM_OBJECT_NULL)
+ vm_object_lock(object);
++
++ if ((object != VM_OBJECT_NULL) && !must_init) {
+ if (object->ref_count == 0) {
+ queue_remove(&vm_object_cached_list, object,
+ vm_object_t, cached_list);
+@@ -2062,10 +2081,9 @@ restart:
+ vm_object_cached_pages_update(-object->resident_page_count);
+ }
+ object->ref_count++;
+- vm_object_unlock(object);
+-
+ vm_stat.hits++;
+ }
++
+ assert((object == VM_OBJECT_NULL) || (object->ref_count > 0) ||
+ ((object->paging_in_progress != 0) && internal));
+
+@@ -2085,6 +2103,10 @@ restart:
+ return(object);
+
+ if (must_init) {
++ vm_size_t pager_size;
++ pager_request_t pager_request;
++ struct ipc_port *pager_name;
++
+ /*
+ * Copy the naked send right we were given.
+ */
+@@ -2112,6 +2134,11 @@ restart:
+ * Let the pager know we're using it.
+ */
+
++ /* Store attributes while we're holding the lock. */
++ pager_size = object->size;
++ pager_request = object->pager_request;
++ pager_name = object->pager_name;
++
+ if (internal) {
+ /* acquire a naked send right for the DMM */
+ ipc_port_t DMM = memory_manager_default_reference();
+@@ -2123,12 +2150,15 @@ restart:
+ /* default-pager objects are ready immediately */
+ object->pager_ready = TRUE;
+
++ /* Unlock object across call to memory manager. */
++ vm_object_unlock(object);
++
+ /* consumes the naked send right for DMM */
+ (void) memory_object_create(DMM,
+ pager,
+- object->size,
+- object->pager_request,
+- object->pager_name,
++ pager_size,
++ pager_request,
++ pager_name,
+ PAGE_SIZE);
+ } else {
+ /* the object is external and not temporary */
+@@ -2138,13 +2168,16 @@ restart:
+ /* user pager objects are not ready until marked so */
+ object->pager_ready = FALSE;
+
++ /* Unlock object across call to memory manager. */
++ vm_object_unlock(object);
++
+ (void) memory_object_init(pager,
+- object->pager_request,
+- object->pager_name,
++ pager_request,
++ pager_name,
+ PAGE_SIZE);
+-
+ }
+
++ /* Object was unlocked across call to memory manager. */
+ vm_object_lock(object);
+ object->pager_initialized = TRUE;
+
+@@ -2152,9 +2185,8 @@ restart:
+ object->pager_ready = TRUE;
+
+ vm_object_wakeup(object, VM_OBJECT_EVENT_INITIALIZED);
+- } else {
+- vm_object_lock(object);
+ }
++
+ /*
+ * [At this point, the object must be locked]
+ */
+diff --git a/vm/vm_pageout.c b/vm/vm_pageout.c
+index 51a6a0d..b676c7b 100644
+--- a/vm/vm_pageout.c
++++ b/vm/vm_pageout.c
+@@ -252,6 +252,8 @@ vm_pageout_setup(
+ vm_object_unlock(new_object);
+ }
+
++ vm_object_lock(old_object);
++
+ if (flush) {
+ /*
+ * Create a place-holder page where the old one was,
+@@ -262,7 +264,6 @@ vm_pageout_setup(
+ == VM_PAGE_NULL)
+ vm_page_more_fictitious();
+
+- vm_object_lock(old_object);
+ vm_page_lock_queues();
+ vm_page_remove(m);
+ vm_page_unlock_queues();
+@@ -281,8 +282,6 @@ vm_pageout_setup(
+ VM_EXTERNAL_STATE_EXISTS);
+ #endif /* MACH_PAGEMAP */
+
+- vm_object_unlock(old_object);
+-
+ vm_object_lock(new_object);
+
+ /*
+@@ -305,7 +304,6 @@ vm_pageout_setup(
+ */
+ vm_page_copy(m, new_m);
+
+- vm_object_lock(old_object);
+ m->dirty = FALSE;
+ pmap_clear_modify(m->phys_addr);
+
+@@ -328,8 +326,6 @@ vm_pageout_setup(
+ VM_EXTERNAL_STATE_EXISTS);
+ #endif /* MACH_PAGEMAP */
+
+- vm_object_unlock(old_object);
+-
+ vm_object_lock(new_object);
+
+ /*
+@@ -383,6 +379,7 @@ vm_pageout_setup(
+ */
+
+ vm_object_unlock(new_object);
++ vm_object_unlock(old_object);
+
+ /*
+ * Return the placeholder page to simplify cleanup.
+--
+2.1.4
+
diff --git a/debian/patches/series b/debian/patches/series
index 029e46a..53a33d2 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -13,3 +13,7 @@ sysenter0001-yyy-sysenter-prototype.patch
vm-cache-policy0001-VM-cache-policy-change.patch
vm-cache-policy0002-vm-keep-track-of-clean-pages.patch
vm-cache-policy0003-vm-evict-clean-pages-first.patch
+fix-locking0001-kern-disable-the-simple-lock-checks-while-debugging.patch
+fix-locking0002-kern-improve-simple-lock-debugging.patch
+fix-locking0003-kern-keep-track-of-the-writer-when-debugging-locks.patch
+fix-locking0004-vm-fix-locking-issues.patch