From 4c57f62a5a0ea826cd0c1ee08bbe8370f1e90fb3 Mon Sep 17 00:00:00 2001 From: Wei Wang <wvw@google.com> Date: Mon, 11 Jun 2018 16:14:51 -0700 Subject: [PATCH] kernel: initialize and free cpufreq stats properly Initialize task's cpufreq to NULL including for idle Make sure free task's cpufreq when free task struct Bug: 110044919 Change-Id: Ie4629d0ebe3ef4b72dffea3ee613b15f40a57142 Signed-off-by: Wei Wang <wvw@google.com> --- drivers/cpufreq/cpufreq_stats.c | 23 ++++++++++++++++++++--- include/linux/cpufreq.h | 4 ++++ kernel/fork.c | 4 ++++ kernel/sched/core.c | 9 +++++++-- 4 files changed, 35 insertions(+), 5 deletions(-) diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 864ebae595b9..37e0f22bcb39 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -470,14 +470,24 @@ static int cpufreq_stats_update(unsigned int cpu) void cpufreq_task_stats_init(struct task_struct *p) { - size_t alloc_size; - void *temp; unsigned long flags; - spin_lock_irqsave(&task_time_in_state_lock, flags); p->time_in_state = NULL; spin_unlock_irqrestore(&task_time_in_state_lock, flags); WRITE_ONCE(p->max_states, 0); + spin_lock_irqsave(&task_concurrent_active_time_lock, flags); + p->concurrent_active_time = NULL; + spin_unlock_irqrestore(&task_concurrent_active_time_lock, flags); + spin_lock_irqsave(&task_concurrent_policy_time_lock, flags); + p->concurrent_policy_time = NULL; + spin_unlock_irqrestore(&task_concurrent_policy_time_lock, flags); +} + +void cpufreq_task_stats_alloc(struct task_struct *p) +{ + size_t alloc_size; + void *temp; + unsigned long flags; if (!all_freq_table || !cpufreq_all_freq_init) return; @@ -1343,6 +1353,13 @@ static int process_notifier(struct notifier_block *self, return NOTIFY_OK; } +void cpufreq_task_stats_free(struct task_struct *p) +{ + kfree(p->time_in_state); + kfree(p->concurrent_active_time); + kfree(p->concurrent_policy_time); +} + static const struct seq_operations uid_time_in_state_seq_ops = { .start = uid_seq_start, .next = uid_seq_next, diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 84f6b21be137..52a6ea074d30 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -655,6 +655,8 @@ int cpufreq_generic_init(struct cpufreq_policy *policy, void acct_update_power(struct task_struct *p, cputime_t cputime); void cpufreq_task_stats_init(struct task_struct *p); +void cpufreq_task_stats_alloc(struct task_struct *p); +void cpufreq_task_stats_free(struct task_struct *p); void cpufreq_task_stats_remove_uids(uid_t uid_start, uid_t uid_end); int proc_time_in_state_show(struct seq_file *m, struct pid_namespace *ns, struct pid *pid, struct task_struct *p); @@ -667,6 +669,8 @@ int single_uid_time_in_state_open(struct inode *inode, struct file *file); static inline void acct_update_power(struct task_struct *p, cputime_t cputime) {} static inline void cpufreq_task_stats_init(struct task_struct *p) {} +static inline void cpufreq_task_stats_alloc(struct task_struct *p) {} +static inline void cpufreq_task_stats_free(struct task_struct *p) {} static inline void cpufreq_task_stats_exit(struct task_struct *p) {} static inline void cpufreq_task_stats_remove_uids(uid_t uid_start, uid_t uid_end) {} diff --git a/kernel/fork.c b/kernel/fork.c index c3061638a6c7..0817e3747dea 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -76,6 +76,7 @@ #include <linux/aio.h> #include <linux/compiler.h> #include <linux/kcov.h> +#include <linux/cpufreq.h> #include <asm/pgtable.h> #include <asm/pgalloc.h> @@ -217,6 +218,9 @@ static void account_kernel_stack(unsigned long *stack, int account) void free_task(struct task_struct *tsk) { +#ifdef CONFIG_CPU_FREQ_STAT + cpufreq_task_stats_free(tsk); +#endif account_kernel_stack(tsk->stack, -1); arch_release_thread_stack(tsk->stack); free_thread_stack(tsk->stack); diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 1493b0a118d3..9a70b45236a8 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -2130,6 +2130,10 @@ static void __sched_fork(unsigned long clone_flags, struct task_struct *p) memset(&p->se.statistics, 0, sizeof(p->se.statistics)); #endif +#ifdef CONFIG_CPU_FREQ_STAT + cpufreq_task_stats_init(p); +#endif + RB_CLEAR_NODE(&p->dl.rb_node); init_dl_task_timer(&p->dl); __dl_clear_params(p); @@ -2215,11 +2219,12 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p) unsigned long flags; int cpu = get_cpu(); + __sched_fork(clone_flags, p); + #ifdef CONFIG_CPU_FREQ_STAT - cpufreq_task_stats_init(p); + cpufreq_task_stats_alloc(p); #endif - __sched_fork(clone_flags, p); /* * We mark the process as running here. This guarantees that * nobody will actually run it, and a signal or other external -- GitLab