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>
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index 864ebae..37e0f22 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -470,14 +470,24 @@
 
 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 @@
 	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 84f6b21..52a6ea0 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -655,6 +655,8 @@
 
 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 @@
 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 c306163..0817e37 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 @@
 
 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 1493b0a..9a70b45 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -2130,6 +2130,10 @@
 	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 @@
 	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