]>
Commit | Line | Data |
---|---|---|
867615e6 GKH |
1 | From 6d69cb87f05eef3b02370b2f7bae608ad2301a00 Mon Sep 17 00:00:00 2001 |
2 | From: Oleg Nesterov <oleg@redhat.com> | |
3 | Date: Thu, 2 Apr 2009 16:58:12 -0700 | |
4 | Subject: ptrace: simplify ptrace_exit()->ignoring_children() path | |
5 | ||
6 | From: Oleg Nesterov <oleg@redhat.com> | |
7 | ||
8 | commit 6d69cb87f05eef3b02370b2f7bae608ad2301a00 upstream. | |
9 | ||
10 | ignoring_children() takes parent->sighand->siglock and checks | |
11 | k_sigaction[SIGCHLD] atomically. But this buys nothing, we can't get the | |
12 | "really" wrong result even if we race with sigaction(SIGCHLD). If we read | |
13 | the "stale" sa_handler/sa_flags we can pretend it was changed right after | |
14 | the check. | |
15 | ||
16 | Remove spin_lock(->siglock), and kill "int ign" which caches the result of | |
17 | ignoring_children() which becomes rather trivial. | |
18 | ||
19 | Perhaps it makes sense to export this helper, do_notify_parent() can use | |
20 | it too. | |
21 | ||
22 | Signed-off-by: Oleg Nesterov <oleg@redhat.com> | |
23 | Cc: Jerome Marchand <jmarchan@redhat.com> | |
24 | Cc: Roland McGrath <roland@redhat.com> | |
25 | Cc: Denys Vlasenko <dvlasenk@redhat.com> | |
26 | Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | |
27 | Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> | |
28 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | |
29 | ||
30 | --- | |
31 | kernel/exit.c | 25 ++++++++----------------- | |
32 | 1 file changed, 8 insertions(+), 17 deletions(-) | |
33 | ||
34 | --- a/kernel/exit.c | |
35 | +++ b/kernel/exit.c | |
36 | @@ -703,19 +703,15 @@ static void exit_mm(struct task_struct * | |
37 | } | |
38 | ||
39 | /* | |
40 | - * Return nonzero if @parent's children should reap themselves. | |
41 | - * | |
42 | - * Called with write_lock_irq(&tasklist_lock) held. | |
43 | + * Called with irqs disabled, returns true if childs should reap themselves. | |
44 | */ | |
45 | -static int ignoring_children(struct task_struct *parent) | |
46 | +static int ignoring_children(struct sighand_struct *sigh) | |
47 | { | |
48 | int ret; | |
49 | - struct sighand_struct *psig = parent->sighand; | |
50 | - unsigned long flags; | |
51 | - spin_lock_irqsave(&psig->siglock, flags); | |
52 | - ret = (psig->action[SIGCHLD-1].sa.sa_handler == SIG_IGN || | |
53 | - (psig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDWAIT)); | |
54 | - spin_unlock_irqrestore(&psig->siglock, flags); | |
55 | + spin_lock(&sigh->siglock); | |
56 | + ret = (sigh->action[SIGCHLD-1].sa.sa_handler == SIG_IGN) || | |
57 | + (sigh->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDWAIT); | |
58 | + spin_unlock(&sigh->siglock); | |
59 | return ret; | |
60 | } | |
61 | ||
62 | @@ -728,7 +724,6 @@ static int ignoring_children(struct task | |
63 | static void ptrace_exit(struct task_struct *parent, struct list_head *dead) | |
64 | { | |
65 | struct task_struct *p, *n; | |
66 | - int ign = -1; | |
67 | ||
68 | list_for_each_entry_safe(p, n, &parent->ptraced, ptrace_entry) { | |
69 | __ptrace_unlink(p); | |
70 | @@ -750,12 +745,8 @@ static void ptrace_exit(struct task_stru | |
71 | if (!task_detached(p) && thread_group_empty(p)) { | |
72 | if (!same_thread_group(p->real_parent, parent)) | |
73 | do_notify_parent(p, p->exit_signal); | |
74 | - else { | |
75 | - if (ign < 0) | |
76 | - ign = ignoring_children(parent); | |
77 | - if (ign) | |
78 | - p->exit_signal = -1; | |
79 | - } | |
80 | + else if (ignoring_children(parent->sighand)) | |
81 | + p->exit_signal = -1; | |
82 | } | |
83 | ||
84 | if (task_detached(p)) { |