diff --git a/arch/x86/kernel/cpu/proc.c b/arch/x86/kernel/cpu/proc.c index e398a6ef9..dd416b497 100644 --- a/arch/x86/kernel/cpu/proc.c +++ b/arch/x86/kernel/cpu/proc.c @@ -56,7 +56,9 @@ static void show_cpuinfo_misc(struct seq_file *m, struct cpuinfo_x86 *c) #ifdef CONFIG_X86 extern int cpuset_cg_cpuinfo_next(struct task_struct *p); -extern int cpuset_cg_cpuinfo_show(struct seq_file *sf, void *v, struct task_struct *p); +extern int cpuset_cg_cpuinfo_show(struct seq_file *sf, void *v, + struct task_struct *p, int max_cpus); +extern int cpu_get_max_cpus(struct task_struct *p); #endif static int show_cpuinfo(struct seq_file *m, void *v) @@ -66,7 +68,8 @@ static int show_cpuinfo(struct seq_file *m, void *v) int i; #ifdef CONFIG_X86 - if (!cpuset_cg_cpuinfo_show(m, v, current)) + int max_cpus = cpu_get_max_cpus(current); + if (!cpuset_cg_cpuinfo_show(m, v, current, max_cpus)) return 0; #endif diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c index ffa987ea6..a0567e4b7 100644 --- a/kernel/cgroup/cpuset.c +++ b/kernel/cgroup/cpuset.c @@ -2076,7 +2076,7 @@ static void show_cpuinfo_misc(struct seq_file *m, struct cpuinfo_x86 *c) #endif static int cpuset_cg_cpuinfo_print(struct seq_file *sf, void *v, - struct cgroup_subsys_state *cs_css) + struct cgroup_subsys_state *cs_css, int max_cpus) { int i, j, k = 0; struct cpuset *cs = css_cs(cs_css); @@ -2097,6 +2097,9 @@ static int cpuset_cg_cpuinfo_print(struct seq_file *sf, void *v, else cpu = k; k++; + if (k > max_cpus) + break; + seq_printf(sf, "processor\t: %u\n" "vendor_id\t: %s\n" "cpu family\t: %d\n" @@ -2177,7 +2180,7 @@ static int cpuset_cg_cpuinfo_print(struct seq_file *sf, void *v, static int cpuset_cgroup_cpuinfo_show(struct seq_file *sf, void *v) { - return cpuset_cg_cpuinfo_print(sf, v, seq_css(sf)); + return cpuset_cg_cpuinfo_print(sf, v, seq_css(sf), INT_MAX); } int cpuset_cg_cpuinfo_next(struct task_struct *p) @@ -2185,13 +2188,14 @@ int cpuset_cg_cpuinfo_next(struct task_struct *p) return cpuset_stats_isolated_enabled(task_cs(p)) ? 0 : 1; } -int cpuset_cg_cpuinfo_show(struct seq_file *sf, void *v, struct task_struct *p) +int cpuset_cg_cpuinfo_show(struct seq_file *sf, void *v, + struct task_struct *p, int max_cpus) { struct cgroup_subsys_state *css = task_css(p, cpuset_cgrp_id); struct cpuset *cs = css_cs(css); return cpuset_stats_isolated_enabled(cs) ? - cpuset_cg_cpuinfo_print(sf, v, css) : 1; + cpuset_cg_cpuinfo_print(sf, v, css, max_cpus) : 1; } #endif diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 30349f7f0..ba4ffb8a4 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -6605,6 +6605,36 @@ static inline struct task_group *css_tg(struct cgroup_subsys_state *css) return css ? container_of(css, struct task_group, css) : NULL; } +void cpu_set_quota_aware(struct task_struct *p, u64 val) +{ + struct task_group *tg = task_group(p); + + if (tg && tg != &root_task_group) + tg->cpuquota_aware = val; +} + +#define cpu_quota_aware_enabled(tg) \ + sysctl_cgroup_stats_isolated && tg && \ + tg != &root_task_group && tg->cpuquota_aware + +int cpu_get_max_cpus(struct task_struct *p) +{ + int max_cpus = INT_MAX; + struct task_group *tg = task_group(p); + + if (!cpu_quota_aware_enabled(tg)) + return max_cpus; + + if (tg->cfs_bandwidth.quota == RUNTIME_INF) + return max_cpus; + + max_cpus = tg->cfs_bandwidth.quota / tg->cfs_bandwidth.period; + if (tg->cfs_bandwidth.quota % tg->cfs_bandwidth.period) + max_cpus++; + + return max_cpus; +} + static struct cgroup_subsys_state * cpu_cgroup_css_alloc(struct cgroup_subsys_state *parent_css) { @@ -6625,6 +6655,8 @@ cpu_cgroup_css_alloc(struct cgroup_subsys_state *parent_css) tg->offline = parent->offline; #endif + tg->cpuquota_aware = 1; + return &tg->css; } @@ -7072,8 +7104,23 @@ static u64 cpu_rt_period_read_uint(struct cgroup_subsys_state *css, } #endif /* CONFIG_RT_GROUP_SCHED */ +#ifdef CONFIG_FAIR_GROUP_SCHED +static u64 cpu_quota_aware_read_u64(struct cgroup_subsys_state *css, + struct cftype *cft) +{ + struct task_group *tg = css_tg(css); + + return tg->cpuquota_aware; +} +#endif + static struct cftype cpu_files[] = { #ifdef CONFIG_FAIR_GROUP_SCHED + { + .name = "quota_aware", + .flags = CFTYPE_NOT_ON_ROOT, + .read_u64 = cpu_quota_aware_read_u64, + }, { .name = "shares", .read_u64 = cpu_shares_read_u64, diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index c1910ca0c..175c409f1 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -372,6 +372,7 @@ struct task_group { struct autogroup *autogroup; #endif + u64 cpuquota_aware; struct cfs_bandwidth cfs_bandwidth; unsigned long offline; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 27790d8cc..8389c0d75 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -227,7 +227,8 @@ static int proc_dostring_coredump(struct ctl_table *table, int write, static int proc_stats_isolated(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos); - +static int proc_cpuquota_aware(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos); #ifdef CONFIG_MAGIC_SYSRQ /* Note: sysrq code uses it's own private copy */ static int __sysrq_enabled = CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE; @@ -338,6 +339,12 @@ extern unsigned int sysctl_memcg_stat_show_subtree; unsigned int sysctl_cgroup_stats_isolated = 0; static struct ctl_table kern_table[] = { + { + .procname = "container_cpuquota_aware", + .maxlen = sizeof(unsigned int), + .mode = 0222, + .proc_handler = proc_cpuquota_aware, + }, { .procname = "container_stats_isolated", .maxlen = sizeof(unsigned int), @@ -3418,6 +3425,26 @@ extern void cpuacct_set_stats_isolated(struct task_struct *p, u64 val); extern void blkcg_set_stats_isolated(struct task_struct *p, unsigned int val); +extern void cpu_set_quota_aware(struct task_struct *p, u64 val); + +static int proc_cpuquota_aware(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + int data = 0; + int err; + + table->data = &data; + err = proc_dointvec(table, write, buffer, lenp, ppos); + if (err) + return err; + + if (data) + cpu_set_quota_aware(current, 1); + else + cpu_set_quota_aware(current, 0); + + return 0; +} static int proc_stats_isolated(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos)