Merge branch 'sched-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'sched-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: sched, cgroup: Use exit hook to avoid use-after-free crash sched: Fix signed unsigned comparison in check_preempt_tick() sched: Replace rq->bkl_count with rq->rq_sched_info.bkl_count sched, autogroup: Fix CONFIG_RT_GROUP_SCHED sched_setscheduler() failure sched: Display autogroup names in /proc/sched_debug sched: Reinstate group names in /proc/sched_debug sched: Update effective_load() to use global share weights
This commit is contained in:
commit
466c19063b
|
@ -553,9 +553,6 @@ struct rq {
|
||||||
/* try_to_wake_up() stats */
|
/* try_to_wake_up() stats */
|
||||||
unsigned int ttwu_count;
|
unsigned int ttwu_count;
|
||||||
unsigned int ttwu_local;
|
unsigned int ttwu_local;
|
||||||
|
|
||||||
/* BKL stats */
|
|
||||||
unsigned int bkl_count;
|
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -609,6 +606,9 @@ static inline struct task_group *task_group(struct task_struct *p)
|
||||||
struct task_group *tg;
|
struct task_group *tg;
|
||||||
struct cgroup_subsys_state *css;
|
struct cgroup_subsys_state *css;
|
||||||
|
|
||||||
|
if (p->flags & PF_EXITING)
|
||||||
|
return &root_task_group;
|
||||||
|
|
||||||
css = task_subsys_state_check(p, cpu_cgroup_subsys_id,
|
css = task_subsys_state_check(p, cpu_cgroup_subsys_id,
|
||||||
lockdep_is_held(&task_rq(p)->lock));
|
lockdep_is_held(&task_rq(p)->lock));
|
||||||
tg = container_of(css, struct task_group, css);
|
tg = container_of(css, struct task_group, css);
|
||||||
|
@ -3887,7 +3887,7 @@ static inline void schedule_debug(struct task_struct *prev)
|
||||||
schedstat_inc(this_rq(), sched_count);
|
schedstat_inc(this_rq(), sched_count);
|
||||||
#ifdef CONFIG_SCHEDSTATS
|
#ifdef CONFIG_SCHEDSTATS
|
||||||
if (unlikely(prev->lock_depth >= 0)) {
|
if (unlikely(prev->lock_depth >= 0)) {
|
||||||
schedstat_inc(this_rq(), bkl_count);
|
schedstat_inc(this_rq(), rq_sched_info.bkl_count);
|
||||||
schedstat_inc(prev, sched_info.bkl_count);
|
schedstat_inc(prev, sched_info.bkl_count);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -4871,7 +4871,8 @@ recheck:
|
||||||
* assigned.
|
* assigned.
|
||||||
*/
|
*/
|
||||||
if (rt_bandwidth_enabled() && rt_policy(policy) &&
|
if (rt_bandwidth_enabled() && rt_policy(policy) &&
|
||||||
task_group(p)->rt_bandwidth.rt_runtime == 0) {
|
task_group(p)->rt_bandwidth.rt_runtime == 0 &&
|
||||||
|
!task_group_is_autogroup(task_group(p))) {
|
||||||
__task_rq_unlock(rq);
|
__task_rq_unlock(rq);
|
||||||
raw_spin_unlock_irqrestore(&p->pi_lock, flags);
|
raw_spin_unlock_irqrestore(&p->pi_lock, flags);
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
@ -8882,6 +8883,20 @@ cpu_cgroup_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cpu_cgroup_exit(struct cgroup_subsys *ss, struct task_struct *task)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* cgroup_exit() is called in the copy_process() failure path.
|
||||||
|
* Ignore this case since the task hasn't ran yet, this avoids
|
||||||
|
* trying to poke a half freed task state from generic code.
|
||||||
|
*/
|
||||||
|
if (!(task->flags & PF_EXITING))
|
||||||
|
return;
|
||||||
|
|
||||||
|
sched_move_task(task);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_FAIR_GROUP_SCHED
|
#ifdef CONFIG_FAIR_GROUP_SCHED
|
||||||
static int cpu_shares_write_u64(struct cgroup *cgrp, struct cftype *cftype,
|
static int cpu_shares_write_u64(struct cgroup *cgrp, struct cftype *cftype,
|
||||||
u64 shareval)
|
u64 shareval)
|
||||||
|
@ -8954,6 +8969,7 @@ struct cgroup_subsys cpu_cgroup_subsys = {
|
||||||
.destroy = cpu_cgroup_destroy,
|
.destroy = cpu_cgroup_destroy,
|
||||||
.can_attach = cpu_cgroup_can_attach,
|
.can_attach = cpu_cgroup_can_attach,
|
||||||
.attach = cpu_cgroup_attach,
|
.attach = cpu_cgroup_attach,
|
||||||
|
.exit = cpu_cgroup_exit,
|
||||||
.populate = cpu_cgroup_populate,
|
.populate = cpu_cgroup_populate,
|
||||||
.subsys_id = cpu_cgroup_subsys_id,
|
.subsys_id = cpu_cgroup_subsys_id,
|
||||||
.early_init = 1,
|
.early_init = 1,
|
||||||
|
|
|
@ -27,6 +27,11 @@ static inline void autogroup_destroy(struct kref *kref)
|
||||||
{
|
{
|
||||||
struct autogroup *ag = container_of(kref, struct autogroup, kref);
|
struct autogroup *ag = container_of(kref, struct autogroup, kref);
|
||||||
|
|
||||||
|
#ifdef CONFIG_RT_GROUP_SCHED
|
||||||
|
/* We've redirected RT tasks to the root task group... */
|
||||||
|
ag->tg->rt_se = NULL;
|
||||||
|
ag->tg->rt_rq = NULL;
|
||||||
|
#endif
|
||||||
sched_destroy_group(ag->tg);
|
sched_destroy_group(ag->tg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,6 +60,10 @@ static inline struct autogroup *autogroup_task_get(struct task_struct *p)
|
||||||
return ag;
|
return ag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_RT_GROUP_SCHED
|
||||||
|
static void free_rt_sched_group(struct task_group *tg);
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline struct autogroup *autogroup_create(void)
|
static inline struct autogroup *autogroup_create(void)
|
||||||
{
|
{
|
||||||
struct autogroup *ag = kzalloc(sizeof(*ag), GFP_KERNEL);
|
struct autogroup *ag = kzalloc(sizeof(*ag), GFP_KERNEL);
|
||||||
|
@ -72,6 +81,19 @@ static inline struct autogroup *autogroup_create(void)
|
||||||
init_rwsem(&ag->lock);
|
init_rwsem(&ag->lock);
|
||||||
ag->id = atomic_inc_return(&autogroup_seq_nr);
|
ag->id = atomic_inc_return(&autogroup_seq_nr);
|
||||||
ag->tg = tg;
|
ag->tg = tg;
|
||||||
|
#ifdef CONFIG_RT_GROUP_SCHED
|
||||||
|
/*
|
||||||
|
* Autogroup RT tasks are redirected to the root task group
|
||||||
|
* so we don't have to move tasks around upon policy change,
|
||||||
|
* or flail around trying to allocate bandwidth on the fly.
|
||||||
|
* A bandwidth exception in __sched_setscheduler() allows
|
||||||
|
* the policy change to proceed. Thereafter, task_group()
|
||||||
|
* returns &root_task_group, so zero bandwidth is required.
|
||||||
|
*/
|
||||||
|
free_rt_sched_group(tg);
|
||||||
|
tg->rt_se = root_task_group.rt_se;
|
||||||
|
tg->rt_rq = root_task_group.rt_rq;
|
||||||
|
#endif
|
||||||
tg->autogroup = ag;
|
tg->autogroup = ag;
|
||||||
|
|
||||||
return ag;
|
return ag;
|
||||||
|
@ -106,6 +128,11 @@ task_wants_autogroup(struct task_struct *p, struct task_group *tg)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool task_group_is_autogroup(struct task_group *tg)
|
||||||
|
{
|
||||||
|
return tg != &root_task_group && tg->autogroup;
|
||||||
|
}
|
||||||
|
|
||||||
static inline struct task_group *
|
static inline struct task_group *
|
||||||
autogroup_task_group(struct task_struct *p, struct task_group *tg)
|
autogroup_task_group(struct task_struct *p, struct task_group *tg)
|
||||||
{
|
{
|
||||||
|
@ -231,6 +258,11 @@ void proc_sched_autogroup_show_task(struct task_struct *p, struct seq_file *m)
|
||||||
#ifdef CONFIG_SCHED_DEBUG
|
#ifdef CONFIG_SCHED_DEBUG
|
||||||
static inline int autogroup_path(struct task_group *tg, char *buf, int buflen)
|
static inline int autogroup_path(struct task_group *tg, char *buf, int buflen)
|
||||||
{
|
{
|
||||||
|
int enabled = ACCESS_ONCE(sysctl_sched_autogroup_enabled);
|
||||||
|
|
||||||
|
if (!enabled || !tg->autogroup)
|
||||||
|
return 0;
|
||||||
|
|
||||||
return snprintf(buf, buflen, "%s-%ld", "/autogroup", tg->autogroup->id);
|
return snprintf(buf, buflen, "%s-%ld", "/autogroup", tg->autogroup->id);
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_SCHED_DEBUG */
|
#endif /* CONFIG_SCHED_DEBUG */
|
||||||
|
|
|
@ -15,6 +15,10 @@ autogroup_task_group(struct task_struct *p, struct task_group *tg);
|
||||||
|
|
||||||
static inline void autogroup_init(struct task_struct *init_task) { }
|
static inline void autogroup_init(struct task_struct *init_task) { }
|
||||||
static inline void autogroup_free(struct task_group *tg) { }
|
static inline void autogroup_free(struct task_group *tg) { }
|
||||||
|
static inline bool task_group_is_autogroup(struct task_group *tg)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static inline struct task_group *
|
static inline struct task_group *
|
||||||
autogroup_task_group(struct task_struct *p, struct task_group *tg)
|
autogroup_task_group(struct task_struct *p, struct task_group *tg)
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
#include <linux/kallsyms.h>
|
#include <linux/kallsyms.h>
|
||||||
#include <linux/utsname.h>
|
#include <linux/utsname.h>
|
||||||
|
|
||||||
|
static DEFINE_SPINLOCK(sched_debug_lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This allows printing both to /proc/sched_debug and
|
* This allows printing both to /proc/sched_debug and
|
||||||
* to the console
|
* to the console
|
||||||
|
@ -86,6 +88,26 @@ static void print_cfs_group_stats(struct seq_file *m, int cpu, struct task_group
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_CGROUP_SCHED
|
||||||
|
static char group_path[PATH_MAX];
|
||||||
|
|
||||||
|
static char *task_group_path(struct task_group *tg)
|
||||||
|
{
|
||||||
|
if (autogroup_path(tg, group_path, PATH_MAX))
|
||||||
|
return group_path;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* May be NULL if the underlying cgroup isn't fully-created yet
|
||||||
|
*/
|
||||||
|
if (!tg->css.cgroup) {
|
||||||
|
group_path[0] = '\0';
|
||||||
|
return group_path;
|
||||||
|
}
|
||||||
|
cgroup_path(tg->css.cgroup, group_path, PATH_MAX);
|
||||||
|
return group_path;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
print_task(struct seq_file *m, struct rq *rq, struct task_struct *p)
|
print_task(struct seq_file *m, struct rq *rq, struct task_struct *p)
|
||||||
{
|
{
|
||||||
|
@ -108,6 +130,9 @@ print_task(struct seq_file *m, struct rq *rq, struct task_struct *p)
|
||||||
SEQ_printf(m, "%15Ld %15Ld %15Ld.%06ld %15Ld.%06ld %15Ld.%06ld",
|
SEQ_printf(m, "%15Ld %15Ld %15Ld.%06ld %15Ld.%06ld %15Ld.%06ld",
|
||||||
0LL, 0LL, 0LL, 0L, 0LL, 0L, 0LL, 0L);
|
0LL, 0LL, 0LL, 0L, 0LL, 0L, 0LL, 0L);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_CGROUP_SCHED
|
||||||
|
SEQ_printf(m, " %s", task_group_path(task_group(p)));
|
||||||
|
#endif
|
||||||
|
|
||||||
SEQ_printf(m, "\n");
|
SEQ_printf(m, "\n");
|
||||||
}
|
}
|
||||||
|
@ -144,7 +169,11 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
|
||||||
struct sched_entity *last;
|
struct sched_entity *last;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
|
#ifdef CONFIG_FAIR_GROUP_SCHED
|
||||||
|
SEQ_printf(m, "\ncfs_rq[%d]:%s\n", cpu, task_group_path(cfs_rq->tg));
|
||||||
|
#else
|
||||||
SEQ_printf(m, "\ncfs_rq[%d]:\n", cpu);
|
SEQ_printf(m, "\ncfs_rq[%d]:\n", cpu);
|
||||||
|
#endif
|
||||||
SEQ_printf(m, " .%-30s: %Ld.%06ld\n", "exec_clock",
|
SEQ_printf(m, " .%-30s: %Ld.%06ld\n", "exec_clock",
|
||||||
SPLIT_NS(cfs_rq->exec_clock));
|
SPLIT_NS(cfs_rq->exec_clock));
|
||||||
|
|
||||||
|
@ -191,7 +220,11 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
|
||||||
|
|
||||||
void print_rt_rq(struct seq_file *m, int cpu, struct rt_rq *rt_rq)
|
void print_rt_rq(struct seq_file *m, int cpu, struct rt_rq *rt_rq)
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_RT_GROUP_SCHED
|
||||||
|
SEQ_printf(m, "\nrt_rq[%d]:%s\n", cpu, task_group_path(rt_rq->tg));
|
||||||
|
#else
|
||||||
SEQ_printf(m, "\nrt_rq[%d]:\n", cpu);
|
SEQ_printf(m, "\nrt_rq[%d]:\n", cpu);
|
||||||
|
#endif
|
||||||
|
|
||||||
#define P(x) \
|
#define P(x) \
|
||||||
SEQ_printf(m, " .%-30s: %Ld\n", #x, (long long)(rt_rq->x))
|
SEQ_printf(m, " .%-30s: %Ld\n", #x, (long long)(rt_rq->x))
|
||||||
|
@ -212,6 +245,7 @@ extern __read_mostly int sched_clock_running;
|
||||||
static void print_cpu(struct seq_file *m, int cpu)
|
static void print_cpu(struct seq_file *m, int cpu)
|
||||||
{
|
{
|
||||||
struct rq *rq = cpu_rq(cpu);
|
struct rq *rq = cpu_rq(cpu);
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
#ifdef CONFIG_X86
|
#ifdef CONFIG_X86
|
||||||
{
|
{
|
||||||
|
@ -262,14 +296,20 @@ static void print_cpu(struct seq_file *m, int cpu)
|
||||||
P(ttwu_count);
|
P(ttwu_count);
|
||||||
P(ttwu_local);
|
P(ttwu_local);
|
||||||
|
|
||||||
P(bkl_count);
|
SEQ_printf(m, " .%-30s: %d\n", "bkl_count",
|
||||||
|
rq->rq_sched_info.bkl_count);
|
||||||
|
|
||||||
#undef P
|
#undef P
|
||||||
|
#undef P64
|
||||||
#endif
|
#endif
|
||||||
|
spin_lock_irqsave(&sched_debug_lock, flags);
|
||||||
print_cfs_stats(m, cpu);
|
print_cfs_stats(m, cpu);
|
||||||
print_rt_stats(m, cpu);
|
print_rt_stats(m, cpu);
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
print_rq(m, rq, cpu);
|
print_rq(m, rq, cpu);
|
||||||
|
rcu_read_unlock();
|
||||||
|
spin_unlock_irqrestore(&sched_debug_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *sched_tunable_scaling_names[] = {
|
static const char *sched_tunable_scaling_names[] = {
|
||||||
|
|
|
@ -1062,6 +1062,9 @@ check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr)
|
||||||
struct sched_entity *se = __pick_next_entity(cfs_rq);
|
struct sched_entity *se = __pick_next_entity(cfs_rq);
|
||||||
s64 delta = curr->vruntime - se->vruntime;
|
s64 delta = curr->vruntime - se->vruntime;
|
||||||
|
|
||||||
|
if (delta < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
if (delta > ideal_runtime)
|
if (delta > ideal_runtime)
|
||||||
resched_task(rq_of(cfs_rq)->curr);
|
resched_task(rq_of(cfs_rq)->curr);
|
||||||
}
|
}
|
||||||
|
@ -1362,27 +1365,27 @@ static long effective_load(struct task_group *tg, int cpu, long wl, long wg)
|
||||||
return wl;
|
return wl;
|
||||||
|
|
||||||
for_each_sched_entity(se) {
|
for_each_sched_entity(se) {
|
||||||
long S, rw, s, a, b;
|
long lw, w;
|
||||||
|
|
||||||
S = se->my_q->tg->shares;
|
tg = se->my_q->tg;
|
||||||
s = se->load.weight;
|
w = se->my_q->load.weight;
|
||||||
rw = se->my_q->load.weight;
|
|
||||||
|
|
||||||
a = S*(rw + wl);
|
/* use this cpu's instantaneous contribution */
|
||||||
b = S*rw + s*wg;
|
lw = atomic_read(&tg->load_weight);
|
||||||
|
lw -= se->my_q->load_contribution;
|
||||||
|
lw += w + wg;
|
||||||
|
|
||||||
wl = s*(a-b);
|
wl += w;
|
||||||
|
|
||||||
if (likely(b))
|
if (lw > 0 && wl < lw)
|
||||||
wl /= b;
|
wl = (wl * tg->shares) / lw;
|
||||||
|
else
|
||||||
|
wl = tg->shares;
|
||||||
|
|
||||||
/*
|
/* zero point is MIN_SHARES */
|
||||||
* Assume the group is already running and will
|
if (wl < MIN_SHARES)
|
||||||
* thus already be accounted for in the weight.
|
wl = MIN_SHARES;
|
||||||
*
|
wl -= se->load.weight;
|
||||||
* That is, moving shares between CPUs, does not
|
|
||||||
* alter the group weight.
|
|
||||||
*/
|
|
||||||
wg = 0;
|
wg = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue