cpuset: remove async hotplug propagation work
As we can drop rcu read lock while iterating cgroup hierarchy, we don't have to do propagation asynchronously via workqueue. Signed-off-by: Li Zefan <lizefan@huawei.com> Signed-off-by: Tejun Heo <tj@kernel.org>
This commit is contained in:
parent
e44193d39e
commit
388afd8549
|
@ -101,8 +101,6 @@ struct cpuset {
|
||||||
|
|
||||||
/* for custom sched domain */
|
/* for custom sched domain */
|
||||||
int relax_domain_level;
|
int relax_domain_level;
|
||||||
|
|
||||||
struct work_struct hotplug_work;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Retrieve the cpuset for a cgroup */
|
/* Retrieve the cpuset for a cgroup */
|
||||||
|
@ -268,12 +266,7 @@ static DEFINE_MUTEX(callback_mutex);
|
||||||
/*
|
/*
|
||||||
* CPU / memory hotplug is handled asynchronously.
|
* CPU / memory hotplug is handled asynchronously.
|
||||||
*/
|
*/
|
||||||
static struct workqueue_struct *cpuset_propagate_hotplug_wq;
|
|
||||||
|
|
||||||
static void cpuset_hotplug_workfn(struct work_struct *work);
|
static void cpuset_hotplug_workfn(struct work_struct *work);
|
||||||
static void cpuset_propagate_hotplug_workfn(struct work_struct *work);
|
|
||||||
static void schedule_cpuset_propagate_hotplug(struct cpuset *cs);
|
|
||||||
|
|
||||||
static DECLARE_WORK(cpuset_hotplug_work, cpuset_hotplug_workfn);
|
static DECLARE_WORK(cpuset_hotplug_work, cpuset_hotplug_workfn);
|
||||||
|
|
||||||
static DECLARE_WAIT_QUEUE_HEAD(cpuset_attach_wq);
|
static DECLARE_WAIT_QUEUE_HEAD(cpuset_attach_wq);
|
||||||
|
@ -1554,7 +1547,6 @@ static int cpuset_write_resmask(struct cgroup *cgrp, struct cftype *cft,
|
||||||
* after execution capability is restored.
|
* after execution capability is restored.
|
||||||
*/
|
*/
|
||||||
flush_work(&cpuset_hotplug_work);
|
flush_work(&cpuset_hotplug_work);
|
||||||
flush_workqueue(cpuset_propagate_hotplug_wq);
|
|
||||||
|
|
||||||
mutex_lock(&cpuset_mutex);
|
mutex_lock(&cpuset_mutex);
|
||||||
if (!is_cpuset_online(cs))
|
if (!is_cpuset_online(cs))
|
||||||
|
@ -1821,7 +1813,6 @@ static struct cgroup_subsys_state *cpuset_css_alloc(struct cgroup *cont)
|
||||||
cpumask_clear(cs->cpus_allowed);
|
cpumask_clear(cs->cpus_allowed);
|
||||||
nodes_clear(cs->mems_allowed);
|
nodes_clear(cs->mems_allowed);
|
||||||
fmeter_init(&cs->fmeter);
|
fmeter_init(&cs->fmeter);
|
||||||
INIT_WORK(&cs->hotplug_work, cpuset_propagate_hotplug_workfn);
|
|
||||||
cs->relax_domain_level = -1;
|
cs->relax_domain_level = -1;
|
||||||
|
|
||||||
return &cs->css;
|
return &cs->css;
|
||||||
|
@ -1984,18 +1975,17 @@ static void remove_tasks_in_empty_cpuset(struct cpuset *cs)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cpuset_propagate_hotplug_workfn - propagate CPU/memory hotplug to a cpuset
|
* cpuset_hotplug_update_tasks - update tasks in a cpuset for hotunplug
|
||||||
* @cs: cpuset in interest
|
* @cs: cpuset in interest
|
||||||
*
|
*
|
||||||
* Compare @cs's cpu and mem masks against top_cpuset and if some have gone
|
* Compare @cs's cpu and mem masks against top_cpuset and if some have gone
|
||||||
* offline, update @cs accordingly. If @cs ends up with no CPU or memory,
|
* offline, update @cs accordingly. If @cs ends up with no CPU or memory,
|
||||||
* all its tasks are moved to the nearest ancestor with both resources.
|
* all its tasks are moved to the nearest ancestor with both resources.
|
||||||
*/
|
*/
|
||||||
static void cpuset_propagate_hotplug_workfn(struct work_struct *work)
|
static void cpuset_hotplug_update_tasks(struct cpuset *cs)
|
||||||
{
|
{
|
||||||
static cpumask_t off_cpus;
|
static cpumask_t off_cpus;
|
||||||
static nodemask_t off_mems, tmp_mems;
|
static nodemask_t off_mems, tmp_mems;
|
||||||
struct cpuset *cs = container_of(work, struct cpuset, hotplug_work);
|
|
||||||
bool is_empty;
|
bool is_empty;
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
|
@ -2044,34 +2034,6 @@ retry:
|
||||||
*/
|
*/
|
||||||
if (is_empty)
|
if (is_empty)
|
||||||
remove_tasks_in_empty_cpuset(cs);
|
remove_tasks_in_empty_cpuset(cs);
|
||||||
|
|
||||||
/* the following may free @cs, should be the last operation */
|
|
||||||
css_put(&cs->css);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* schedule_cpuset_propagate_hotplug - schedule hotplug propagation to a cpuset
|
|
||||||
* @cs: cpuset of interest
|
|
||||||
*
|
|
||||||
* Schedule cpuset_propagate_hotplug_workfn() which will update CPU and
|
|
||||||
* memory masks according to top_cpuset.
|
|
||||||
*/
|
|
||||||
static void schedule_cpuset_propagate_hotplug(struct cpuset *cs)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Pin @cs. The refcnt will be released when the work item
|
|
||||||
* finishes executing.
|
|
||||||
*/
|
|
||||||
if (!css_tryget(&cs->css))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Queue @cs->hotplug_work. If already pending, lose the css ref.
|
|
||||||
* cpuset_propagate_hotplug_wq is ordered and propagation will
|
|
||||||
* happen in the order this function is called.
|
|
||||||
*/
|
|
||||||
if (!queue_work(cpuset_propagate_hotplug_wq, &cs->hotplug_work))
|
|
||||||
css_put(&cs->css);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2084,8 +2046,8 @@ static void schedule_cpuset_propagate_hotplug(struct cpuset *cs)
|
||||||
* actively using CPU hotplug but making no active use of cpusets.
|
* actively using CPU hotplug but making no active use of cpusets.
|
||||||
*
|
*
|
||||||
* Non-root cpusets are only affected by offlining. If any CPUs or memory
|
* Non-root cpusets are only affected by offlining. If any CPUs or memory
|
||||||
* nodes have been taken down, cpuset_propagate_hotplug() is invoked on all
|
* nodes have been taken down, cpuset_hotplug_update_tasks() is invoked on
|
||||||
* descendants.
|
* all descendants.
|
||||||
*
|
*
|
||||||
* Note that CPU offlining during suspend is ignored. We don't modify
|
* Note that CPU offlining during suspend is ignored. We don't modify
|
||||||
* cpusets across suspend/resume cycles at all.
|
* cpusets across suspend/resume cycles at all.
|
||||||
|
@ -2128,22 +2090,27 @@ static void cpuset_hotplug_workfn(struct work_struct *work)
|
||||||
update_tasks_nodemask(&top_cpuset, &tmp_mems, NULL);
|
update_tasks_nodemask(&top_cpuset, &tmp_mems, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&cpuset_mutex);
|
||||||
|
|
||||||
/* if cpus or mems went down, we need to propagate to descendants */
|
/* if cpus or mems went down, we need to propagate to descendants */
|
||||||
if (cpus_offlined || mems_offlined) {
|
if (cpus_offlined || mems_offlined) {
|
||||||
struct cpuset *cs;
|
struct cpuset *cs;
|
||||||
struct cgroup *pos_cgrp;
|
struct cgroup *pos_cgrp;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
cpuset_for_each_descendant_pre(cs, pos_cgrp, &top_cpuset)
|
cpuset_for_each_descendant_pre(cs, pos_cgrp, &top_cpuset) {
|
||||||
schedule_cpuset_propagate_hotplug(cs);
|
if (!css_tryget(&cs->css))
|
||||||
|
continue;
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
cpuset_hotplug_update_tasks(cs);
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
css_put(&cs->css);
|
||||||
|
}
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&cpuset_mutex);
|
|
||||||
|
|
||||||
/* wait for propagations to finish */
|
|
||||||
flush_workqueue(cpuset_propagate_hotplug_wq);
|
|
||||||
|
|
||||||
/* rebuild sched domains if cpus_allowed has changed */
|
/* rebuild sched domains if cpus_allowed has changed */
|
||||||
if (cpus_updated)
|
if (cpus_updated)
|
||||||
rebuild_sched_domains();
|
rebuild_sched_domains();
|
||||||
|
@ -2193,10 +2160,6 @@ void __init cpuset_init_smp(void)
|
||||||
top_cpuset.mems_allowed = node_states[N_MEMORY];
|
top_cpuset.mems_allowed = node_states[N_MEMORY];
|
||||||
|
|
||||||
register_hotmemory_notifier(&cpuset_track_online_nodes_nb);
|
register_hotmemory_notifier(&cpuset_track_online_nodes_nb);
|
||||||
|
|
||||||
cpuset_propagate_hotplug_wq =
|
|
||||||
alloc_ordered_workqueue("cpuset_hotplug", 0);
|
|
||||||
BUG_ON(!cpuset_propagate_hotplug_wq);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue