diff options
Diffstat (limited to 'kernel/taskstats.c')
-rw-r--r-- | kernel/taskstats.c | 26 |
1 files changed, 25 insertions, 1 deletions
diff --git a/kernel/taskstats.c b/kernel/taskstats.c index 2654886fe058..7d793d6b1e90 100644 --- a/kernel/taskstats.c +++ b/kernel/taskstats.c | |||
@@ -412,6 +412,30 @@ err: | |||
412 | return rc; | 412 | return rc; |
413 | } | 413 | } |
414 | 414 | ||
415 | static struct taskstats *taskstats_tgid_alloc(struct task_struct *tsk) | ||
416 | { | ||
417 | struct signal_struct *sig = tsk->signal; | ||
418 | struct taskstats *stats; | ||
419 | |||
420 | if (sig->stats || thread_group_empty(tsk)) | ||
421 | goto ret; | ||
422 | |||
423 | /* No problem if kmem_cache_zalloc() fails */ | ||
424 | stats = kmem_cache_zalloc(taskstats_cache, GFP_KERNEL); | ||
425 | |||
426 | spin_lock_irq(&tsk->sighand->siglock); | ||
427 | if (!sig->stats) { | ||
428 | sig->stats = stats; | ||
429 | stats = NULL; | ||
430 | } | ||
431 | spin_unlock_irq(&tsk->sighand->siglock); | ||
432 | |||
433 | if (stats) | ||
434 | kmem_cache_free(taskstats_cache, stats); | ||
435 | ret: | ||
436 | return sig->stats; | ||
437 | } | ||
438 | |||
415 | /* Send pid data out on exit */ | 439 | /* Send pid data out on exit */ |
416 | void taskstats_exit(struct task_struct *tsk, int group_dead) | 440 | void taskstats_exit(struct task_struct *tsk, int group_dead) |
417 | { | 441 | { |
@@ -433,7 +457,7 @@ void taskstats_exit(struct task_struct *tsk, int group_dead) | |||
433 | size = nla_total_size(sizeof(u32)) + | 457 | size = nla_total_size(sizeof(u32)) + |
434 | nla_total_size(sizeof(struct taskstats)) + nla_total_size(0); | 458 | nla_total_size(sizeof(struct taskstats)) + nla_total_size(0); |
435 | 459 | ||
436 | is_thread_group = (tsk->signal->stats != NULL); | 460 | is_thread_group = !!taskstats_tgid_alloc(tsk); |
437 | if (is_thread_group) { | 461 | if (is_thread_group) { |
438 | /* PID + STATS + TGID + STATS */ | 462 | /* PID + STATS + TGID + STATS */ |
439 | size = 2 * size; | 463 | size = 2 * size; |