Skip to content
14 changes: 6 additions & 8 deletions include/linux/cgroup.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@

struct kernel_clone_args;

#ifdef CONFIG_CGROUPS

/*
* All weight knobs on the default hierarchy should use the following min,
* default and max values. The default value is the logarithmic center of
Expand All @@ -40,13 +38,13 @@ struct kernel_clone_args;
#define CGROUP_WEIGHT_DFL 100
#define CGROUP_WEIGHT_MAX 10000

/* walk only threadgroup leaders */
#define CSS_TASK_ITER_PROCS (1U << 0)
/* walk all threaded css_sets in the domain */
#define CSS_TASK_ITER_THREADED (1U << 1)
#ifdef CONFIG_CGROUPS

/* internal flags */
#define CSS_TASK_ITER_SKIPPED (1U << 16)
enum {
CSS_TASK_ITER_PROCS = (1U << 0), /* walk only threadgroup leaders */
CSS_TASK_ITER_THREADED = (1U << 1), /* walk all threaded css_sets in the domain */
CSS_TASK_ITER_SKIPPED = (1U << 16), /* internal flags */
};

/* a css_task_iter should be treated as an opaque object */
struct css_task_iter {
Expand Down
3 changes: 2 additions & 1 deletion include/linux/sched/task.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ extern asmlinkage void schedule_tail(struct task_struct *prev);
extern void init_idle(struct task_struct *idle, int cpu);

extern int sched_fork(unsigned long clone_flags, struct task_struct *p);
extern void sched_cgroup_fork(struct task_struct *p, struct kernel_clone_args *kargs);
extern int sched_cgroup_fork(struct task_struct *p, struct kernel_clone_args *kargs);
extern void sched_cancel_fork(struct task_struct *p);
extern void sched_post_fork(struct task_struct *p);
extern void sched_dead(struct task_struct *p);

Expand Down
18 changes: 12 additions & 6 deletions kernel/cgroup/cgroup.c
Original file line number Diff line number Diff line change
Expand Up @@ -4950,9 +4950,11 @@ static void css_task_iter_advance(struct css_task_iter *it)
void css_task_iter_start(struct cgroup_subsys_state *css, unsigned int flags,
struct css_task_iter *it)
{
unsigned long irqflags;

memset(it, 0, sizeof(*it));

spin_lock_irq(&css_set_lock);
spin_lock_irqsave(&css_set_lock, irqflags);

it->ss = css->ss;
it->flags = flags;
Expand All @@ -4966,7 +4968,7 @@ void css_task_iter_start(struct cgroup_subsys_state *css, unsigned int flags,

css_task_iter_advance(it);

spin_unlock_irq(&css_set_lock);
spin_unlock_irqrestore(&css_set_lock, irqflags);
}

/**
Expand All @@ -4979,12 +4981,14 @@ void css_task_iter_start(struct cgroup_subsys_state *css, unsigned int flags,
*/
struct task_struct *css_task_iter_next(struct css_task_iter *it)
{
unsigned long irqflags;

if (it->cur_task) {
put_task_struct(it->cur_task);
it->cur_task = NULL;
}

spin_lock_irq(&css_set_lock);
spin_lock_irqsave(&css_set_lock, irqflags);

/* @it may be half-advanced by skips, finish advancing */
if (it->flags & CSS_TASK_ITER_SKIPPED)
Expand All @@ -4997,7 +5001,7 @@ struct task_struct *css_task_iter_next(struct css_task_iter *it)
css_task_iter_advance(it);
}

spin_unlock_irq(&css_set_lock);
spin_unlock_irqrestore(&css_set_lock, irqflags);

return it->cur_task;
}
Expand All @@ -5010,11 +5014,13 @@ struct task_struct *css_task_iter_next(struct css_task_iter *it)
*/
void css_task_iter_end(struct css_task_iter *it)
{
unsigned long irqflags;

if (it->cur_cset) {
spin_lock_irq(&css_set_lock);
spin_lock_irqsave(&css_set_lock, irqflags);
list_del(&it->iters_node);
put_css_set_locked(it->cur_cset);
spin_unlock_irq(&css_set_lock);
spin_unlock_irqrestore(&css_set_lock, irqflags);
}

if (it->cur_dcset)
Expand Down
15 changes: 10 additions & 5 deletions kernel/fork.c
Original file line number Diff line number Diff line change
Expand Up @@ -2557,7 +2557,7 @@ __latent_entropy struct task_struct *copy_process(

retval = perf_event_init_task(p, clone_flags);
if (retval)
goto bad_fork_cleanup_policy;
goto bad_fork_sched_cancel_fork;
retval = audit_alloc(p);
if (retval)
goto bad_fork_cleanup_perf;
Expand Down Expand Up @@ -2689,7 +2689,9 @@ __latent_entropy struct task_struct *copy_process(
* cgroup specific, it unconditionally needs to place the task on a
* runqueue.
*/
sched_cgroup_fork(p, args);
retval = sched_cgroup_fork(p, args);
if (retval)
goto bad_fork_cancel_cgroup;

/*
* From this point on we must avoid any synchronous user-space
Expand Down Expand Up @@ -2735,13 +2737,13 @@ __latent_entropy struct task_struct *copy_process(
/* Don't start children in a dying pid namespace */
if (unlikely(!(ns_of_pid(pid)->pid_allocated & PIDNS_ADDING))) {
retval = -ENOMEM;
goto bad_fork_cancel_cgroup;
goto bad_fork_core_free;
}

/* Let kill terminate clone/fork in the middle */
if (fatal_signal_pending(current)) {
retval = -EINTR;
goto bad_fork_cancel_cgroup;
goto bad_fork_core_free;
}

/* No more failure paths after this point. */
Expand Down Expand Up @@ -2815,10 +2817,11 @@ __latent_entropy struct task_struct *copy_process(

return p;

bad_fork_cancel_cgroup:
bad_fork_core_free:
sched_core_free(p);
spin_unlock(&current->sighand->siglock);
write_unlock_irq(&tasklist_lock);
bad_fork_cancel_cgroup:
cgroup_cancel_fork(p, args);
bad_fork_put_pidfd:
if (clone_flags & CLONE_PIDFD) {
Expand Down Expand Up @@ -2857,6 +2860,8 @@ __latent_entropy struct task_struct *copy_process(
audit_free(p);
bad_fork_cleanup_perf:
perf_event_free_task(p);
bad_fork_sched_cancel_fork:
sched_cancel_fork(p);
bad_fork_cleanup_policy:
lockdep_free_task(p);
#ifdef CONFIG_NUMA
Expand Down
60 changes: 38 additions & 22 deletions kernel/sched/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1341,8 +1341,8 @@ void set_load_weight(struct task_struct *p, bool update_load)
* SCHED_OTHER tasks have to update their load when changing their
* weight
*/
if (update_load && p->sched_class == &fair_sched_class)
reweight_task(p, &lw);
if (update_load && p->sched_class->reweight_task)
p->sched_class->reweight_task(task_rq(p), p, &lw);
else
p->se.load = lw;
}
Expand Down Expand Up @@ -2064,6 +2064,17 @@ inline int task_curr(const struct task_struct *p)
return cpu_curr(task_cpu(p)) == p;
}

/*
* ->switching_to() is called with the pi_lock and rq_lock held and must not
* mess with locking.
*/
void check_class_changing(struct rq *rq, struct task_struct *p,
const struct sched_class *prev_class)
{
if (prev_class != p->sched_class && p->sched_class->switching_to)
p->sched_class->switching_to(rq, p);
}

/*
* switched_from, switched_to and prio_changed must _NOT_ drop rq->lock,
* use the balance_callback list if you want balancing.
Expand Down Expand Up @@ -4648,7 +4659,7 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p)
return 0;
}

void sched_cgroup_fork(struct task_struct *p, struct kernel_clone_args *kargs)
int sched_cgroup_fork(struct task_struct *p, struct kernel_clone_args *kargs)
{
unsigned long flags;

Expand All @@ -4675,6 +4686,12 @@ void sched_cgroup_fork(struct task_struct *p, struct kernel_clone_args *kargs)
if (p->sched_class->task_fork)
p->sched_class->task_fork(p);
raw_spin_unlock_irqrestore(&p->pi_lock, flags);

return 0;
}

void sched_cancel_fork(struct task_struct *p)
{
}

void sched_post_fork(struct task_struct *p)
Expand Down Expand Up @@ -7128,6 +7145,7 @@ void rt_mutex_setprio(struct task_struct *p, struct task_struct *pi_task)

p->sched_class = next_class;
p->prio = prio;
check_class_changing(rq, p, prev_class);

if (queued)
enqueue_task(rq, p, queue_flag);
Expand Down Expand Up @@ -8301,12 +8319,12 @@ void __init sched_init(void)
int i;

/* Make sure the linker didn't screw up */
BUG_ON(&idle_sched_class != &fair_sched_class + 1 ||
&fair_sched_class != &rt_sched_class + 1 ||
&rt_sched_class != &dl_sched_class + 1);
#ifdef CONFIG_SMP
BUG_ON(&dl_sched_class != &stop_sched_class + 1);
BUG_ON(!sched_class_above(&stop_sched_class, &dl_sched_class));
#endif
BUG_ON(!sched_class_above(&dl_sched_class, &rt_sched_class));
BUG_ON(!sched_class_above(&rt_sched_class, &fair_sched_class));
BUG_ON(!sched_class_above(&fair_sched_class, &idle_sched_class));

wait_bit_init();

Expand Down Expand Up @@ -9681,37 +9699,35 @@ static int cpu_local_stat_show(struct seq_file *sf,
}

#ifdef CONFIG_FAIR_GROUP_SCHED

static unsigned long tg_weight(struct task_group *tg)
{
return scale_load_down(tg->shares);
}

static u64 cpu_weight_read_u64(struct cgroup_subsys_state *css,
struct cftype *cft)
{
struct task_group *tg = css_tg(css);
u64 weight = scale_load_down(tg->shares);

return DIV_ROUND_CLOSEST_ULL(weight * CGROUP_WEIGHT_DFL, 1024);
return sched_weight_to_cgroup(tg_weight(css_tg(css)));
}

static int cpu_weight_write_u64(struct cgroup_subsys_state *css,
struct cftype *cft, u64 weight)
struct cftype *cft, u64 cgrp_weight)
{
/*
* cgroup weight knobs should use the common MIN, DFL and MAX
* values which are 1, 100 and 10000 respectively. While it loses
* a bit of range on both ends, it maps pretty well onto the shares
* value used by scheduler and the round-trip conversions preserve
* the original value over the entire range.
*/
if (weight < CGROUP_WEIGHT_MIN || weight > CGROUP_WEIGHT_MAX)
unsigned long weight;

if (cgrp_weight < CGROUP_WEIGHT_MIN || cgrp_weight > CGROUP_WEIGHT_MAX)
return -ERANGE;

weight = DIV_ROUND_CLOSEST_ULL(weight * 1024, CGROUP_WEIGHT_DFL);
weight = sched_weight_from_cgroup(cgrp_weight);

return sched_group_set_shares(css_tg(css), scale_load(weight));
}

static s64 cpu_weight_nice_read_s64(struct cgroup_subsys_state *css,
struct cftype *cft)
{
unsigned long weight = scale_load_down(css_tg(css)->shares);
unsigned long weight = tg_weight(css_tg(css));
int last_delta = INT_MAX;
int prio, delta;

Expand Down
21 changes: 6 additions & 15 deletions kernel/sched/fair.c
Original file line number Diff line number Diff line change
Expand Up @@ -3958,7 +3958,7 @@ static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
}
}

void reweight_task(struct task_struct *p, const struct load_weight *lw)
static void reweight_task_fair(struct rq *this_rq, struct task_struct *p, const struct load_weight *lw)
{
struct sched_entity *se = &p->se;
struct cfs_rq *cfs_rq = cfs_rq_of(se);
Expand Down Expand Up @@ -8692,7 +8692,7 @@ static void check_preempt_wakeup_fair(struct rq *rq, struct task_struct *p, int
/*
* BATCH and IDLE tasks do not preempt others.
*/
if (unlikely(p->policy != SCHED_NORMAL))
if (unlikely(!normal_policy(p->policy)))
return;

cfs_rq = cfs_rq_of(se);
Expand Down Expand Up @@ -9649,28 +9649,18 @@ static inline void update_blocked_load_status(struct rq *rq, bool has_blocked) {

static bool __update_blocked_others(struct rq *rq, bool *done)
{
const struct sched_class *curr_class;
u64 now = rq_clock_pelt(rq);
unsigned long thermal_pressure;
bool decayed;
bool updated;

/*
* update_load_avg() can call cpufreq_update_util(). Make sure that RT,
* DL and IRQ signals have been updated before updating CFS.
*/
curr_class = rq->curr->sched_class;

thermal_pressure = arch_scale_thermal_pressure(cpu_of(rq));

decayed = update_rt_rq_load_avg(now, rq, curr_class == &rt_sched_class) |
update_dl_rq_load_avg(now, rq, curr_class == &dl_sched_class) |
update_thermal_load_avg(rq_clock_thermal(rq), rq, thermal_pressure) |
update_irq_load_avg(rq, 0);
updated = update_other_load_avgs(rq);

if (others_have_blocked(rq))
*done = false;

return decayed;
return updated;
}

#ifdef CONFIG_FAIR_GROUP_SCHED
Expand Down Expand Up @@ -13551,6 +13541,7 @@ DEFINE_SCHED_CLASS(fair) = {
.task_tick = task_tick_fair,
.task_fork = task_fork_fair,

.reweight_task = reweight_task_fair,
.prio_changed = prio_changed_fair,
.switched_from = switched_from_fair,
.switched_to = switched_to_fair,
Expand Down
Loading
Loading