diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index b0f8da80d7d4..921c22ad16e4 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -155,8 +155,26 @@ int ptrace_attach(struct task_struct *task)
 	if (task->tgid == current->tgid)
 		goto out;
 
-	write_lock_irq(&tasklist_lock);
+repeat:
+	/*
+	 * Nasty, nasty.
+	 *
+	 * We want to hold both the task-lock and the
+	 * tasklist_lock for writing at the same time.
+	 * But that's against the rules (tasklist_lock
+	 * is taken for reading by interrupts on other
+	 * cpu's that may have task_lock).
+	 */
 	task_lock(task);
+	local_irq_disable();
+	if (!write_trylock(&tasklist_lock)) {
+		local_irq_enable();
+		task_unlock(task);
+		do {
+			cpu_relax();
+		} while (!write_can_lock(&tasklist_lock));
+		goto repeat;
+	}
 
 	/* the same process cannot be attached many times */
 	if (task->ptrace & PT_PTRACED)