diff options
| author | Oleg Nesterov <oleg@redhat.com> | 2014-12-10 15:45:33 -0800 |
|---|---|---|
| committer | Moyster <oysterized@gmail.com> | 2019-05-02 18:25:36 +0200 |
| commit | db5c059244b15491042e27d018c9c1860729e54a (patch) | |
| tree | 81ca5b72e66b7be5d50a777c58429af988d3b2f1 /kernel | |
| parent | 859af0b5efbbe7d139f348052abf9c4bbf505a8d (diff) | |
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.
Change-Id: I07b22f882fe7d5ec0bdc4f12d416992f96567610
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>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/exit.c | 10 | ||||
| -rw-r--r-- | kernel/ptrace.c | 23 |
2 files changed, 7 insertions, 26 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index cd141d0a1..4dbad0f93 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -556,13 +556,11 @@ static void forget_original_parent(struct task_struct *father) LIST_HEAD(dead_children); write_lock_irq(&tasklist_lock); - /* - * Note that exit_ptrace() and find_new_reaper() might - * drop tasklist_lock and reacquire it. - */ - exit_ptrace(father); - reaper = find_new_reaper(father); + if (unlikely(!list_empty(&father->ptraced))) + exit_ptrace(father, &dead_children); + /* Can drop and reacquire tasklist_lock */ + reaper = find_new_reaper(father); list_for_each_entry(p, &father->children, sibling) { for_each_thread(p, t) { t->real_parent = reaper; diff --git a/kernel/ptrace.c b/kernel/ptrace.c index d34c05ac6..48f6ef448 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -520,36 +520,19 @@ static int ptrace_detach(struct task_struct *child, unsigned int data) /* * Detach all tasks we were using ptrace on. Called with tasklist held - * for writing, and returns with it held too. But note it can release - * and reacquire the lock. + * for writing. */ -void exit_ptrace(struct task_struct *tracer) - __releases(&tasklist_lock) - __acquires(&tasklist_lock) +void exit_ptrace(struct task_struct *tracer, struct list_head *dead) { struct task_struct *p, *n; - LIST_HEAD(ptrace_dead); - - if (likely(list_empty(&tracer->ptraced))) - return; list_for_each_entry_safe(p, n, &tracer->ptraced, ptrace_entry) { if (unlikely(p->ptrace & PT_EXITKILL)) send_sig_info(SIGKILL, SEND_SIG_FORCED, p); if (__ptrace_detach(tracer, p)) - list_add(&p->ptrace_entry, &ptrace_dead); - } - - write_unlock_irq(&tasklist_lock); - BUG_ON(!list_empty(&tracer->ptraced)); - - list_for_each_entry_safe(p, n, &ptrace_dead, ptrace_entry) { - list_del_init(&p->ptrace_entry); - release_task(p); + list_add(&p->ptrace_entry, dead); } - - write_lock_irq(&tasklist_lock); } int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len) |
