diff options
author | Li Zefan <lizefan@huawei.com> | 2013-06-09 05:14:47 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2013-06-09 11:47:13 -0400 |
commit | 388afd8549dc8be0920e00ae9404341593b6bd7c (patch) | |
tree | b54acc60359bb52585db1da9be7a4452fcc32ba6 /kernel/cpuset.c | |
parent | e44193d39e8d4d1de5d996fcd37ed75e5c704f10 (diff) |
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>
Diffstat (limited to 'kernel/cpuset.c')
-rw-r--r-- | kernel/cpuset.c | 69 |
1 files changed, 16 insertions, 53 deletions
diff --git a/kernel/cpuset.c b/kernel/cpuset.c index e902473f76bf..608fe1308b22 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c | |||
@@ -101,8 +101,6 @@ struct cpuset { | |||
101 | 101 | ||
102 | /* for custom sched domain */ | 102 | /* for custom sched domain */ |
103 | int relax_domain_level; | 103 | int relax_domain_level; |
104 | |||
105 | struct work_struct hotplug_work; | ||
106 | }; | 104 | }; |
107 | 105 | ||
108 | /* Retrieve the cpuset for a cgroup */ | 106 | /* Retrieve the cpuset for a cgroup */ |
@@ -268,12 +266,7 @@ static DEFINE_MUTEX(callback_mutex); | |||
268 | /* | 266 | /* |
269 | * CPU / memory hotplug is handled asynchronously. | 267 | * CPU / memory hotplug is handled asynchronously. |
270 | */ | 268 | */ |
271 | static struct workqueue_struct *cpuset_propagate_hotplug_wq; | ||
272 | |||
273 | static void cpuset_hotplug_workfn(struct work_struct *work); | 269 | static void cpuset_hotplug_workfn(struct work_struct *work); |
274 | static void cpuset_propagate_hotplug_workfn(struct work_struct *work); | ||
275 | static void schedule_cpuset_propagate_hotplug(struct cpuset *cs); | ||
276 | |||
277 | static DECLARE_WORK(cpuset_hotplug_work, cpuset_hotplug_workfn); | 270 | static DECLARE_WORK(cpuset_hotplug_work, cpuset_hotplug_workfn); |
278 | 271 | ||
279 | static DECLARE_WAIT_QUEUE_HEAD(cpuset_attach_wq); | 272 | static DECLARE_WAIT_QUEUE_HEAD(cpuset_attach_wq); |
@@ -1554,7 +1547,6 @@ static int cpuset_write_resmask(struct cgroup *cgrp, struct cftype *cft, | |||
1554 | * after execution capability is restored. | 1547 | * after execution capability is restored. |
1555 | */ | 1548 | */ |
1556 | flush_work(&cpuset_hotplug_work); | 1549 | flush_work(&cpuset_hotplug_work); |
1557 | flush_workqueue(cpuset_propagate_hotplug_wq); | ||
1558 | 1550 | ||
1559 | mutex_lock(&cpuset_mutex); | 1551 | mutex_lock(&cpuset_mutex); |
1560 | if (!is_cpuset_online(cs)) | 1552 | if (!is_cpuset_online(cs)) |
@@ -1821,7 +1813,6 @@ static struct cgroup_subsys_state *cpuset_css_alloc(struct cgroup *cont) | |||
1821 | cpumask_clear(cs->cpus_allowed); | 1813 | cpumask_clear(cs->cpus_allowed); |
1822 | nodes_clear(cs->mems_allowed); | 1814 | nodes_clear(cs->mems_allowed); |
1823 | fmeter_init(&cs->fmeter); | 1815 | fmeter_init(&cs->fmeter); |
1824 | INIT_WORK(&cs->hotplug_work, cpuset_propagate_hotplug_workfn); | ||
1825 | cs->relax_domain_level = -1; | 1816 | cs->relax_domain_level = -1; |
1826 | 1817 | ||
1827 | return &cs->css; | 1818 | return &cs->css; |
@@ -1984,18 +1975,17 @@ static void remove_tasks_in_empty_cpuset(struct cpuset *cs) | |||
1984 | } | 1975 | } |
1985 | 1976 | ||
1986 | /** | 1977 | /** |
1987 | * cpuset_propagate_hotplug_workfn - propagate CPU/memory hotplug to a cpuset | 1978 | * cpuset_hotplug_update_tasks - update tasks in a cpuset for hotunplug |
1988 | * @cs: cpuset in interest | 1979 | * @cs: cpuset in interest |
1989 | * | 1980 | * |
1990 | * Compare @cs's cpu and mem masks against top_cpuset and if some have gone | 1981 | * Compare @cs's cpu and mem masks against top_cpuset and if some have gone |
1991 | * offline, update @cs accordingly. If @cs ends up with no CPU or memory, | 1982 | * offline, update @cs accordingly. If @cs ends up with no CPU or memory, |
1992 | * all its tasks are moved to the nearest ancestor with both resources. | 1983 | * all its tasks are moved to the nearest ancestor with both resources. |
1993 | */ | 1984 | */ |
1994 | static void cpuset_propagate_hotplug_workfn(struct work_struct *work) | 1985 | static void cpuset_hotplug_update_tasks(struct cpuset *cs) |
1995 | { | 1986 | { |
1996 | static cpumask_t off_cpus; | 1987 | static cpumask_t off_cpus; |
1997 | static nodemask_t off_mems, tmp_mems; | 1988 | static nodemask_t off_mems, tmp_mems; |
1998 | struct cpuset *cs = container_of(work, struct cpuset, hotplug_work); | ||
1999 | bool is_empty; | 1989 | bool is_empty; |
2000 | 1990 | ||
2001 | retry: | 1991 | retry: |
@@ -2044,34 +2034,6 @@ retry: | |||
2044 | */ | 2034 | */ |
2045 | if (is_empty) | 2035 | if (is_empty) |
2046 | remove_tasks_in_empty_cpuset(cs); | 2036 | remove_tasks_in_empty_cpuset(cs); |
2047 | |||
2048 | /* the following may free @cs, should be the last operation */ | ||
2049 | css_put(&cs->css); | ||
2050 | } | ||
2051 | |||
2052 | /** | ||
2053 | * schedule_cpuset_propagate_hotplug - schedule hotplug propagation to a cpuset | ||
2054 | * @cs: cpuset of interest | ||
2055 | * | ||
2056 | * Schedule cpuset_propagate_hotplug_workfn() which will update CPU and | ||
2057 | * memory masks according to top_cpuset. | ||
2058 | */ | ||
2059 | static void schedule_cpuset_propagate_hotplug(struct cpuset *cs) | ||
2060 | { | ||
2061 | /* | ||
2062 | * Pin @cs. The refcnt will be released when the work item | ||
2063 | * finishes executing. | ||
2064 | */ | ||
2065 | if (!css_tryget(&cs->css)) | ||
2066 | return; | ||
2067 | |||
2068 | /* | ||
2069 | * Queue @cs->hotplug_work. If already pending, lose the css ref. | ||
2070 | * cpuset_propagate_hotplug_wq is ordered and propagation will | ||
2071 | * happen in the order this function is called. | ||
2072 | */ | ||
2073 | if (!queue_work(cpuset_propagate_hotplug_wq, &cs->hotplug_work)) | ||
2074 | css_put(&cs->css); | ||
2075 | } | 2037 | } |
2076 | 2038 | ||
2077 | /** | 2039 | /** |
@@ -2084,8 +2046,8 @@ static void schedule_cpuset_propagate_hotplug(struct cpuset *cs) | |||
2084 | * actively using CPU hotplug but making no active use of cpusets. | 2046 | * actively using CPU hotplug but making no active use of cpusets. |
2085 | * | 2047 | * |
2086 | * Non-root cpusets are only affected by offlining. If any CPUs or memory | 2048 | * Non-root cpusets are only affected by offlining. If any CPUs or memory |
2087 | * nodes have been taken down, cpuset_propagate_hotplug() is invoked on all | 2049 | * nodes have been taken down, cpuset_hotplug_update_tasks() is invoked on |
2088 | * descendants. | 2050 | * all descendants. |
2089 | * | 2051 | * |
2090 | * Note that CPU offlining during suspend is ignored. We don't modify | 2052 | * Note that CPU offlining during suspend is ignored. We don't modify |
2091 | * cpusets across suspend/resume cycles at all. | 2053 | * cpusets across suspend/resume cycles at all. |
@@ -2128,21 +2090,26 @@ static void cpuset_hotplug_workfn(struct work_struct *work) | |||
2128 | update_tasks_nodemask(&top_cpuset, &tmp_mems, NULL); | 2090 | update_tasks_nodemask(&top_cpuset, &tmp_mems, NULL); |
2129 | } | 2091 | } |
2130 | 2092 | ||
2093 | mutex_unlock(&cpuset_mutex); | ||
2094 | |||
2131 | /* if cpus or mems went down, we need to propagate to descendants */ | 2095 | /* if cpus or mems went down, we need to propagate to descendants */ |
2132 | if (cpus_offlined || mems_offlined) { | 2096 | if (cpus_offlined || mems_offlined) { |
2133 | struct cpuset *cs; | 2097 | struct cpuset *cs; |
2134 | struct cgroup *pos_cgrp; | 2098 | struct cgroup *pos_cgrp; |
2135 | 2099 | ||
2136 | rcu_read_lock(); | 2100 | rcu_read_lock(); |
2137 | cpuset_for_each_descendant_pre(cs, pos_cgrp, &top_cpuset) | 2101 | cpuset_for_each_descendant_pre(cs, pos_cgrp, &top_cpuset) { |
2138 | schedule_cpuset_propagate_hotplug(cs); | 2102 | if (!css_tryget(&cs->css)) |
2139 | rcu_read_unlock(); | 2103 | continue; |
2140 | } | 2104 | rcu_read_unlock(); |
2141 | 2105 | ||
2142 | mutex_unlock(&cpuset_mutex); | 2106 | cpuset_hotplug_update_tasks(cs); |
2143 | 2107 | ||
2144 | /* wait for propagations to finish */ | 2108 | rcu_read_lock(); |
2145 | flush_workqueue(cpuset_propagate_hotplug_wq); | 2109 | css_put(&cs->css); |
2110 | } | ||
2111 | rcu_read_unlock(); | ||
2112 | } | ||
2146 | 2113 | ||
2147 | /* rebuild sched domains if cpus_allowed has changed */ | 2114 | /* rebuild sched domains if cpus_allowed has changed */ |
2148 | if (cpus_updated) | 2115 | if (cpus_updated) |
@@ -2193,10 +2160,6 @@ void __init cpuset_init_smp(void) | |||
2193 | top_cpuset.mems_allowed = node_states[N_MEMORY]; | 2160 | top_cpuset.mems_allowed = node_states[N_MEMORY]; |
2194 | 2161 | ||
2195 | register_hotmemory_notifier(&cpuset_track_online_nodes_nb); | 2162 | register_hotmemory_notifier(&cpuset_track_online_nodes_nb); |
2196 | |||
2197 | cpuset_propagate_hotplug_wq = | ||
2198 | alloc_ordered_workqueue("cpuset_hotplug", 0); | ||
2199 | BUG_ON(!cpuset_propagate_hotplug_wq); | ||
2200 | } | 2163 | } |
2201 | 2164 | ||
2202 | /** | 2165 | /** |