Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

exit: ptrace: shift "reap dead" code from exit_ptrace() to forget_original_parent()

Now that forget_original_parent() uses ->ptrace_entry for EXIT_DEAD tasks,
we can simply pass "dead_children" list to exit_ptrace() and remove
another release_task() loop. Plus this way we do not need to drop and
reacquire tasklist_lock.

Also shift the list_empty(ptraced) check, if we want this optimization it
makes sense to eliminate the function call altogether.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Cc: Aaron Tomlin <atomlin@redhat.com>
Cc: Alexey Dobriyan <adobriyan@gmail.com>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>,
Cc: Sterling Alexander <stalexan@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Roland McGrath <roland@hack.frob.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Oleg Nesterov and committed by
Linus Torvalds
7c8bd232 2831096e

+8 -27
+1 -1
include/linux/ptrace.h
··· 52 52 extern void __ptrace_link(struct task_struct *child, 53 53 struct task_struct *new_parent); 54 54 extern void __ptrace_unlink(struct task_struct *child); 55 - extern void exit_ptrace(struct task_struct *tracer); 55 + extern void exit_ptrace(struct task_struct *tracer, struct list_head *dead); 56 56 #define PTRACE_MODE_READ 0x01 57 57 #define PTRACE_MODE_ATTACH 0x02 58 58 #define PTRACE_MODE_NOAUDIT 0x04
+4 -6
kernel/exit.c
··· 553 553 LIST_HEAD(dead_children); 554 554 555 555 write_lock_irq(&tasklist_lock); 556 - /* 557 - * Note that exit_ptrace() and find_new_reaper() might 558 - * drop tasklist_lock and reacquire it. 559 - */ 560 - exit_ptrace(father); 561 - reaper = find_new_reaper(father); 556 + if (unlikely(!list_empty(&father->ptraced))) 557 + exit_ptrace(father, &dead_children); 562 558 559 + /* Can drop and reacquire tasklist_lock */ 560 + reaper = find_new_reaper(father); 563 561 list_for_each_entry(p, &father->children, sibling) { 564 562 for_each_thread(p, t) { 565 563 t->real_parent = reaper;
+3 -20
kernel/ptrace.c
··· 485 485 486 486 /* 487 487 * Detach all tasks we were using ptrace on. Called with tasklist held 488 - * for writing, and returns with it held too. But note it can release 489 - * and reacquire the lock. 488 + * for writing. 490 489 */ 491 - void exit_ptrace(struct task_struct *tracer) 492 - __releases(&tasklist_lock) 493 - __acquires(&tasklist_lock) 490 + void exit_ptrace(struct task_struct *tracer, struct list_head *dead) 494 491 { 495 492 struct task_struct *p, *n; 496 - LIST_HEAD(ptrace_dead); 497 - 498 - if (likely(list_empty(&tracer->ptraced))) 499 - return; 500 493 501 494 list_for_each_entry_safe(p, n, &tracer->ptraced, ptrace_entry) { 502 495 if (unlikely(p->ptrace & PT_EXITKILL)) 503 496 send_sig_info(SIGKILL, SEND_SIG_FORCED, p); 504 497 505 498 if (__ptrace_detach(tracer, p)) 506 - list_add(&p->ptrace_entry, &ptrace_dead); 499 + list_add(&p->ptrace_entry, dead); 507 500 } 508 - 509 - write_unlock_irq(&tasklist_lock); 510 - BUG_ON(!list_empty(&tracer->ptraced)); 511 - 512 - list_for_each_entry_safe(p, n, &ptrace_dead, ptrace_entry) { 513 - list_del_init(&p->ptrace_entry); 514 - release_task(p); 515 - } 516 - 517 - write_lock_irq(&tasklist_lock); 518 501 } 519 502 520 503 int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len)