aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorDaniel Wagner <daniel.wagner@bmw-carit.de>2012-09-12 10:12:07 -0400
committerTejun Heo <tj@kernel.org>2012-09-14 12:57:43 -0400
commit8a8e04df4747661daaee77e98e102d99c9e09b98 (patch)
tree8ecd4288cfad84ed2bfc1820331b2483e70abfd3 /kernel
parent80f4c87774721e864d5a5a1f7aca3e95fd90e194 (diff)
cgroup: Assign subsystem IDs during compile time
WARNING: With this change it is impossible to load external built controllers anymore. In case where CONFIG_NETPRIO_CGROUP=m and CONFIG_NET_CLS_CGROUP=m is set, corresponding subsys_id should also be a constant. Up to now, net_prio_subsys_id and net_cls_subsys_id would be of the type int and the value would be assigned during runtime. By switching the macro definition IS_SUBSYS_ENABLED from IS_BUILTIN to IS_ENABLED, all *_subsys_id will have constant value. That means we need to remove all the code which assumes a value can be assigned to net_prio_subsys_id and net_cls_subsys_id. A close look is necessary on the RCU part which was introduces by following patch: commit f845172531fb7410c7fb7780b1a6e51ee6df7d52 Author: Herbert Xu <herbert@gondor.apana.org.au> Mon May 24 09:12:34 2010 Committer: David S. Miller <davem@davemloft.net> Mon May 24 09:12:34 2010 cls_cgroup: Store classid in struct sock Tis code was added to init_cgroup_cls() /* We can't use rcu_assign_pointer because this is an int. */ smp_wmb(); net_cls_subsys_id = net_cls_subsys.subsys_id; respectively to exit_cgroup_cls() net_cls_subsys_id = -1; synchronize_rcu(); and in module version of task_cls_classid() rcu_read_lock(); id = rcu_dereference(net_cls_subsys_id); if (id >= 0) classid = container_of(task_subsys_state(p, id), struct cgroup_cls_state, css)->classid; rcu_read_unlock(); Without an explicit explaination why the RCU part is needed. (The rcu_deference was fixed by exchanging it to rcu_derefence_index_check() in a later commit, but that is a minor detail.) So here is my pondering why it was introduced and why it safe to remove it now. Note that this code was copied over to net_prio the reasoning holds for that subsystem too. The idea behind the RCU use for net_cls_subsys_id is to make sure we get a valid pointer back from task_subsys_state(). task_subsys_state() is just blindly accessing the subsys array and returning the pointer. Obviously, passing in -1 as id into task_subsys_state() returns an invalid value (out of lower bound). So this code makes sure that only after module is loaded and the subsystem registered, the id is assigned. Before unregistering the module all old readers must have left the critical section. This is done by assigning -1 to the id and issuing a synchronized_rcu(). Any new readers wont call task_subsys_state() anymore and therefore it is safe to unregister the subsystem. The new code relies on the same trick, but it looks at the subsys pointer return by task_subsys_state() (remember the id is constant and therefore we allways have a valid index into the subsys array). No precautions need to be taken during module loading module. Eventually, all CPUs will get a valid pointer back from task_subsys_state() because rebind_subsystem() which is called after the module init() function will assigned subsys[net_cls_subsys_id] the newly loaded module subsystem pointer. When the subsystem is about to be removed, rebind_subsystem() will called before the module exit() function. In this case, rebind_subsys() will assign subsys[net_cls_subsys_id] a NULL pointer and then it calls synchronize_rcu(). All old readers have left by then the critical section. Any new reader wont access the subsystem anymore. At this point we are safe to unregister the subsystem. No synchronize_rcu() call is needed. Signed-off-by: Daniel Wagner <daniel.wagner@bmw-carit.de> Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: Li Zefan <lizefan@huawei.com> Acked-by: Neil Horman <nhorman@tuxdriver.com> Cc: "David S. Miller" <davem@davemloft.net> Cc: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Eric Dumazet <edumazet@google.com> Cc: Gao feng <gaofeng@cn.fujitsu.com> Cc: Glauber Costa <glommer@parallels.com> Cc: Herbert Xu <herbert@gondor.apana.org.au> Cc: Jamal Hadi Salim <jhs@mojatatu.com> Cc: John Fastabend <john.r.fastabend@intel.com> Cc: Kamezawa Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: netdev@vger.kernel.org Cc: cgroups@vger.kernel.org
Diffstat (limited to 'kernel')
-rw-r--r--kernel/cgroup.c22
1 files changed, 3 insertions, 19 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 2bfc78f531b6..485cc1487ea2 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -4451,24 +4451,8 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss)
4451 /* init base cftset */ 4451 /* init base cftset */
4452 cgroup_init_cftsets(ss); 4452 cgroup_init_cftsets(ss);
4453 4453
4454 /*
4455 * need to register a subsys id before anything else - for example,
4456 * init_cgroup_css needs it.
4457 */
4458 mutex_lock(&cgroup_mutex); 4454 mutex_lock(&cgroup_mutex);
4459 /* find the first empty slot in the array */ 4455 subsys[ss->subsys_id] = ss;
4460 for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
4461 if (subsys[i] == NULL)
4462 break;
4463 }
4464 if (i == CGROUP_SUBSYS_COUNT) {
4465 /* maximum number of subsystems already registered! */
4466 mutex_unlock(&cgroup_mutex);
4467 return -EBUSY;
4468 }
4469 /* assign ourselves the subsys_id */
4470 ss->subsys_id = i;
4471 subsys[i] = ss;
4472 4456
4473 /* 4457 /*
4474 * no ss->create seems to need anything important in the ss struct, so 4458 * no ss->create seems to need anything important in the ss struct, so
@@ -4477,7 +4461,7 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss)
4477 css = ss->create(dummytop); 4461 css = ss->create(dummytop);
4478 if (IS_ERR(css)) { 4462 if (IS_ERR(css)) {
4479 /* failure case - need to deassign the subsys[] slot. */ 4463 /* failure case - need to deassign the subsys[] slot. */
4480 subsys[i] = NULL; 4464 subsys[ss->subsys_id] = NULL;
4481 mutex_unlock(&cgroup_mutex); 4465 mutex_unlock(&cgroup_mutex);
4482 return PTR_ERR(css); 4466 return PTR_ERR(css);
4483 } 4467 }
@@ -4493,7 +4477,7 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss)
4493 if (ret) { 4477 if (ret) {
4494 dummytop->subsys[ss->subsys_id] = NULL; 4478 dummytop->subsys[ss->subsys_id] = NULL;
4495 ss->destroy(dummytop); 4479 ss->destroy(dummytop);
4496 subsys[i] = NULL; 4480 subsys[ss->subsys_id] = NULL;
4497 mutex_unlock(&cgroup_mutex); 4481 mutex_unlock(&cgroup_mutex);
4498 return ret; 4482 return ret;
4499 } 4483 }