aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Hilman <khilman@linaro.org>2015-06-16 11:32:45 -0700
committerKevin Hilman <khilman@linaro.org>2015-06-16 11:32:45 -0700
commit3d84ced2488b2cede1c52ada86db26d1e55f4898 (patch)
tree97ca64887ca0c0362118c6858b4e686dc42ec427
parent3f1011ae062950b30326fa7d0538d5083a91ece6 (diff)
parent3174b276b358c0e9416bc58af120b9ab7860907c (diff)
Merge branch 'android-3.18' of https://android.googlesource.com/kernel/common into linux-linaro-lsk-v3.18-android
* 'android-3.18' of https://android.googlesource.com/kernel/common: sched: cpufreq: update power usage only if cpufreq_stat is enabled cpufreq: Iterate over all the possible cpus to create powerstats. uid_cputime: Extends the cputime functionality to report power per uid sched: cpufreq: Adds a field cpu_power in the task_struct cpufreq_stats: Adds the fucntionality to load current values for each frequency for all the cores. cgroup: Fix issues in allow_attach callback New Build Breakage in branch: kernel-m-dev-tegra-flounder-3.10 @ 1960706 net/unix: sk_socket can disappear when state is unlocked selinux: enable genfscon labeling for sysfs and pstore files ext4: don't save the error information if the block device is read-only selinux: enable per-file labeling for debugfs files. cpufreq: interactive: Rearm governor timer at max freq cpufreq: interactive: Implement cluster-based min_sample_time cpufreq: interactive: Exercise hispeed settings at a policy level cpufreq: interactive: Round up timer_rate to match jiffy cpufreq: interactive: Don't set floor_validate_time during boost
-rw-r--r--drivers/cpufreq/cpufreq_interactive.c150
-rw-r--r--drivers/cpufreq/cpufreq_stats.c221
-rw-r--r--drivers/misc/uid_cputime.c12
-rw-r--r--fs/ext4/super.c2
-rw-r--r--include/linux/cgroup.h2
-rw-r--r--include/linux/cpufreq.h9
-rw-r--r--include/linux/sched.h1
-rw-r--r--kernel/fork.c1
-rw-r--r--kernel/sched/core.c1
-rw-r--r--kernel/sched/cputime.c11
-rw-r--r--net/caif/caif_socket.c8
-rw-r--r--net/unix/af_unix.c8
-rw-r--r--security/selinux/hooks.c45
-rw-r--r--security/selinux/include/security.h1
14 files changed, 305 insertions, 167 deletions
diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c
index 7c0affa48914..e569e0b8c2ca 100644
--- a/drivers/cpufreq/cpufreq_interactive.c
+++ b/drivers/cpufreq/cpufreq_interactive.c
@@ -47,9 +47,10 @@ struct cpufreq_interactive_cpuinfo {
spinlock_t target_freq_lock; /*protects target freq */
unsigned int target_freq;
unsigned int floor_freq;
- unsigned int max_freq;
- u64 floor_validate_time;
- u64 hispeed_validate_time;
+ u64 pol_floor_val_time; /* policy floor_validate_time */
+ u64 loc_floor_val_time; /* per-cpu floor_validate_time */
+ u64 pol_hispeed_val_time; /* policy hispeed_validate_time */
+ u64 loc_hispeed_val_time; /* per-cpu hispeed_validate_time */
struct rw_semaphore enable_sem;
int governor_enabled;
};
@@ -345,6 +346,7 @@ static void cpufreq_interactive_timer(unsigned long data)
unsigned int loadadjfreq;
unsigned int index;
unsigned long flags;
+ u64 max_fvtime;
if (!down_read_trylock(&pcpu->enable_sem))
return;
@@ -367,7 +369,7 @@ static void cpufreq_interactive_timer(unsigned long data)
tunables->boosted = tunables->boost_val || now < tunables->boostpulse_endtime;
if (cpu_load >= tunables->go_hispeed_load || tunables->boosted) {
- if (pcpu->target_freq < tunables->hispeed_freq) {
+ if (pcpu->policy->cur < tunables->hispeed_freq) {
new_freq = tunables->hispeed_freq;
} else {
new_freq = choose_freq(pcpu, loadadjfreq);
@@ -378,14 +380,14 @@ static void cpufreq_interactive_timer(unsigned long data)
} else {
new_freq = choose_freq(pcpu, loadadjfreq);
if (new_freq > tunables->hispeed_freq &&
- pcpu->target_freq < tunables->hispeed_freq)
+ pcpu->policy->cur < tunables->hispeed_freq)
new_freq = tunables->hispeed_freq;
}
- if (pcpu->target_freq >= tunables->hispeed_freq &&
- new_freq > pcpu->target_freq &&
- now - pcpu->hispeed_validate_time <
- freq_to_above_hispeed_delay(tunables, pcpu->target_freq)) {
+ if (pcpu->policy->cur >= tunables->hispeed_freq &&
+ new_freq > pcpu->policy->cur &&
+ now - pcpu->pol_hispeed_val_time <
+ freq_to_above_hispeed_delay(tunables, pcpu->policy->cur)) {
trace_cpufreq_interactive_notyet(
data, cpu_load, pcpu->target_freq,
pcpu->policy->cur, new_freq);
@@ -393,7 +395,7 @@ static void cpufreq_interactive_timer(unsigned long data)
goto rearm;
}
- pcpu->hispeed_validate_time = now;
+ pcpu->loc_hispeed_val_time = now;
if (cpufreq_frequency_table_target(pcpu->policy, pcpu->freq_table,
new_freq, CPUFREQ_RELATION_L,
@@ -408,9 +410,10 @@ static void cpufreq_interactive_timer(unsigned long data)
* Do not scale below floor_freq unless we have been at or above the
* floor frequency for the minimum sample time since last validated.
*/
- if (new_freq < pcpu->floor_freq) {
- if (now - pcpu->floor_validate_time <
- tunables->min_sample_time) {
+ max_fvtime = max(pcpu->pol_floor_val_time, pcpu->loc_floor_val_time);
+ if (new_freq < pcpu->floor_freq &&
+ pcpu->target_freq >= pcpu->policy->cur) {
+ if (now - max_fvtime < tunables->min_sample_time) {
trace_cpufreq_interactive_notyet(
data, cpu_load, pcpu->target_freq,
pcpu->policy->cur, new_freq);
@@ -429,7 +432,9 @@ static void cpufreq_interactive_timer(unsigned long data)
if (!tunables->boosted || new_freq > tunables->hispeed_freq) {
pcpu->floor_freq = new_freq;
- pcpu->floor_validate_time = now;
+ if (pcpu->target_freq >= pcpu->policy->cur ||
+ new_freq >= pcpu->policy->cur)
+ pcpu->loc_floor_val_time = now;
}
if (pcpu->target_freq == new_freq &&
@@ -438,7 +443,7 @@ static void cpufreq_interactive_timer(unsigned long data)
data, cpu_load, pcpu->target_freq,
pcpu->policy->cur, new_freq);
spin_unlock_irqrestore(&pcpu->target_freq_lock, flags);
- goto rearm_if_notmax;
+ goto rearm;
}
trace_cpufreq_interactive_target(data, cpu_load, pcpu->target_freq,
@@ -451,14 +456,6 @@ static void cpufreq_interactive_timer(unsigned long data)
spin_unlock_irqrestore(&speedchange_cpumask_lock, flags);
wake_up_process(speedchange_task);
-rearm_if_notmax:
- /*
- * Already set max speed and don't see a need to change that,
- * wait until next idle to re-evaluate, don't need timer.
- */
- if (pcpu->target_freq == pcpu->policy->max)
- goto exit;
-
rearm:
if (!timer_pending(&pcpu->cpu_timer))
cpufreq_interactive_timer_resched(pcpu);
@@ -468,37 +465,6 @@ exit:
return;
}
-static void cpufreq_interactive_idle_start(void)
-{
- struct cpufreq_interactive_cpuinfo *pcpu =
- &per_cpu(cpuinfo, smp_processor_id());
- int pending;
-
- if (!down_read_trylock(&pcpu->enable_sem))
- return;
- if (!pcpu->governor_enabled) {
- up_read(&pcpu->enable_sem);
- return;
- }
-
- pending = timer_pending(&pcpu->cpu_timer);
-
- if (pcpu->target_freq != pcpu->policy->min) {
- /*
- * Entering idle while not at lowest speed. On some
- * platforms this can hold the other CPU(s) at that speed
- * even though the CPU is idle. Set a timer to re-evaluate
- * speed so this idle CPU doesn't hold the other CPUs above
- * min indefinitely. This should probably be a quirk of
- * the CPUFreq driver.
- */
- if (!pending)
- cpufreq_interactive_timer_resched(pcpu);
- }
-
- up_read(&pcpu->enable_sem);
-}
-
static void cpufreq_interactive_idle_end(void)
{
struct cpufreq_interactive_cpuinfo *pcpu =
@@ -553,6 +519,8 @@ static int cpufreq_interactive_speedchange_task(void *data)
for_each_cpu(cpu, &tmp_mask) {
unsigned int j;
unsigned int max_freq = 0;
+ struct cpufreq_interactive_cpuinfo *pjcpu;
+ u64 hvt = ~0ULL, fvt = 0;
pcpu = &per_cpu(cpuinfo, cpu);
if (!down_read_trylock(&pcpu->enable_sem))
@@ -563,17 +531,30 @@ static int cpufreq_interactive_speedchange_task(void *data)
}
for_each_cpu(j, pcpu->policy->cpus) {
- struct cpufreq_interactive_cpuinfo *pjcpu =
- &per_cpu(cpuinfo, j);
+ pjcpu = &per_cpu(cpuinfo, j);
- if (pjcpu->target_freq > max_freq)
+ fvt = max(fvt, pjcpu->loc_floor_val_time);
+ if (pjcpu->target_freq > max_freq) {
max_freq = pjcpu->target_freq;
+ hvt = pjcpu->loc_hispeed_val_time;
+ } else if (pjcpu->target_freq == max_freq) {
+ hvt = min(hvt, pjcpu->loc_hispeed_val_time);
+ }
+ }
+ for_each_cpu(j, pcpu->policy->cpus) {
+ pjcpu = &per_cpu(cpuinfo, j);
+ pjcpu->pol_floor_val_time = fvt;
}
- if (max_freq != pcpu->policy->cur)
+ if (max_freq != pcpu->policy->cur) {
__cpufreq_driver_target(pcpu->policy,
max_freq,
CPUFREQ_RELATION_H);
+ for_each_cpu(j, pcpu->policy->cpus) {
+ pjcpu = &per_cpu(cpuinfo, j);
+ pjcpu->pol_hispeed_val_time = hvt;
+ }
+ }
trace_cpufreq_interactive_setspeed(cpu,
pcpu->target_freq,
pcpu->policy->cur);
@@ -605,18 +586,10 @@ static void cpufreq_interactive_boost(struct cpufreq_interactive_tunables *tunab
if (pcpu->target_freq < tunables->hispeed_freq) {
pcpu->target_freq = tunables->hispeed_freq;
cpumask_set_cpu(i, &speedchange_cpumask);
- pcpu->hispeed_validate_time =
+ pcpu->pol_hispeed_val_time =
ktime_to_us(ktime_get());
anyboost = 1;
}
-
- /*
- * Set floor freq and (re)start timer for when last
- * validated.
- */
-
- pcpu->floor_freq = tunables->hispeed_freq;
- pcpu->floor_validate_time = ktime_to_us(ktime_get());
spin_unlock_irqrestore(&pcpu->target_freq_lock, flags[1]);
}
@@ -863,12 +836,18 @@ static ssize_t store_timer_rate(struct cpufreq_interactive_tunables *tunables,
const char *buf, size_t count)
{
int ret;
- unsigned long val;
+ unsigned long val, val_round;
ret = kstrtoul(buf, 0, &val);
if (ret < 0)
return ret;
- tunables->timer_rate = val;
+
+ val_round = jiffies_to_usecs(usecs_to_jiffies(val));
+ if (val != val_round)
+ pr_warn("timer_rate not aligned to jiffy. Rounded up to %lu\n",
+ val_round);
+
+ tunables->timer_rate = val_round;
return count;
}
@@ -1110,14 +1089,8 @@ static int cpufreq_interactive_idle_notifier(struct notifier_block *nb,
unsigned long val,
void *data)
{
- switch (val) {
- case IDLE_START:
- cpufreq_interactive_idle_start();
- break;
- case IDLE_END:
+ if (val == IDLE_END)
cpufreq_interactive_idle_end();
- break;
- }
return 0;
}
@@ -1234,11 +1207,11 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
pcpu->target_freq = policy->cur;
pcpu->freq_table = freq_table;
pcpu->floor_freq = pcpu->target_freq;
- pcpu->floor_validate_time =
+ pcpu->pol_floor_val_time =
ktime_to_us(ktime_get());
- pcpu->hispeed_validate_time =
- pcpu->floor_validate_time;
- pcpu->max_freq = policy->max;
+ pcpu->loc_floor_val_time = pcpu->pol_floor_val_time;
+ pcpu->pol_hispeed_val_time = pcpu->pol_floor_val_time;
+ pcpu->loc_hispeed_val_time = pcpu->pol_floor_val_time;
down_write(&pcpu->enable_sem);
del_timer_sync(&pcpu->cpu_timer);
del_timer_sync(&pcpu->cpu_slack_timer);
@@ -1288,23 +1261,6 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
spin_unlock_irqrestore(&pcpu->target_freq_lock, flags);
up_read(&pcpu->enable_sem);
-
- /* Reschedule timer only if policy->max is raised.
- * Delete the timers, else the timer callback may
- * return without re-arm the timer when failed
- * acquire the semaphore. This race may cause timer
- * stopped unexpectedly.
- */
-
- if (policy->max > pcpu->max_freq) {
- down_write(&pcpu->enable_sem);
- del_timer_sync(&pcpu->cpu_timer);
- del_timer_sync(&pcpu->cpu_slack_timer);
- cpufreq_interactive_timer_start(tunables, j);
- up_write(&pcpu->enable_sem);
- }
-
- pcpu->max_freq = policy->max;
}
break;
}
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index d45ae3e48150..a65b6bd09b3f 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -14,6 +14,8 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/sort.h>
+#include <linux/of.h>
+#include <linux/sched.h>
#include <linux/cputime.h>
static spinlock_t cpufreq_stats_lock;
@@ -38,6 +40,12 @@ struct all_cpufreq_stats {
unsigned int *freq_table;
};
+struct cpufreq_power_stats {
+ unsigned int state_num;
+ unsigned int *curr;
+ unsigned int *freq_table;
+};
+
struct all_freq_table {
unsigned int *freq_table;
unsigned int table_size;
@@ -47,6 +55,7 @@ static struct all_freq_table *all_freq_table;
static DEFINE_PER_CPU(struct all_cpufreq_stats *, all_cpufreq_stats);
static DEFINE_PER_CPU(struct cpufreq_stats *, cpufreq_stats_table);
+static DEFINE_PER_CPU(struct cpufreq_power_stats *, cpufreq_power_stats);
struct cpufreq_stats_attribute {
struct attribute attr;
@@ -117,6 +126,47 @@ static int get_index_all_cpufreq_stat(struct all_cpufreq_stats *all_stat,
return -1;
}
+void acct_update_power(struct task_struct *task, cputime_t cputime) {
+ struct cpufreq_power_stats *powerstats;
+ struct cpufreq_stats *stats;
+ unsigned int cpu_num, curr;
+
+ if (!task)
+ return;
+ cpu_num = task_cpu(task);
+ powerstats = per_cpu(cpufreq_power_stats, cpu_num);
+ stats = per_cpu(cpufreq_stats_table, cpu_num);
+ if (!powerstats || !stats)
+ return;
+
+ curr = powerstats->curr[stats->last_index];
+ task->cpu_power += curr * cputime_to_usecs(cputime);
+}
+EXPORT_SYMBOL_GPL(acct_update_power);
+
+static ssize_t show_current_in_state(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ ssize_t len = 0;
+ unsigned int i, cpu;
+ struct cpufreq_power_stats *powerstats;
+
+ spin_lock(&cpufreq_stats_lock);
+ for_each_possible_cpu(cpu) {
+ powerstats = per_cpu(cpufreq_power_stats, cpu);
+ if (!powerstats)
+ continue;
+ len += scnprintf(buf + len, PAGE_SIZE - len, "CPU%d:", cpu);
+ for (i = 0; i < powerstats->state_num; i++)
+ len += scnprintf(buf + len, PAGE_SIZE - len,
+ "%d=%d ", powerstats->freq_table[i],
+ powerstats->curr[i]);
+ len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
+ }
+ spin_unlock(&cpufreq_stats_lock);
+ return len;
+}
+
static ssize_t show_all_time_in_state(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
@@ -226,6 +276,9 @@ static struct attribute_group stats_attr_group = {
static struct kobj_attribute _attr_all_time_in_state = __ATTR(all_time_in_state,
0444, show_all_time_in_state, NULL);
+static struct kobj_attribute _attr_current_in_state = __ATTR(current_in_state,
+ 0444, show_current_in_state, NULL);
+
static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
{
int index;
@@ -287,17 +340,31 @@ static void cpufreq_allstats_free(void)
}
}
-static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
+static void cpufreq_powerstats_free(void)
{
- unsigned int i, count = 0, ret = 0;
+ int cpu;
+ struct cpufreq_power_stats *powerstats;
+
+ sysfs_remove_file(cpufreq_global_kobject, &_attr_current_in_state.attr);
+
+ for_each_possible_cpu(cpu) {
+ powerstats = per_cpu(cpufreq_power_stats, cpu);
+ if (!powerstats)
+ continue;
+ kfree(powerstats->curr);
+ kfree(powerstats);
+ per_cpu(cpufreq_power_stats, cpu) = NULL;
+ }
+}
+
+static int __cpufreq_stats_create_table(struct cpufreq_policy *policy,
+ struct cpufreq_frequency_table *table, int count)
+{
+ unsigned int i, ret = 0;
struct cpufreq_stats *stat;
unsigned int alloc_size;
unsigned int cpu = policy->cpu;
- struct cpufreq_frequency_table *pos, *table;
-
- table = cpufreq_frequency_get_table(cpu);
- if (unlikely(!table))
- return 0;
+ struct cpufreq_frequency_table *pos;
if (per_cpu(cpufreq_stats_table, cpu))
return -EBUSY;
@@ -312,9 +379,6 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
stat->cpu = cpu;
per_cpu(cpufreq_stats_table, cpu) = stat;
- cpufreq_for_each_valid_entry(pos, table)
- count++;
-
alloc_size = count * sizeof(int) + count * sizeof(u64);
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
@@ -349,23 +413,6 @@ error_out:
return ret;
}
-static void cpufreq_stats_create_table(unsigned int cpu)
-{
- struct cpufreq_policy *policy;
-
- /*
- * "likely(!policy)" because normally cpufreq_stats will be registered
- * before cpufreq driver
- */
- policy = cpufreq_cpu_get(cpu);
- if (likely(!policy))
- return;
-
- __cpufreq_stats_create_table(policy);
-
- cpufreq_cpu_put(policy);
-}
-
static void cpufreq_stats_update_policy_cpu(struct cpufreq_policy *policy)
{
struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table,
@@ -379,6 +426,51 @@ static void cpufreq_stats_update_policy_cpu(struct cpufreq_policy *policy)
stat->cpu = policy->cpu;
}
+static void cpufreq_powerstats_create(unsigned int cpu,
+ struct cpufreq_frequency_table *table, int count) {
+ unsigned int alloc_size, i = 0, ret = 0;
+ struct cpufreq_power_stats *powerstats;
+ struct cpufreq_frequency_table *pos;
+ struct device_node *cpu_node;
+ char device_path[16];
+
+ powerstats = kzalloc(sizeof(struct cpufreq_power_stats),
+ GFP_KERNEL);
+ if (!powerstats)
+ return;
+
+ /* Allocate memory for freq table per cpu as well as clockticks per
+ * freq*/
+ alloc_size = count * sizeof(unsigned int) +
+ count * sizeof(unsigned int);
+ powerstats->curr = kzalloc(alloc_size, GFP_KERNEL);
+ if (!powerstats->curr) {
+ kfree(powerstats);
+ return;
+ }
+ powerstats->freq_table = powerstats->curr + count;
+
+ spin_lock(&cpufreq_stats_lock);
+ i = 0;
+ cpufreq_for_each_valid_entry(pos, table)
+ powerstats->freq_table[i++] = pos->frequency;
+ powerstats->state_num = i;
+
+ snprintf(device_path, sizeof(device_path), "/cpus/cpu@%d", cpu);
+ cpu_node = of_find_node_by_path(device_path);
+ if (cpu_node) {
+ ret = of_property_read_u32_array(cpu_node, "current",
+ powerstats->curr, count);
+ if (ret) {
+ kfree(powerstats->curr);
+ kfree(powerstats);
+ powerstats = NULL;
+ }
+ }
+ per_cpu(cpufreq_power_stats, cpu) = powerstats;
+ spin_unlock(&cpufreq_stats_lock);
+}
+
static int compare_for_sort(const void *lhs_ptr, const void *rhs_ptr)
{
unsigned int lhs = *(const unsigned int *)(lhs_ptr);
@@ -423,24 +515,14 @@ static void add_all_freq_table(unsigned int freq)
all_freq_table->freq_table[all_freq_table->table_size++] = freq;
}
-static void cpufreq_allstats_create(unsigned int cpu)
+static void cpufreq_allstats_create(unsigned int cpu,
+ struct cpufreq_frequency_table *table, int count)
{
int i , j = 0;
- unsigned int alloc_size, count = 0;
- struct cpufreq_frequency_table *table = cpufreq_frequency_get_table(cpu);
+ unsigned int alloc_size;
struct all_cpufreq_stats *all_stat;
bool sort_needed = false;
- if (!table)
- return;
-
- for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
- unsigned int freq = table[i].frequency;
- if (freq == CPUFREQ_ENTRY_INVALID)
- continue;
- count++;
- }
-
all_stat = kzalloc(sizeof(struct all_cpufreq_stats),
GFP_KERNEL);
if (!all_stat) {
@@ -479,22 +561,65 @@ static void cpufreq_allstats_create(unsigned int cpu)
spin_unlock(&cpufreq_stats_lock);
}
+static void cpufreq_stats_create_table(unsigned int cpu)
+{
+ struct cpufreq_policy *policy;
+ struct cpufreq_frequency_table *table, *pos;
+ int count = 0;
+ /*
+ * "likely(!policy)" because normally cpufreq_stats will be registered
+ * before cpufreq driver
+ */
+ policy = cpufreq_cpu_get(cpu);
+ if (likely(!policy))
+ return;
+
+ table = cpufreq_frequency_get_table(policy->cpu);
+ if (likely(table)) {
+ cpufreq_for_each_valid_entry(pos, table);
+ count++;
+
+ if (!per_cpu(all_cpufreq_stats, cpu))
+ cpufreq_allstats_create(cpu, table, count);
+
+ if (!per_cpu(cpufreq_power_stats, cpu))
+ cpufreq_powerstats_create(cpu, table, count);
+
+ __cpufreq_stats_create_table(policy, table, count);
+ }
+ cpufreq_cpu_put(policy);
+}
+
static int cpufreq_stat_notifier_policy(struct notifier_block *nb,
unsigned long val, void *data)
{
- int ret = 0;
+ int ret = 0, count = 0;
struct cpufreq_policy *policy = data;
+ struct cpufreq_frequency_table *table, *pos;
+ unsigned int cpu_num, cpu = policy->cpu;
if (val == CPUFREQ_UPDATE_POLICY_CPU) {
cpufreq_stats_update_policy_cpu(policy);
return 0;
}
- if (!per_cpu(all_cpufreq_stats, policy->cpu))
- cpufreq_allstats_create(policy->cpu);
+ table = cpufreq_frequency_get_table(cpu);
+ if (!table)
+ return 0;
+
+ cpufreq_for_each_valid_entry(pos, table);
+ count++;
+
+ if (!per_cpu(all_cpufreq_stats, cpu))
+ cpufreq_allstats_create(cpu, table, count);
+
+ for_each_possible_cpu(cpu_num) {
+ if (!per_cpu(cpufreq_power_stats, cpu_num))
+ cpufreq_powerstats_create(cpu_num, table, count);
+ }
if (val == CPUFREQ_CREATE_POLICY)
- ret = __cpufreq_stats_create_table(policy);
+ ret = __cpufreq_stats_create_table(policy, table, count);
else if (val == CPUFREQ_REMOVE_POLICY)
__cpufreq_stats_free_table(policy);
@@ -574,7 +699,12 @@ static int __init cpufreq_stats_init(void)
ret = sysfs_create_file(cpufreq_global_kobject,
&_attr_all_time_in_state.attr);
if (ret)
- pr_warn("Error creating sysfs file for cpufreq stats\n");
+ pr_warn("Cannot create sysfs file for cpufreq stats\n");
+
+ ret = sysfs_create_file(cpufreq_global_kobject,
+ &_attr_current_in_state.attr);
+ if (ret)
+ pr_warn("Cannot create sysfs file for cpufreq current stats\n");
return 0;
}
@@ -589,6 +719,7 @@ static void __exit cpufreq_stats_exit(void)
for_each_online_cpu(cpu)
cpufreq_stats_free_table(cpu);
cpufreq_allstats_free();
+ cpufreq_powerstats_free();
cpufreq_put_global_kobject();
}
diff --git a/drivers/misc/uid_cputime.c b/drivers/misc/uid_cputime.c
index c3f5bda9241d..89bfba6c5b6a 100644
--- a/drivers/misc/uid_cputime.c
+++ b/drivers/misc/uid_cputime.c
@@ -38,6 +38,8 @@ struct uid_entry {
cputime_t stime;
cputime_t active_utime;
cputime_t active_stime;
+ unsigned long long active_power;
+ unsigned long long power;
struct hlist_node hash;
};
@@ -83,6 +85,7 @@ static int uid_stat_show(struct seq_file *m, void *v)
hash_for_each(hash_table, bkt, uid_entry, hash) {
uid_entry->active_stime = 0;
uid_entry->active_utime = 0;
+ uid_entry->active_power = 0;
}
read_lock(&tasklist_lock);
@@ -100,6 +103,7 @@ static int uid_stat_show(struct seq_file *m, void *v)
task_cputime_adjusted(task, &utime, &stime);
uid_entry->active_utime += utime;
uid_entry->active_stime += stime;
+ uid_entry->active_power += task->cpu_power;
}
read_unlock(&tasklist_lock);
@@ -108,9 +112,12 @@ static int uid_stat_show(struct seq_file *m, void *v)
uid_entry->active_utime;
cputime_t total_stime = uid_entry->stime +
uid_entry->active_stime;
- seq_printf(m, "%d: %u %u\n", uid_entry->uid,
+ unsigned long long total_power = uid_entry->power +
+ uid_entry->active_power;
+ seq_printf(m, "%d: %u %u %llu\n", uid_entry->uid,
cputime_to_usecs(total_utime),
- cputime_to_usecs(total_stime));
+ cputime_to_usecs(total_stime),
+ total_power);
}
mutex_unlock(&uid_lock);
@@ -203,6 +210,7 @@ static int process_notifier(struct notifier_block *self,
task_cputime_adjusted(task, &utime, &stime);
uid_entry->utime += utime;
uid_entry->stime += stime;
+ uid_entry->power += task->cpu_power;
exit:
mutex_unlock(&uid_lock);
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index fc7391e14c2a..392107447152 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -304,6 +304,8 @@ static void __save_error_info(struct super_block *sb, const char *func,
struct ext4_super_block *es = EXT4_SB(sb)->s_es;
EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
+ if (bdev_read_only(sb->s_bdev))
+ return;
es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
es->s_last_error_time = cpu_to_le32(get_seconds());
strncpy(es->s_last_error_func, func, sizeof(es->s_last_error_func));
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index 76e154e25572..cbc8db1c1c07 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -948,7 +948,7 @@ static inline int cgroup_attach_task_all(struct task_struct *from,
static inline int subsys_cgroup_allow_attach(struct cgroup_subsys_state *css,
void *tset)
{
- return 0;
+ return -EINVAL;
}
#endif /* !CONFIG_CGROUPS */
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index d0e6f6d340c3..56ea8a336016 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -18,6 +18,8 @@
#include <linux/notifier.h>
#include <linux/spinlock.h>
#include <linux/sysfs.h>
+#include <asm/cputime.h>
+
/*********************************************************************
* CPUFREQ INTERFACE *
@@ -600,4 +602,11 @@ unsigned int cpufreq_generic_get(unsigned int cpu);
int cpufreq_generic_init(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table,
unsigned int transition_latency);
+
+/*********************************************************************
+ * CPUFREQ STATS *
+ *********************************************************************/
+
+void acct_update_power(struct task_struct *p, cputime_t cputime);
+
#endif /* _LINUX_CPUFREQ_H */
diff --git a/include/linux/sched.h b/include/linux/sched.h
index a0918e13523b..4169de53eae3 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1367,6 +1367,7 @@ struct task_struct {
cputime_t utime, stime, utimescaled, stimescaled;
cputime_t gtime;
+ unsigned long long cpu_power;
#ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
struct cputime prev_cputime;
#endif
diff --git a/kernel/fork.c b/kernel/fork.c
index f7f83a103b24..d3a81415925c 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1304,6 +1304,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
p->utime = p->stime = p->gtime = 0;
p->utimescaled = p->stimescaled = 0;
+ p->cpu_power = 0;
#ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
p->prev_cputime.utime = p->prev_cputime.stime = 0;
#endif
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 0e3e7b04a487..372e61688d42 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -8265,6 +8265,7 @@ struct cgroup_subsys cpu_cgrp_subsys = {
.fork = cpu_cgroup_fork,
.can_attach = cpu_cgroup_can_attach,
.attach = cpu_cgroup_attach,
+ .allow_attach = subsys_cgroup_allow_attach,
.exit = cpu_cgroup_exit,
.legacy_cftypes = cpu_files,
.early_init = 1,
diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c
index 8394b1ee600c..b293203ff256 100644
--- a/kernel/sched/cputime.c
+++ b/kernel/sched/cputime.c
@@ -1,3 +1,4 @@
+#include <linux/cpufreq.h>
#include <linux/export.h>
#include <linux/sched.h>
#include <linux/tsacct_kern.h>
@@ -149,6 +150,11 @@ void account_user_time(struct task_struct *p, cputime_t cputime,
/* Account for user time used */
acct_account_cputime(p);
+
+#ifdef CONFIG_CPU_FREQ_STAT
+ /* Account power usage for user time */
+ acct_update_power(p, cputime);
+#endif
}
/*
@@ -199,6 +205,11 @@ void __account_system_time(struct task_struct *p, cputime_t cputime,
/* Account for system time used */
acct_account_cputime(p);
+
+#ifdef CONFIG_CPU_FREQ_STAT
+ /* Account power usage for system time */
+ acct_update_power(p, cputime);
+#endif
}
/*
diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c
index 765c78110fa8..5e10ee0efffb 100644
--- a/net/caif/caif_socket.c
+++ b/net/caif/caif_socket.c
@@ -330,6 +330,10 @@ static long caif_stream_data_wait(struct sock *sk, long timeo)
release_sock(sk);
timeo = schedule_timeout(timeo);
lock_sock(sk);
+
+ if (sock_flag(sk, SOCK_DEAD))
+ break;
+
clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
}
@@ -374,6 +378,10 @@ static int caif_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
struct sk_buff *skb;
lock_sock(sk);
+ if (sock_flag(sk, SOCK_DEAD)) {
+ err = -ECONNRESET;
+ goto unlock;
+ }
skb = skb_dequeue(&sk->sk_receive_queue);
caif_check_flow_release(sk);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index e96884380732..8232118b3f82 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1899,6 +1899,10 @@ static long unix_stream_data_wait(struct sock *sk, long timeo,
unix_state_unlock(sk);
timeo = freezable_schedule_timeout(timeo);
unix_state_lock(sk);
+
+ if (sock_flag(sk, SOCK_DEAD))
+ break;
+
clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
}
@@ -1963,6 +1967,10 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
struct sk_buff *skb, *last;
unix_state_lock(sk);
+ if (sock_flag(sk, SOCK_DEAD)) {
+ err = -ECONNRESET;
+ goto unlock;
+ }
last = skb = skb_peek(&sk->sk_receive_queue);
again:
if (skb == NULL) {
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index e097b8757a90..946120d21663 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -731,7 +731,12 @@ static int selinux_set_mnt_opts(struct super_block *sb,
}
if (strcmp(sb->s_type->name, "proc") == 0)
- sbsec->flags |= SE_SBPROC;
+ sbsec->flags |= SE_SBPROC | SE_SBGENFS;
+
+ if (!strcmp(sb->s_type->name, "debugfs") ||
+ !strcmp(sb->s_type->name, "sysfs") ||
+ !strcmp(sb->s_type->name, "pstore"))
+ sbsec->flags |= SE_SBGENFS;
if (!sbsec->behavior) {
/*
@@ -1227,12 +1232,13 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc
return SECCLASS_SOCKET;
}
-#ifdef CONFIG_PROC_FS
-static int selinux_proc_get_sid(struct dentry *dentry,
- u16 tclass,
- u32 *sid)
+static int selinux_genfs_get_sid(struct dentry *dentry,
+ u16 tclass,
+ u16 flags,
+ u32 *sid)
{
int rc;
+ struct super_block *sb = dentry->d_inode->i_sb;
char *buffer, *path;
buffer = (char *)__get_free_page(GFP_KERNEL);
@@ -1243,26 +1249,20 @@ static int selinux_proc_get_sid(struct dentry *dentry,
if (IS_ERR(path))
rc = PTR_ERR(path);
else {
- /* each process gets a /proc/PID/ entry. Strip off the
- * PID part to get a valid selinux labeling.
- * e.g. /proc/1/net/rpc/nfs -> /net/rpc/nfs */
- while (path[1] >= '0' && path[1] <= '9') {
- path[1] = '/';
- path++;
+ if (flags & SE_SBPROC) {
+ /* each process gets a /proc/PID/ entry. Strip off the
+ * PID part to get a valid selinux labeling.
+ * e.g. /proc/1/net/rpc/nfs -> /net/rpc/nfs */
+ while (path[1] >= '0' && path[1] <= '9') {
+ path[1] = '/';
+ path++;
+ }
}
- rc = security_genfs_sid("proc", path, tclass, sid);
+ rc = security_genfs_sid(sb->s_type->name, path, tclass, sid);
}
free_page((unsigned long)buffer);
return rc;
}
-#else
-static int selinux_proc_get_sid(struct dentry *dentry,
- u16 tclass,
- u32 *sid)
-{
- return -EINVAL;
-}
-#endif
/* The inode's security attributes must be initialized before first use. */
static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry)
@@ -1419,7 +1419,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
/* Default to the fs superblock SID. */
isec->sid = sbsec->sid;
- if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) {
+ if ((sbsec->flags & SE_SBGENFS) && !S_ISLNK(inode->i_mode)) {
/* We must have a dentry to determine the label on
* procfs inodes */
if (opt_dentry)
@@ -1442,7 +1442,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
if (!dentry)
goto out_unlock;
isec->sclass = inode_mode_to_security_class(inode->i_mode);
- rc = selinux_proc_get_sid(dentry, isec->sclass, &sid);
+ rc = selinux_genfs_get_sid(dentry, isec->sclass,
+ sbsec->flags, &sid);
dput(dentry);
if (rc)
goto out_unlock;
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 9f4f7cbe2e7d..8d506832927f 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -57,6 +57,7 @@
/* Non-mount related flags */
#define SE_SBINITIALIZED 0x0100
#define SE_SBPROC 0x0200
+#define SE_SBGENFS 0x0400
#define CONTEXT_STR "context="
#define FSCONTEXT_STR "fscontext="