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