Allocate ->signal->stats on demand in taskstats_exit(), this allows us to remove taskstats_tgid_alloc() (the last non-trivial inline) from taskstat's public interface.
Unified · Split
| @@ -20,28 +20,6 @@ static inline void taskstats_tgid_init(struct signal_struct *sig) · 19 unmodified lines | ||
| 20 | 20 | sig->stats = NULL; |
| 21 | 21 | } |
| 22 | 22 | |
| 23 | −static inline void taskstats_tgid_alloc(struct task_struct *tsk) | |
| 24 | −{ | |
| 25 | − struct signal_struct *sig = tsk->signal; | |
| 26 | − struct taskstats *stats; | |
| 27 | − | |
| 28 | − if (sig->stats != NULL) | |
| 29 | − return; | |
| 30 | − | |
| 31 | − /* No problem if kmem_cache_zalloc() fails */ | |
| 32 | − stats = kmem_cache_zalloc(taskstats_cache, GFP_KERNEL); | |
| 33 | − | |
| 34 | − spin_lock_irq(&tsk->sighand->siglock); | |
| 35 | − if (!sig->stats) { | |
| 36 | − sig->stats = stats; | |
| 37 | − stats = NULL; | |
| 38 | − } | |
| 39 | − spin_unlock_irq(&tsk->sighand->siglock); | |
| 40 | − | |
| 41 | − if (stats) | |
| 42 | − kmem_cache_free(taskstats_cache, stats); | |
| 43 | −} | |
| 44 | − | |
| 45 | 23 | static inline void taskstats_tgid_free(struct signal_struct *sig) |
| 46 | 24 | { |
| 47 | 25 | if (sig->stats) |
| @@ -55,8 +33,6 @@ static inline void taskstats_exit(struct task_struct *tsk, int group_dead) · 7 unmodified lines | ||
| 55 | 33 | {} |
| 56 | 34 | static inline void taskstats_tgid_init(struct signal_struct *sig) |
| 57 | 35 | {} |
| 58 | −static inline void taskstats_tgid_alloc(struct task_struct *tsk) | |
| 59 | −{} | |
| 60 | 36 | static inline void taskstats_tgid_free(struct signal_struct *sig) |
| 61 | 37 | {} |
| 62 | 38 | static inline void taskstats_init_early(void) |
| @@ -847,7 +847,6 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts · 846 unmodified lines | ||
| 847 | 847 | if (clone_flags & CLONE_THREAD) { |
| 848 | 848 | atomic_inc(¤t->signal->count); |
| 849 | 849 | atomic_inc(¤t->signal->live); |
| 850 | − taskstats_tgid_alloc(current); | |
| 851 | 850 | return 0; |
| 852 | 851 | } |
| 853 | 852 | sig = kmem_cache_alloc(signal_cachep, GFP_KERNEL); |
| @@ -412,6 +412,30 @@ err: · 411 unmodified lines | ||
| 412 | 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 | 439 | /* Send pid data out on exit */ |
| 416 | 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) · 15 unmodified lines | ||
| 433 | 457 | size = nla_total_size(sizeof(u32)) + |
| 434 | 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 | 461 | if (is_thread_group) { |
| 438 | 462 | /* PID + STATS + TGID + STATS */ |
| 439 | 463 | size = 2 * size; |