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>
static inline void taskstats_tgid_free(struct signal_struct *sig)
{
- struct taskstats *stats = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&sig->stats_lock, flags);
- if (sig->stats) {
- stats = sig->stats;
- sig->stats = NULL;
- }
- spin_unlock_irqrestore(&sig->stats_lock, flags);
- if (stats)
- kmem_cache_free(taskstats_cache, stats);
+ if (sig->stats)
+ kmem_cache_free(taskstats_cache, sig->stats);
}
extern void taskstats_exit_alloc(struct taskstats **, unsigned int *);
flush_sigqueue(&tsk->pending);
if (sig) {
flush_sigqueue(&sig->shared_pending);
+ taskstats_tgid_free(sig);
__cleanup_signal(sig);
}
}
void __cleanup_signal(struct signal_struct *sig)
{
exit_thread_group_keys(sig);
- taskstats_tgid_free(sig);
kmem_cache_free(signal_cachep, sig);
}