Index: kernel/generic/src/cap/cap.c
===================================================================
--- kernel/generic/src/cap/cap.c	(revision 15d9fe658a0f05d8f11f65e26e719b38c268b096)
+++ kernel/generic/src/cap/cap.c	(revision c1f68b0b464a5358c1ef12ca16a6a4fb18b3ad5a)
@@ -148,5 +148,5 @@
 void caps_task_init(task_t *task)
 {
-	mutex_initialize(&task->cap_info->lock, MUTEX_PASSIVE);
+	mutex_initialize(&task->cap_info->lock, MUTEX_RECURSIVE);
 
 	for (kobject_type_t t = 0; t < KOBJECT_TYPE_MAX; t++)
@@ -238,5 +238,5 @@
 	if (cap->state == CAP_STATE_PUBLISHED && cap->kobject->ops->reclaim &&
 	    cap->kobject->ops->reclaim(cap->kobject)) {
-		kobject_t *kobj = cap_unpublish_locked(cap->task, cap->handle,
+		kobject_t *kobj = cap_unpublish(cap->task, cap->handle,
 		    cap->kobject->type);
 		kobject_put(kobj);
@@ -318,14 +318,21 @@
 }
 
-/** @copydoc cap_unpublish()
- *
- * Can only be called internally by the capability subsytem or from a
- * caps_apply_to_kobject_type() callback.
- */
-kobject_t *
-cap_unpublish_locked(task_t *task, cap_handle_t handle, kobject_type_t type)
+/** Unpublish published capability
+ *
+ * The kernel object is moved out of the capability. In other words, the
+ * capability's reference to the objects is handed over to the kernel object
+ * pointer returned by this function. Once unpublished, the capability does not
+ * refer to any kernel object anymore.
+ *
+ * @param task    Task in which to unpublish the capability.
+ * @param handle  Capability handle.
+ * @param type    Kernel object type of the object associated with the
+ *                capability.
+ */
+kobject_t *cap_unpublish(task_t *task, cap_handle_t handle, kobject_type_t type)
 {
 	kobject_t *kobj = NULL;
 
+	mutex_lock(&task->cap_info->lock);
 	cap_t *cap = cap_get(task, handle, CAP_STATE_PUBLISHED);
 	if (cap) {
@@ -338,40 +345,20 @@
 		}
 	}
+	mutex_unlock(&task->cap_info->lock);
 
 	return kobj;
 }
 
-/** Unpublish published capability
- *
- * The kernel object is moved out of the capability. In other words, the
- * capability's reference to the objects is handed over to the kernel object
- * pointer returned by this function. Once unpublished, the capability does not
- * refer to any kernel object anymore.
- *
- * @param task    Task in which to unpublish the capability.
+/** Free allocated capability
+ *
+ * @param task    Task in which to free the capability.
  * @param handle  Capability handle.
- * @param type    Kernel object type of the object associated with the
- *                capability.
- */
-kobject_t *cap_unpublish(task_t *task, cap_handle_t handle, kobject_type_t type)
-{
-
-	mutex_lock(&task->cap_info->lock);
-	kobject_t *kobj = cap_unpublish_locked(task, handle, type);
-	mutex_unlock(&task->cap_info->lock);
-
-	return kobj;
-}
-
-/** @copydoc cap_free()
- *
- * Can only be called internally by the capability subsytem or from a
- * caps_apply_to_kobject_type() callback.
- */
-void cap_free_locked(task_t *task, cap_handle_t handle)
+ */
+void cap_free(task_t *task, cap_handle_t handle)
 {
 	assert(handle >= 0);
 	assert(handle < MAX_CAPS);
 
+	mutex_lock(&task->cap_info->lock);
 	cap_t *cap = cap_get(task, handle, CAP_STATE_ALLOCATED);
 
@@ -381,15 +368,4 @@
 	ra_free(task->cap_info->handles, handle, 1);
 	slab_free(cap_slab, cap);
-}
-
-/** Free allocated capability
- *
- * @param task    Task in which to free the capability.
- * @param handle  Capability handle.
- */
-void cap_free(task_t *task, cap_handle_t handle)
-{
-	mutex_lock(&task->cap_info->lock);
-	cap_free_locked(task, handle);
 	mutex_unlock(&task->cap_info->lock);
 }
Index: kernel/generic/src/ipc/ipc.c
===================================================================
--- kernel/generic/src/ipc/ipc.c	(revision 15d9fe658a0f05d8f11f65e26e719b38c268b096)
+++ kernel/generic/src/ipc/ipc.c	(revision c1f68b0b464a5358c1ef12ca16a6a4fb18b3ad5a)
@@ -829,8 +829,8 @@
 {
 	ipc_phone_hangup(cap->kobject->phone);
-	kobject_t *kobj = cap_unpublish_locked(cap->task, cap->handle,
+	kobject_t *kobj = cap_unpublish(cap->task, cap->handle,
 	    KOBJECT_TYPE_PHONE);
 	kobject_put(kobj);
-	cap_free_locked(cap->task, cap->handle);
+	cap_free(cap->task, cap->handle);
 	return true;
 }
@@ -839,8 +839,4 @@
 {
 	ipc_irq_unsubscribe(&TASK->answerbox, cap->handle);
-	kobject_t *kobj = cap_unpublish_locked(cap->task, cap->handle,
-	    KOBJECT_TYPE_IRQ);
-	kobject_put(kobj);
-	cap_free_locked(cap->task, cap->handle);
 	return true;
 }
Index: kernel/generic/src/ipc/irq.c
===================================================================
--- kernel/generic/src/ipc/irq.c	(revision 15d9fe658a0f05d8f11f65e26e719b38c268b096)
+++ kernel/generic/src/ipc/irq.c	(revision c1f68b0b464a5358c1ef12ca16a6a4fb18b3ad5a)
@@ -271,7 +271,24 @@
 }
 
+static void irq_hash_out(irq_t *irq)
+{
+	irq_spinlock_lock(&irq_uspace_hash_table_lock, true);
+	irq_spinlock_lock(&irq->lock, false);
+	
+	if (irq->notif_cfg.hashed_in) {
+		/* Remove the IRQ from the uspace IRQ hash table. */
+		hash_table_remove_item(&irq_uspace_hash_table, &irq->link);
+		irq->notif_cfg.hashed_in = false;
+	}
+
+	irq_spinlock_unlock(&irq->lock, false);
+	irq_spinlock_unlock(&irq_uspace_hash_table_lock, true);
+}
+
 static void irq_destroy(void *arg)
 {
 	irq_t *irq = (irq_t *) arg;
+
+	irq_hash_out(irq);
 
 	/* Free up the IRQ code and associated structures. */
@@ -373,16 +390,5 @@
 	assert(kobj->irq->notif_cfg.answerbox == box);
 
-	irq_spinlock_lock(&irq_uspace_hash_table_lock, true);
-	irq_spinlock_lock(&kobj->irq->lock, false);
-	
-	if (kobj->irq->notif_cfg.hashed_in) {
-		/* Remove the IRQ from the uspace IRQ hash table. */
-		hash_table_remove_item(&irq_uspace_hash_table,
-		    &kobj->irq->link);
-		kobj->irq->notif_cfg.hashed_in = false;
-	}
-
-	irq_spinlock_unlock(&kobj->irq->lock, false);
-	irq_spinlock_unlock(&irq_uspace_hash_table_lock, true);
+	irq_hash_out(kobj->irq);
 
 	kobject_put(kobj);
