Commit 7c8bd2322c7fd973d089b27de55e29c92c667a06

Authored by Oleg Nesterov
Committed by Linus Torvalds
1 parent 2831096e21

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>

Showing 3 changed files with 8 additions and 27 deletions Side-by-side Diff

include/linux/ptrace.h
... ... @@ -52,7 +52,7 @@
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
... ... @@ -553,13 +553,11 @@
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;
... ... @@ -485,36 +485,19 @@
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 493  
498   - if (likely(list_empty(&tracer->ptraced)))
499   - return;
500   -
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)