Skip to content

Commit

Permalink
cpuset: remove async hotplug propagation work
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Li Zefan authored and Tejun Heo committed Jun 9, 2013
1 parent e44193d commit 388afd8
Showing 1 changed file with 16 additions and 53 deletions.
69 changes: 16 additions & 53 deletions kernel/cpuset.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,6 @@ struct cpuset {

/* for custom sched domain */
int relax_domain_level;

struct work_struct hotplug_work;
};

/* Retrieve the cpuset for a cgroup */
Expand Down Expand Up @@ -268,12 +266,7 @@ static DEFINE_MUTEX(callback_mutex);
/*
* 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_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_WAIT_QUEUE_HEAD(cpuset_attach_wq);
Expand Down Expand Up @@ -1554,7 +1547,6 @@ static int cpuset_write_resmask(struct cgroup *cgrp, struct cftype *cft,
* after execution capability is restored.
*/
flush_work(&cpuset_hotplug_work);
flush_workqueue(cpuset_propagate_hotplug_wq);

mutex_lock(&cpuset_mutex);
if (!is_cpuset_online(cs))
Expand Down Expand Up @@ -1821,7 +1813,6 @@ static struct cgroup_subsys_state *cpuset_css_alloc(struct cgroup *cont)
cpumask_clear(cs->cpus_allowed);
nodes_clear(cs->mems_allowed);
fmeter_init(&cs->fmeter);
INIT_WORK(&cs->hotplug_work, cpuset_propagate_hotplug_workfn);
cs->relax_domain_level = -1;

return &cs->css;
Expand Down Expand Up @@ -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
*
* 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,
* 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 nodemask_t off_mems, tmp_mems;
struct cpuset *cs = container_of(work, struct cpuset, hotplug_work);
bool is_empty;

retry:
Expand Down Expand Up @@ -2044,34 +2034,6 @@ static void cpuset_propagate_hotplug_workfn(struct work_struct *work)
*/
if (is_empty)
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);
}

/**
Expand All @@ -2084,8 +2046,8 @@ static void schedule_cpuset_propagate_hotplug(struct cpuset *cs)
* actively using CPU hotplug but making no active use of cpusets.
*
* 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
* descendants.
* nodes have been taken down, cpuset_hotplug_update_tasks() is invoked on
* all descendants.
*
* Note that CPU offlining during suspend is ignored. We don't modify
* cpusets across suspend/resume cycles at all.
Expand Down Expand Up @@ -2128,21 +2090,26 @@ static void cpuset_hotplug_workfn(struct work_struct *work)
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_offlined || mems_offlined) {
struct cpuset *cs;
struct cgroup *pos_cgrp;

rcu_read_lock();
cpuset_for_each_descendant_pre(cs, pos_cgrp, &top_cpuset)
schedule_cpuset_propagate_hotplug(cs);
rcu_read_unlock();
}
cpuset_for_each_descendant_pre(cs, pos_cgrp, &top_cpuset) {
if (!css_tryget(&cs->css))
continue;
rcu_read_unlock();

mutex_unlock(&cpuset_mutex);
cpuset_hotplug_update_tasks(cs);

/* wait for propagations to finish */
flush_workqueue(cpuset_propagate_hotplug_wq);
rcu_read_lock();
css_put(&cs->css);
}
rcu_read_unlock();
}

/* rebuild sched domains if cpus_allowed has changed */
if (cpus_updated)
Expand Down Expand Up @@ -2193,10 +2160,6 @@ void __init cpuset_init_smp(void)
top_cpuset.mems_allowed = node_states[N_MEMORY];

register_hotmemory_notifier(&cpuset_track_online_nodes_nb);

cpuset_propagate_hotplug_wq =
alloc_ordered_workqueue("cpuset_hotplug", 0);
BUG_ON(!cpuset_propagate_hotplug_wq);
}

/**
Expand Down

0 comments on commit 388afd8

Please sign in to comment.