Index: kernel/generic/src/ddi/irq.c
===================================================================
--- kernel/generic/src/ddi/irq.c	(revision 13a638d3605c8d5aaaa69c1cba72bf0787e576fa)
+++ kernel/generic/src/ddi/irq.c	(revision ccf814f73c779a8626e11c6228a90af59620ace2)
@@ -102,9 +102,10 @@
 static index_t irq_ht_hash(unative_t *key);
 static bool irq_ht_compare(unative_t *key, count_t keys, link_t *item);
+static void irq_ht_remove(link_t *item);
 
 static hash_table_operations_t irq_ht_ops = {
 	.hash = irq_ht_hash,
 	.compare = irq_ht_compare,
-	.remove_callback = NULL		/* not used */
+	.remove_callback = irq_ht_remove,
 };
 
@@ -117,9 +118,10 @@
 static index_t irq_lin_hash(unative_t *key);
 static bool irq_lin_compare(unative_t *key, count_t keys, link_t *item);
+static void irq_lin_remove(link_t *item);
 
 static hash_table_operations_t irq_lin_ops = {
 	.hash = irq_lin_hash,
 	.compare = irq_lin_compare,
-	.remove_callback = NULL		/* not used */
+	.remove_callback = irq_lin_remove,
 };
 
@@ -348,4 +350,14 @@
 }
 
+/** Unlock IRQ structure after hash_table_remove().
+ *
+ * @param lnk		Link in the removed and locked IRQ structure.
+ */
+void irq_ht_remove(link_t *lnk)
+{
+	irq_t *irq = hash_table_get_instance(lnk, irq_t, link);
+	spinlock_unlock(&irq->lock);
+}
+
 /** Compute hash index for the key.
  *
@@ -407,4 +419,14 @@
 }
 
+/** Unlock IRQ structure after hash_table_remove().
+ *
+ * @param lnk		Link in the removed and locked IRQ structure.
+ */
+void irq_lin_remove(link_t *lnk)
+{
+	irq_t *irq = hash_table_get_instance(lnk, irq_t, link);
+	spinlock_unlock(&irq->lock);
+}
+
 /** @}
  */
Index: kernel/generic/src/ipc/irq.c
===================================================================
--- kernel/generic/src/ipc/irq.c	(revision 13a638d3605c8d5aaaa69c1cba72bf0787e576fa)
+++ kernel/generic/src/ipc/irq.c	(revision ccf814f73c779a8626e11c6228a90af59620ace2)
@@ -143,4 +143,5 @@
 	irq_code_t *code;
 	irq_t *irq;
+	link_t *hlp;
 	unative_t key[] = {
 		(unative_t) inr,
@@ -177,10 +178,10 @@
 	ipl = interrupts_disable();
 	spinlock_lock(&irq_uspace_hash_table_lock);
-	spinlock_lock(&irq->lock);
-	spinlock_lock(&box->irq_lock);
-	if (hash_table_find(&irq_uspace_hash_table, key)) {
+	hlp = hash_table_find(&irq_uspace_hash_table, key);
+	if (hlp) {
+		irq_t *hirq = hash_table_get_instance(hlp, irq_t, link);
+		/* hirq is locked */
+		spinlock_unlock(&hirq->lock);
 		code_free(code);
-		spinlock_unlock(&box->irq_lock);
-		spinlock_unlock(&irq->lock);
 		spinlock_unlock(&irq_uspace_hash_table_lock);
 		free(irq);
@@ -188,4 +189,6 @@
 		return EEXISTS;
 	}
+	spinlock_lock(&irq->lock);	/* not really necessary, but paranoid */
+	spinlock_lock(&box->irq_lock);
 	hash_table_insert(&irq_uspace_hash_table, key, &irq->link);
 	list_append(&irq->notif_cfg.link, &box->irq_head);
@@ -223,5 +226,5 @@
 	}
 	irq = hash_table_get_instance(lnk, irq_t, link);
-	spinlock_lock(&irq->lock);
+	/* irq is locked */
 	spinlock_lock(&box->irq_lock);
 	
@@ -234,9 +237,17 @@
 	list_remove(&irq->notif_cfg.link);
 
+	/*
+	 * We need to drop the IRQ lock now because hash_table_remove() will try
+	 * to reacquire it. That basically violates the natural locking order,
+	 * but a deadlock in hash_table_remove() is prevented by the fact that
+	 * we already held the IRQ lock and didn't drop the hash table lock in
+	 * the meantime.
+	 */
+	spinlock_unlock(&irq->lock);
+
 	/* Remove the IRQ from the uspace IRQ hash table. */
 	hash_table_remove(&irq_uspace_hash_table, key, 2);
 	
 	spinlock_unlock(&irq_uspace_hash_table_lock);
-	spinlock_unlock(&irq->lock);
 	spinlock_unlock(&box->irq_lock);
 	
@@ -295,4 +306,11 @@
 		code_free(irq->notif_cfg.code);
 		
+		/*
+		 * We need to drop the IRQ lock now because hash_table_remove()
+		 * will try to reacquire it. That basically violates the natural
+		 * locking order, but a deadlock in hash_table_remove() is
+		 * prevented by the fact that we already held the IRQ lock and
+		 * didn't drop the hash table lock in the meantime.
+		 */
 		spinlock_unlock(&irq->lock);
 		
