diff options
author | Oleg Nesterov <oleg@redhat.com> | 2014-12-10 18:54:48 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-10 20:41:17 -0500 |
commit | f953ccd00615140b5e722ffe2b920da22dfb4db9 (patch) | |
tree | 6c087e1e9f3c8bdd941bbdcf8d7bec472272b5a5 /kernel/exit.c | |
parent | f6507f83bccd4a5f7dc7091079bf58128dc56d66 (diff) |
exit: wait: don't use zombie->real_parent
1. wait_task_zombie() uses p->real_parent to get psig/siglock. This is
correct but needs tasklist_lock, ->real_parent can exit.
We can use "current" instead. This is our natural child, its parent
must be our sub-thread.
2. Read psig/sig outside of ->siglock, ->signal is no longer protected
by this lock.
3. Fix the outdated comments about tasklist_lock. We can not race with
__exit_signal(), the whole thread group is dead, nobody but us can
call it.
Also clarify the usage of ->stats_lock and ->siglock.
Note: thread_group_cputime_adjusted() is sub-optimal in this case, we
probably want to export cputime_adjust() to avoid thread_group_cputime().
The comment says "all threads" but there are no other threads.
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Cc: Aaron Tomlin <atomlin@redhat.com>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Rik van Riel <riel@redhat.com>
Cc: Sterling Alexander <stalexan@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/exit.c')
-rw-r--r-- | kernel/exit.c | 23 |
1 files changed, 11 insertions, 12 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index 20875d6398ae..457673d65934 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -1010,8 +1010,8 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p) | |||
1010 | * Check thread_group_leader() to exclude the traced sub-threads. | 1010 | * Check thread_group_leader() to exclude the traced sub-threads. |
1011 | */ | 1011 | */ |
1012 | if (state == EXIT_DEAD && thread_group_leader(p)) { | 1012 | if (state == EXIT_DEAD && thread_group_leader(p)) { |
1013 | struct signal_struct *psig; | 1013 | struct signal_struct *sig = p->signal; |
1014 | struct signal_struct *sig; | 1014 | struct signal_struct *psig = current->signal; |
1015 | unsigned long maxrss; | 1015 | unsigned long maxrss; |
1016 | cputime_t tgutime, tgstime; | 1016 | cputime_t tgutime, tgstime; |
1017 | 1017 | ||
@@ -1023,21 +1023,20 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p) | |||
1023 | * accumulate in the parent's signal_struct c* fields. | 1023 | * accumulate in the parent's signal_struct c* fields. |
1024 | * | 1024 | * |
1025 | * We don't bother to take a lock here to protect these | 1025 | * We don't bother to take a lock here to protect these |
1026 | * p->signal fields, because they are only touched by | 1026 | * p->signal fields because the whole thread group is dead |
1027 | * __exit_signal, which runs with tasklist_lock | 1027 | * and nobody can change them. |
1028 | * write-locked anyway, and so is excluded here. We do | 1028 | * |
1029 | * need to protect the access to parent->signal fields, | 1029 | * psig->stats_lock also protects us from our sub-theads |
1030 | * as other threads in the parent group can be right | 1030 | * which can reap other children at the same time. Until |
1031 | * here reaping other children at the same time. | 1031 | * we change k_getrusage()-like users to rely on this lock |
1032 | * we have to take ->siglock as well. | ||
1032 | * | 1033 | * |
1033 | * We use thread_group_cputime_adjusted() to get times for | 1034 | * We use thread_group_cputime_adjusted() to get times for |
1034 | * the thread group, which consolidates times for all threads | 1035 | * the thread group, which consolidates times for all threads |
1035 | * in the group including the group leader. | 1036 | * in the group including the group leader. |
1036 | */ | 1037 | */ |
1037 | thread_group_cputime_adjusted(p, &tgutime, &tgstime); | 1038 | thread_group_cputime_adjusted(p, &tgutime, &tgstime); |
1038 | spin_lock_irq(&p->real_parent->sighand->siglock); | 1039 | spin_lock_irq(¤t->sighand->siglock); |
1039 | psig = p->real_parent->signal; | ||
1040 | sig = p->signal; | ||
1041 | write_seqlock(&psig->stats_lock); | 1040 | write_seqlock(&psig->stats_lock); |
1042 | psig->cutime += tgutime + sig->cutime; | 1041 | psig->cutime += tgutime + sig->cutime; |
1043 | psig->cstime += tgstime + sig->cstime; | 1042 | psig->cstime += tgstime + sig->cstime; |
@@ -1062,7 +1061,7 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p) | |||
1062 | task_io_accounting_add(&psig->ioac, &p->ioac); | 1061 | task_io_accounting_add(&psig->ioac, &p->ioac); |
1063 | task_io_accounting_add(&psig->ioac, &sig->ioac); | 1062 | task_io_accounting_add(&psig->ioac, &sig->ioac); |
1064 | write_sequnlock(&psig->stats_lock); | 1063 | write_sequnlock(&psig->stats_lock); |
1065 | spin_unlock_irq(&p->real_parent->sighand->siglock); | 1064 | spin_unlock_irq(¤t->sighand->siglock); |
1066 | } | 1065 | } |
1067 | 1066 | ||
1068 | /* | 1067 | /* |