kernel -- vm_object locking: DEBUG_LOCKS check for hold_wait vs hold deadlock
authorVenkatesh Srinivas <me@endeavour.zapto.org>
Sun, 27 Mar 2011 14:20:20 +0000 (07:20 -0700)
committerVenkatesh Srinivas <me@endeavour.zapto.org>
Sun, 27 Mar 2011 14:20:20 +0000 (07:20 -0700)
If a thread has a hold on a vm_object and enters hold_wait (via either
vm_object_terminate or vm_object_collapse), it will wait forever for the hold
count to hit 0. Record the threads holding an object in a per-object array.

sys/vm/vm_object.c
sys/vm/vm_object.h

index 499a0a4..e227ccd 100644 (file)
@@ -1819,6 +1819,14 @@ vm_object_set_writeable_dirty(vm_object_t object)
 static void
 vm_object_lock_init(vm_object_t obj)
 {
+#if defined(DEBUG_LOCKS)
+       int i;
+
+       obj->debug_hold_bitmap = 0;
+       for (i = 0; i < VMOBJ_DEBUG_ARRAY_SIZE; i++) {
+               obj->debug_hold_thrs[i] = NULL;
+       }
+#endif
 }
 
 void
@@ -1839,6 +1847,18 @@ vm_object_hold(vm_object_t obj)
        vm_object_lock(obj);
 
        refcount_acquire(&obj->hold_count);
+
+#if defined(DEBUG_LOCKS)
+       int i;
+
+       i = ffs(~obj->debug_hold_bitmap) - 1;
+       if (i == -1) {
+               panic("vm_object hold count > VMOBJ_DEBUG_ARRAY_SIZE");
+       }
+
+       obj->debug_hold_bitmap |= (1 << i);
+       obj->debug_hold_thrs[i] = curthread;
+#endif
 }
 
 void
@@ -1846,6 +1866,24 @@ vm_object_drop(vm_object_t obj)
 {
        int rc;
 
+#if defined(DEBUG_LOCKS)
+       int found = 0;
+       int i;
+
+       for (i = 0; i < VMOBJ_DEBUG_ARRAY_SIZE; i++) {
+               if ((obj->debug_hold_bitmap & (1 << i)) &&
+                   (obj->debug_hold_thrs[i] == curthread)) {
+                       obj->debug_hold_bitmap &= ~(1 << i);
+                       obj->debug_hold_thrs[i] = NULL;
+                       found = 1;
+                       break;
+               }
+       }
+
+       if (found == 0)
+               panic("vm_object: attempt to drop hold on non-self-held obj");
+#endif
+
        rc = refcount_release(&obj->hold_count);
        vm_object_unlock(obj);
 
@@ -1864,6 +1902,16 @@ vm_object_hold_wait(vm_object_t obj)
 {
        vm_object_lock(obj);
 
+#if defined(DEBUG_LOCKS)
+       int i;
+
+       for (i = 0; i < VMOBJ_DEBUG_ARRAY_SIZE; i++) {
+               if ((obj->debug_hold_bitmap & (1 << i)) &&
+                   (obj->debug_hold_thrs[i] == curthread))
+                       panic("vm_object: self-hold in terminate or collapse");
+       }
+#endif
+
        while (obj->hold_count)
                tsleep(obj, 0, "vmobjhld", 0);
 
index cb29529..68769f2 100644 (file)
@@ -147,6 +147,17 @@ struct vm_object {
        void *handle;
        int hold_count;                 /* refcount for object liveness */
        
+#if defined(DEBUG_LOCKS)
+       /* 
+        * Record threads holding a vm_object
+        */
+
+#define VMOBJ_DEBUG_ARRAY_SIZE         (32)
+       u_int debug_hold_bitmap;
+       thread_t debug_hold_thrs[VMOBJ_DEBUG_ARRAY_SIZE];
+
+#endif
+
        union {
                /*
                 * Device pager