aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@tv-sign.ru>2006-10-28 13:38:51 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-28 14:30:54 -0400
commit093a8e8aecd77b2799934996a55a6838e1e2b8f3 (patch)
treeece87b2e194494059b2d4aaa43a094786dac1db7
parent05d5bcd60e8202e5c7b28cf61186043a4d612623 (diff)
[PATCH] taskstats_tgid_free: fix usage
taskstats_tgid_free() is called on copy_process's error path. This is wrong. IF (clone_flags & CLONE_THREAD) We should not clear ->signal->taskstats, current uses it, it probably has a valid accumulated info. ELSE taskstats_tgid_init() set ->signal->taskstats = NULL, there is nothing to free. Move the callsite to __exit_signal(). We don't need any locking, entire thread group is exiting, nobody should have a reference to soon to be released ->signal. Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru> Cc: Shailabh Nagar <nagar@watson.ibm.com> Cc: Balbir Singh <balbir@in.ibm.com> Cc: Jay Lan <jlan@sgi.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--include/linux/taskstats_kern.h13
-rw-r--r--kernel/exit.c1
-rw-r--r--kernel/fork.c1
3 files changed, 3 insertions, 12 deletions
diff --git a/include/linux/taskstats_kern.h b/include/linux/taskstats_kern.h
index 16894b7edcc8..a437ca0d226b 100644
--- a/include/linux/taskstats_kern.h
+++ b/include/linux/taskstats_kern.h
@@ -49,17 +49,8 @@ static inline void taskstats_tgid_alloc(struct signal_struct *sig)
49 49
50static inline void taskstats_tgid_free(struct signal_struct *sig) 50static inline void taskstats_tgid_free(struct signal_struct *sig)
51{ 51{
52 struct taskstats *stats = NULL; 52 if (sig->stats)
53 unsigned long flags; 53 kmem_cache_free(taskstats_cache, sig->stats);
54
55 spin_lock_irqsave(&sig->stats_lock, flags);
56 if (sig->stats) {
57 stats = sig->stats;
58 sig->stats = NULL;
59 }
60 spin_unlock_irqrestore(&sig->stats_lock, flags);
61 if (stats)
62 kmem_cache_free(taskstats_cache, stats);
63} 54}
64 55
65extern void taskstats_exit_alloc(struct taskstats **, unsigned int *); 56extern void taskstats_exit_alloc(struct taskstats **, unsigned int *);
diff --git a/kernel/exit.c b/kernel/exit.c
index f250a5e3e281..06de6c4e8ca3 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -128,6 +128,7 @@ static void __exit_signal(struct task_struct *tsk)
128 flush_sigqueue(&tsk->pending); 128 flush_sigqueue(&tsk->pending);
129 if (sig) { 129 if (sig) {
130 flush_sigqueue(&sig->shared_pending); 130 flush_sigqueue(&sig->shared_pending);
131 taskstats_tgid_free(sig);
131 __cleanup_signal(sig); 132 __cleanup_signal(sig);
132 } 133 }
133} 134}
diff --git a/kernel/fork.c b/kernel/fork.c
index 29ebb30850ed..213326609bac 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -897,7 +897,6 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts
897void __cleanup_signal(struct signal_struct *sig) 897void __cleanup_signal(struct signal_struct *sig)
898{ 898{
899 exit_thread_group_keys(sig); 899 exit_thread_group_keys(sig);
900 taskstats_tgid_free(sig);
901 kmem_cache_free(signal_cachep, sig); 900 kmem_cache_free(signal_cachep, sig);
902} 901}
903 902