Index: kernel/generic/src/ipc/irq.c
===================================================================
--- kernel/generic/src/ipc/irq.c	(revision 13a638d3605c8d5aaaa69c1cba72bf0787e576fa)
+++ kernel/generic/src/ipc/irq.c	(revision 7afb4a53710d7b78f26a51c1825abc447de3ea5b)
@@ -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);
 		
