cgroup/cpuset: move legacy hotplug update to cpuset-v1.c
There are some differents about hotplug update between cpuset v1 and cpuset v2. Move the legacy code to cpuset-v1.c. 'update_tasks_cpumask' and 'update_tasks_nodemask' are both used in cpuset v1 and cpuset v2, declare them in cpuset-internal.h. The change from original code is that use callback_lock helpers to get callback_lock lock/unlock. Signed-off-by: Chen Ridong <chenridong@huawei.com> Acked-by: Waiman Long <longman@redhat.com> Signed-off-by: Tejun Heo <tj@kernel.org>
This commit is contained in:
@@ -241,6 +241,8 @@ static inline int is_spread_slab(const struct cpuset *cs)
|
||||
void rebuild_sched_domains_locked(void);
|
||||
void callback_lock_irq(void);
|
||||
void callback_unlock_irq(void);
|
||||
void update_tasks_cpumask(struct cpuset *cs, struct cpumask *new_cpus);
|
||||
void update_tasks_nodemask(struct cpuset *cs);
|
||||
|
||||
/*
|
||||
* cpuset-v1.c
|
||||
@@ -253,5 +255,8 @@ s64 cpuset_read_s64(struct cgroup_subsys_state *css, struct cftype *cft);
|
||||
void cpuset_update_task_spread_flags(struct cpuset *cs,
|
||||
struct task_struct *tsk);
|
||||
void update_tasks_flags(struct cpuset *cs);
|
||||
void hotplug_update_tasks_legacy(struct cpuset *cs,
|
||||
struct cpumask *new_cpus, nodemask_t *new_mems,
|
||||
bool cpus_updated, bool mems_updated);
|
||||
|
||||
#endif /* __CPUSET_INTERNAL_H */
|
||||
|
||||
@@ -2,6 +2,14 @@
|
||||
|
||||
#include "cpuset-internal.h"
|
||||
|
||||
/*
|
||||
* Legacy hierarchy call to cgroup_transfer_tasks() is handled asynchrously
|
||||
*/
|
||||
struct cpuset_remove_tasks_struct {
|
||||
struct work_struct work;
|
||||
struct cpuset *cs;
|
||||
};
|
||||
|
||||
/*
|
||||
* Frequency meter - How fast is some event occurring?
|
||||
*
|
||||
@@ -236,3 +244,86 @@ void update_tasks_flags(struct cpuset *cs)
|
||||
cpuset_update_task_spread_flags(cs, task);
|
||||
css_task_iter_end(&it);
|
||||
}
|
||||
|
||||
/*
|
||||
* If CPU and/or memory hotplug handlers, below, unplug any CPUs
|
||||
* or memory nodes, we need to walk over the cpuset hierarchy,
|
||||
* removing that CPU or node from all cpusets. If this removes the
|
||||
* last CPU or node from a cpuset, then move the tasks in the empty
|
||||
* cpuset to its next-highest non-empty parent.
|
||||
*/
|
||||
static void remove_tasks_in_empty_cpuset(struct cpuset *cs)
|
||||
{
|
||||
struct cpuset *parent;
|
||||
|
||||
/*
|
||||
* Find its next-highest non-empty parent, (top cpuset
|
||||
* has online cpus, so can't be empty).
|
||||
*/
|
||||
parent = parent_cs(cs);
|
||||
while (cpumask_empty(parent->cpus_allowed) ||
|
||||
nodes_empty(parent->mems_allowed))
|
||||
parent = parent_cs(parent);
|
||||
|
||||
if (cgroup_transfer_tasks(parent->css.cgroup, cs->css.cgroup)) {
|
||||
pr_err("cpuset: failed to transfer tasks out of empty cpuset ");
|
||||
pr_cont_cgroup_name(cs->css.cgroup);
|
||||
pr_cont("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void cpuset_migrate_tasks_workfn(struct work_struct *work)
|
||||
{
|
||||
struct cpuset_remove_tasks_struct *s;
|
||||
|
||||
s = container_of(work, struct cpuset_remove_tasks_struct, work);
|
||||
remove_tasks_in_empty_cpuset(s->cs);
|
||||
css_put(&s->cs->css);
|
||||
kfree(s);
|
||||
}
|
||||
|
||||
void hotplug_update_tasks_legacy(struct cpuset *cs,
|
||||
struct cpumask *new_cpus, nodemask_t *new_mems,
|
||||
bool cpus_updated, bool mems_updated)
|
||||
{
|
||||
bool is_empty;
|
||||
|
||||
callback_lock_irq();
|
||||
cpumask_copy(cs->cpus_allowed, new_cpus);
|
||||
cpumask_copy(cs->effective_cpus, new_cpus);
|
||||
cs->mems_allowed = *new_mems;
|
||||
cs->effective_mems = *new_mems;
|
||||
callback_unlock_irq();
|
||||
|
||||
/*
|
||||
* Don't call update_tasks_cpumask() if the cpuset becomes empty,
|
||||
* as the tasks will be migrated to an ancestor.
|
||||
*/
|
||||
if (cpus_updated && !cpumask_empty(cs->cpus_allowed))
|
||||
update_tasks_cpumask(cs, new_cpus);
|
||||
if (mems_updated && !nodes_empty(cs->mems_allowed))
|
||||
update_tasks_nodemask(cs);
|
||||
|
||||
is_empty = cpumask_empty(cs->cpus_allowed) ||
|
||||
nodes_empty(cs->mems_allowed);
|
||||
|
||||
/*
|
||||
* Move tasks to the nearest ancestor with execution resources,
|
||||
* This is full cgroup operation which will also call back into
|
||||
* cpuset. Execute it asynchronously using workqueue.
|
||||
*/
|
||||
if (is_empty && cs->css.cgroup->nr_populated_csets &&
|
||||
css_tryget_online(&cs->css)) {
|
||||
struct cpuset_remove_tasks_struct *s;
|
||||
|
||||
s = kzalloc(sizeof(*s), GFP_KERNEL);
|
||||
if (WARN_ON_ONCE(!s)) {
|
||||
css_put(&cs->css);
|
||||
return;
|
||||
}
|
||||
|
||||
s->cs = cs;
|
||||
INIT_WORK(&s->work, cpuset_migrate_tasks_workfn);
|
||||
schedule_work(&s->work);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-94
@@ -65,14 +65,6 @@ static const char * const perr_strings[] = {
|
||||
[PERR_ACCESS] = "Enable partition not permitted",
|
||||
};
|
||||
|
||||
/*
|
||||
* Legacy hierarchy call to cgroup_transfer_tasks() is handled asynchrously
|
||||
*/
|
||||
struct cpuset_remove_tasks_struct {
|
||||
struct work_struct work;
|
||||
struct cpuset *cs;
|
||||
};
|
||||
|
||||
/*
|
||||
* Exclusive CPUs distributed out to sub-partitions of top_cpuset
|
||||
*/
|
||||
@@ -1144,7 +1136,7 @@ void rebuild_sched_domains(void)
|
||||
* is used instead of effective_cpus to make sure all offline CPUs are also
|
||||
* included as hotplug code won't update cpumasks for tasks in top_cpuset.
|
||||
*/
|
||||
static void update_tasks_cpumask(struct cpuset *cs, struct cpumask *new_cpus)
|
||||
void update_tasks_cpumask(struct cpuset *cs, struct cpumask *new_cpus)
|
||||
{
|
||||
struct css_task_iter it;
|
||||
struct task_struct *task;
|
||||
@@ -2597,7 +2589,7 @@ static void *cpuset_being_rebound;
|
||||
* effective cpuset's. As this function is called with cpuset_mutex held,
|
||||
* cpuset membership stays stable.
|
||||
*/
|
||||
static void update_tasks_nodemask(struct cpuset *cs)
|
||||
void update_tasks_nodemask(struct cpuset *cs)
|
||||
{
|
||||
static nodemask_t newmems; /* protected by cpuset_mutex */
|
||||
struct css_task_iter it;
|
||||
@@ -3936,90 +3928,6 @@ int __init cpuset_init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If CPU and/or memory hotplug handlers, below, unplug any CPUs
|
||||
* or memory nodes, we need to walk over the cpuset hierarchy,
|
||||
* removing that CPU or node from all cpusets. If this removes the
|
||||
* last CPU or node from a cpuset, then move the tasks in the empty
|
||||
* cpuset to its next-highest non-empty parent.
|
||||
*/
|
||||
static void remove_tasks_in_empty_cpuset(struct cpuset *cs)
|
||||
{
|
||||
struct cpuset *parent;
|
||||
|
||||
/*
|
||||
* Find its next-highest non-empty parent, (top cpuset
|
||||
* has online cpus, so can't be empty).
|
||||
*/
|
||||
parent = parent_cs(cs);
|
||||
while (cpumask_empty(parent->cpus_allowed) ||
|
||||
nodes_empty(parent->mems_allowed))
|
||||
parent = parent_cs(parent);
|
||||
|
||||
if (cgroup_transfer_tasks(parent->css.cgroup, cs->css.cgroup)) {
|
||||
pr_err("cpuset: failed to transfer tasks out of empty cpuset ");
|
||||
pr_cont_cgroup_name(cs->css.cgroup);
|
||||
pr_cont("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void cpuset_migrate_tasks_workfn(struct work_struct *work)
|
||||
{
|
||||
struct cpuset_remove_tasks_struct *s;
|
||||
|
||||
s = container_of(work, struct cpuset_remove_tasks_struct, work);
|
||||
remove_tasks_in_empty_cpuset(s->cs);
|
||||
css_put(&s->cs->css);
|
||||
kfree(s);
|
||||
}
|
||||
|
||||
static void
|
||||
hotplug_update_tasks_legacy(struct cpuset *cs,
|
||||
struct cpumask *new_cpus, nodemask_t *new_mems,
|
||||
bool cpus_updated, bool mems_updated)
|
||||
{
|
||||
bool is_empty;
|
||||
|
||||
spin_lock_irq(&callback_lock);
|
||||
cpumask_copy(cs->cpus_allowed, new_cpus);
|
||||
cpumask_copy(cs->effective_cpus, new_cpus);
|
||||
cs->mems_allowed = *new_mems;
|
||||
cs->effective_mems = *new_mems;
|
||||
spin_unlock_irq(&callback_lock);
|
||||
|
||||
/*
|
||||
* Don't call update_tasks_cpumask() if the cpuset becomes empty,
|
||||
* as the tasks will be migrated to an ancestor.
|
||||
*/
|
||||
if (cpus_updated && !cpumask_empty(cs->cpus_allowed))
|
||||
update_tasks_cpumask(cs, new_cpus);
|
||||
if (mems_updated && !nodes_empty(cs->mems_allowed))
|
||||
update_tasks_nodemask(cs);
|
||||
|
||||
is_empty = cpumask_empty(cs->cpus_allowed) ||
|
||||
nodes_empty(cs->mems_allowed);
|
||||
|
||||
/*
|
||||
* Move tasks to the nearest ancestor with execution resources,
|
||||
* This is full cgroup operation which will also call back into
|
||||
* cpuset. Execute it asynchronously using workqueue.
|
||||
*/
|
||||
if (is_empty && cs->css.cgroup->nr_populated_csets &&
|
||||
css_tryget_online(&cs->css)) {
|
||||
struct cpuset_remove_tasks_struct *s;
|
||||
|
||||
s = kzalloc(sizeof(*s), GFP_KERNEL);
|
||||
if (WARN_ON_ONCE(!s)) {
|
||||
css_put(&cs->css);
|
||||
return;
|
||||
}
|
||||
|
||||
s->cs = cs;
|
||||
INIT_WORK(&s->work, cpuset_migrate_tasks_workfn);
|
||||
schedule_work(&s->work);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
hotplug_update_tasks(struct cpuset *cs,
|
||||
struct cpumask *new_cpus, nodemask_t *new_mems,
|
||||
|
||||
Reference in New Issue
Block a user