[PATCH 13] exit_ptrace: use ptrace_do_detach()

Oleg Nesterov oleg at redhat.com
Sat Aug 22 18:58:38 UTC 2009


Change exit_ptrace() to use ptrace_do_detach() and kill now unused
ptrace_utrace_exit().

This means we can't iterate over ->ptraced (the current code does this
twice) under tasklist, change the code to pick tracees by one and do
get/put on task_struct.

With this patch, exit_ptrace() does ptrace_unlink() then UTRACE_DETACH.
But currently  this is not exactly correct too. Unlike ptrace_detach(),
exit_ptrace() can be called when the tracee is running, if it calls
utrace_stop() before UTRACE_DETACH we will notify ->real_parent.
Hopefully this will be fixed when we change the ptrace-related kludge
in utrace_stop().

---

 kernel/ptrace.c |   40 +++++++++++++++-------------------------
 1 file changed, 15 insertions(+), 25 deletions(-)

--- PU/kernel/ptrace.c~13_REWORK_EXIT_PTRACE	2009-08-22 20:08:23.000000000 +0200
+++ PU/kernel/ptrace.c	2009-08-22 20:31:26.000000000 +0200
@@ -751,7 +751,8 @@ static void ptrace_do_detach(struct task
 	 */
 	traced = tracee->ptrace;
 	if (likely(traced)) {
-		tracee->exit_code = data;
+		if (valid_signal(data))
+			tracee->exit_code = data;
 		dead = __ptrace_detach(current, tracee);
 	}
 	write_unlock_irq(&tasklist_lock);
@@ -776,37 +777,26 @@ int ptrace_detach(struct task_struct *ch
 	return 0;
 }
 
-static void ptrace_utrace_exit(struct task_struct *task)
-{
-	struct task_struct *child;
-	read_lock(&tasklist_lock);
-	list_for_each_entry(child, &task->ptraced, ptrace_entry)
-		ptrace_detach_task(child, 0);
-	read_unlock(&tasklist_lock);
-}
-
 /*
  * Detach all tasks we were using ptrace on.
  */
 void exit_ptrace(struct task_struct *tracer)
 {
-	struct task_struct *p, *n;
-	LIST_HEAD(ptrace_dead);
-
-	ptrace_utrace_exit(tracer);
-
-	write_lock_irq(&tasklist_lock);
-	list_for_each_entry_safe(p, n, &tracer->ptraced, ptrace_entry) {
-		if (__ptrace_detach(tracer, p))
-			list_add(&p->ptrace_entry, &ptrace_dead);
-	}
-	write_unlock_irq(&tasklist_lock);
+	for (;;) {
+		struct task_struct *tracee = NULL;
 
-	BUG_ON(!list_empty(&tracer->ptraced));
+		read_lock(&tasklist_lock);
+		if (!list_empty(&tracer->ptraced)) {
+			tracee = list_first_entry(&tracer->ptraced,
+					struct task_struct, ptrace_entry);
+			get_task_struct(tracee);
+		}
+		read_unlock(&tasklist_lock);
+		if (!tracee)
+			break;
 
-	list_for_each_entry_safe(p, n, &ptrace_dead, ptrace_entry) {
-		list_del_init(&p->ptrace_entry);
-		release_task(p);
+		ptrace_do_detach(tracee, -1);
+		put_task_struct(tracee);
 	}
 }
 




More information about the utrace-devel mailing list