diff options
author | Ben Blum <bblum@andrew.cmu.edu> | 2010-03-10 18:22:09 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-03-12 18:52:36 -0500 |
commit | e6a1105ba08b265023dd71a4174fb4a29ebc7083 (patch) | |
tree | c171a012df4364b0feac5d6f1bf8c354164ab0f9 | |
parent | aae8aab40367036931608fdaf9e2dc568b516f19 (diff) |
cgroups: subsystem module loading interface
Add interface between cgroups subsystem management and module loading
This patch implements rudimentary module-loading support for cgroups -
namely, a cgroup_load_subsys (similar to cgroup_init_subsys) for use as a
module initcall, and a struct module pointer in struct cgroup_subsys.
Several functions that might be wanted by modules have had EXPORT_SYMBOL
added to them, but it's unclear exactly which functions want it and which
won't.
Signed-off-by: Ben Blum <bblum@andrew.cmu.edu>
Acked-by: Li Zefan <lizf@cn.fujitsu.com>
Cc: Paul Menage <menage@google.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: Lai Jiangshan <laijs@cn.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | Documentation/cgroups/cgroups.txt | 4 | ||||
-rw-r--r-- | include/linux/cgroup.h | 4 | ||||
-rw-r--r-- | kernel/cgroup.c | 150 |
3 files changed, 153 insertions, 5 deletions
diff --git a/Documentation/cgroups/cgroups.txt b/Documentation/cgroups/cgroups.txt index d45082653e3d..ae8a037a761e 100644 --- a/Documentation/cgroups/cgroups.txt +++ b/Documentation/cgroups/cgroups.txt | |||
@@ -488,6 +488,10 @@ Each subsystem should: | |||
488 | - add an entry in linux/cgroup_subsys.h | 488 | - add an entry in linux/cgroup_subsys.h |
489 | - define a cgroup_subsys object called <name>_subsys | 489 | - define a cgroup_subsys object called <name>_subsys |
490 | 490 | ||
491 | If a subsystem can be compiled as a module, it should also have in its | ||
492 | module initcall a call to cgroup_load_subsys(&its_subsys_struct). It | ||
493 | should also set its_subsys.module = THIS_MODULE in its .c file. | ||
494 | |||
491 | Each subsystem may export the following methods. The only mandatory | 495 | Each subsystem may export the following methods. The only mandatory |
492 | methods are create/destroy. Any others that are null are presumed to | 496 | methods are create/destroy. Any others that are null are presumed to |
493 | be successful no-ops. | 497 | be successful no-ops. |
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 28319a9fe569..402ce477c47e 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h | |||
@@ -37,6 +37,7 @@ extern void cgroup_post_fork(struct task_struct *p); | |||
37 | extern void cgroup_exit(struct task_struct *p, int run_callbacks); | 37 | extern void cgroup_exit(struct task_struct *p, int run_callbacks); |
38 | extern int cgroupstats_build(struct cgroupstats *stats, | 38 | extern int cgroupstats_build(struct cgroupstats *stats, |
39 | struct dentry *dentry); | 39 | struct dentry *dentry); |
40 | extern int cgroup_load_subsys(struct cgroup_subsys *ss); | ||
40 | 41 | ||
41 | extern const struct file_operations proc_cgroup_operations; | 42 | extern const struct file_operations proc_cgroup_operations; |
42 | 43 | ||
@@ -486,6 +487,9 @@ struct cgroup_subsys { | |||
486 | /* used when use_id == true */ | 487 | /* used when use_id == true */ |
487 | struct idr idr; | 488 | struct idr idr; |
488 | spinlock_t id_lock; | 489 | spinlock_t id_lock; |
490 | |||
491 | /* should be defined only by modular subsystems */ | ||
492 | struct module *module; | ||
489 | }; | 493 | }; |
490 | 494 | ||
491 | #define SUBSYS(_x) extern struct cgroup_subsys _x ## _subsys; | 495 | #define SUBSYS(_x) extern struct cgroup_subsys _x ## _subsys; |
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index c92fb9549358..2cae38e64c59 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include <linux/string.h> | 44 | #include <linux/string.h> |
45 | #include <linux/sort.h> | 45 | #include <linux/sort.h> |
46 | #include <linux/kmod.h> | 46 | #include <linux/kmod.h> |
47 | #include <linux/module.h> | ||
47 | #include <linux/delayacct.h> | 48 | #include <linux/delayacct.h> |
48 | #include <linux/cgroupstats.h> | 49 | #include <linux/cgroupstats.h> |
49 | #include <linux/hash.h> | 50 | #include <linux/hash.h> |
@@ -254,7 +255,8 @@ struct cg_cgroup_link { | |||
254 | static struct css_set init_css_set; | 255 | static struct css_set init_css_set; |
255 | static struct cg_cgroup_link init_css_set_link; | 256 | static struct cg_cgroup_link init_css_set_link; |
256 | 257 | ||
257 | static int cgroup_subsys_init_idr(struct cgroup_subsys *ss); | 258 | static int cgroup_init_idr(struct cgroup_subsys *ss, |
259 | struct cgroup_subsys_state *css); | ||
258 | 260 | ||
259 | /* css_set_lock protects the list of css_set objects, and the | 261 | /* css_set_lock protects the list of css_set objects, and the |
260 | * chain of tasks off each css_set. Nests outside task->alloc_lock | 262 | * chain of tasks off each css_set. Nests outside task->alloc_lock |
@@ -2125,6 +2127,7 @@ int cgroup_add_file(struct cgroup *cgrp, | |||
2125 | error = PTR_ERR(dentry); | 2127 | error = PTR_ERR(dentry); |
2126 | return error; | 2128 | return error; |
2127 | } | 2129 | } |
2130 | EXPORT_SYMBOL_GPL(cgroup_add_file); | ||
2128 | 2131 | ||
2129 | int cgroup_add_files(struct cgroup *cgrp, | 2132 | int cgroup_add_files(struct cgroup *cgrp, |
2130 | struct cgroup_subsys *subsys, | 2133 | struct cgroup_subsys *subsys, |
@@ -2139,6 +2142,7 @@ int cgroup_add_files(struct cgroup *cgrp, | |||
2139 | } | 2142 | } |
2140 | return 0; | 2143 | return 0; |
2141 | } | 2144 | } |
2145 | EXPORT_SYMBOL_GPL(cgroup_add_files); | ||
2142 | 2146 | ||
2143 | /** | 2147 | /** |
2144 | * cgroup_task_count - count the number of tasks in a cgroup. | 2148 | * cgroup_task_count - count the number of tasks in a cgroup. |
@@ -3292,7 +3296,144 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss) | |||
3292 | mutex_init(&ss->hierarchy_mutex); | 3296 | mutex_init(&ss->hierarchy_mutex); |
3293 | lockdep_set_class(&ss->hierarchy_mutex, &ss->subsys_key); | 3297 | lockdep_set_class(&ss->hierarchy_mutex, &ss->subsys_key); |
3294 | ss->active = 1; | 3298 | ss->active = 1; |
3299 | |||
3300 | /* this function shouldn't be used with modular subsystems, since they | ||
3301 | * need to register a subsys_id, among other things */ | ||
3302 | BUG_ON(ss->module); | ||
3303 | } | ||
3304 | |||
3305 | /** | ||
3306 | * cgroup_load_subsys: load and register a modular subsystem at runtime | ||
3307 | * @ss: the subsystem to load | ||
3308 | * | ||
3309 | * This function should be called in a modular subsystem's initcall. If the | ||
3310 | * subsytem is built as a module, it will be assigned a new subsys_id and set | ||
3311 | * up for use. If the subsystem is built-in anyway, work is delegated to the | ||
3312 | * simpler cgroup_init_subsys. | ||
3313 | */ | ||
3314 | int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss) | ||
3315 | { | ||
3316 | int i; | ||
3317 | struct cgroup_subsys_state *css; | ||
3318 | |||
3319 | /* check name and function validity */ | ||
3320 | if (ss->name == NULL || strlen(ss->name) > MAX_CGROUP_TYPE_NAMELEN || | ||
3321 | ss->create == NULL || ss->destroy == NULL) | ||
3322 | return -EINVAL; | ||
3323 | |||
3324 | /* | ||
3325 | * we don't support callbacks in modular subsystems. this check is | ||
3326 | * before the ss->module check for consistency; a subsystem that could | ||
3327 | * be a module should still have no callbacks even if the user isn't | ||
3328 | * compiling it as one. | ||
3329 | */ | ||
3330 | if (ss->fork || ss->exit) | ||
3331 | return -EINVAL; | ||
3332 | |||
3333 | /* | ||
3334 | * an optionally modular subsystem is built-in: we want to do nothing, | ||
3335 | * since cgroup_init_subsys will have already taken care of it. | ||
3336 | */ | ||
3337 | if (ss->module == NULL) { | ||
3338 | /* a few sanity checks */ | ||
3339 | BUG_ON(ss->subsys_id >= CGROUP_BUILTIN_SUBSYS_COUNT); | ||
3340 | BUG_ON(subsys[ss->subsys_id] != ss); | ||
3341 | return 0; | ||
3342 | } | ||
3343 | |||
3344 | /* | ||
3345 | * need to register a subsys id before anything else - for example, | ||
3346 | * init_cgroup_css needs it. | ||
3347 | */ | ||
3348 | mutex_lock(&cgroup_mutex); | ||
3349 | /* find the first empty slot in the array */ | ||
3350 | for (i = CGROUP_BUILTIN_SUBSYS_COUNT; i < CGROUP_SUBSYS_COUNT; i++) { | ||
3351 | if (subsys[i] == NULL) | ||
3352 | break; | ||
3353 | } | ||
3354 | if (i == CGROUP_SUBSYS_COUNT) { | ||
3355 | /* maximum number of subsystems already registered! */ | ||
3356 | mutex_unlock(&cgroup_mutex); | ||
3357 | return -EBUSY; | ||
3358 | } | ||
3359 | /* assign ourselves the subsys_id */ | ||
3360 | ss->subsys_id = i; | ||
3361 | subsys[i] = ss; | ||
3362 | |||
3363 | /* | ||
3364 | * no ss->create seems to need anything important in the ss struct, so | ||
3365 | * this can happen first (i.e. before the rootnode attachment). | ||
3366 | */ | ||
3367 | css = ss->create(ss, dummytop); | ||
3368 | if (IS_ERR(css)) { | ||
3369 | /* failure case - need to deassign the subsys[] slot. */ | ||
3370 | subsys[i] = NULL; | ||
3371 | mutex_unlock(&cgroup_mutex); | ||
3372 | return PTR_ERR(css); | ||
3373 | } | ||
3374 | |||
3375 | list_add(&ss->sibling, &rootnode.subsys_list); | ||
3376 | ss->root = &rootnode; | ||
3377 | |||
3378 | /* our new subsystem will be attached to the dummy hierarchy. */ | ||
3379 | init_cgroup_css(css, ss, dummytop); | ||
3380 | /* init_idr must be after init_cgroup_css because it sets css->id. */ | ||
3381 | if (ss->use_id) { | ||
3382 | int ret = cgroup_init_idr(ss, css); | ||
3383 | if (ret) { | ||
3384 | dummytop->subsys[ss->subsys_id] = NULL; | ||
3385 | ss->destroy(ss, dummytop); | ||
3386 | subsys[i] = NULL; | ||
3387 | mutex_unlock(&cgroup_mutex); | ||
3388 | return ret; | ||
3389 | } | ||
3390 | } | ||
3391 | |||
3392 | /* | ||
3393 | * Now we need to entangle the css into the existing css_sets. unlike | ||
3394 | * in cgroup_init_subsys, there are now multiple css_sets, so each one | ||
3395 | * will need a new pointer to it; done by iterating the css_set_table. | ||
3396 | * furthermore, modifying the existing css_sets will corrupt the hash | ||
3397 | * table state, so each changed css_set will need its hash recomputed. | ||
3398 | * this is all done under the css_set_lock. | ||
3399 | */ | ||
3400 | write_lock(&css_set_lock); | ||
3401 | for (i = 0; i < CSS_SET_TABLE_SIZE; i++) { | ||
3402 | struct css_set *cg; | ||
3403 | struct hlist_node *node, *tmp; | ||
3404 | struct hlist_head *bucket = &css_set_table[i], *new_bucket; | ||
3405 | |||
3406 | hlist_for_each_entry_safe(cg, node, tmp, bucket, hlist) { | ||
3407 | /* skip entries that we already rehashed */ | ||
3408 | if (cg->subsys[ss->subsys_id]) | ||
3409 | continue; | ||
3410 | /* remove existing entry */ | ||
3411 | hlist_del(&cg->hlist); | ||
3412 | /* set new value */ | ||
3413 | cg->subsys[ss->subsys_id] = css; | ||
3414 | /* recompute hash and restore entry */ | ||
3415 | new_bucket = css_set_hash(cg->subsys); | ||
3416 | hlist_add_head(&cg->hlist, new_bucket); | ||
3417 | } | ||
3418 | } | ||
3419 | write_unlock(&css_set_lock); | ||
3420 | |||
3421 | mutex_init(&ss->hierarchy_mutex); | ||
3422 | lockdep_set_class(&ss->hierarchy_mutex, &ss->subsys_key); | ||
3423 | ss->active = 1; | ||
3424 | |||
3425 | /* | ||
3426 | * pin the subsystem's module so it doesn't go away. this shouldn't | ||
3427 | * fail, since the module's initcall calls us. | ||
3428 | * TODO: with module unloading, move this elsewhere | ||
3429 | */ | ||
3430 | BUG_ON(!try_module_get(ss->module)); | ||
3431 | |||
3432 | /* success! */ | ||
3433 | mutex_unlock(&cgroup_mutex); | ||
3434 | return 0; | ||
3295 | } | 3435 | } |
3436 | EXPORT_SYMBOL_GPL(cgroup_load_subsys); | ||
3296 | 3437 | ||
3297 | /** | 3438 | /** |
3298 | * cgroup_init_early - cgroup initialization at system boot | 3439 | * cgroup_init_early - cgroup initialization at system boot |
@@ -3364,7 +3505,7 @@ int __init cgroup_init(void) | |||
3364 | if (!ss->early_init) | 3505 | if (!ss->early_init) |
3365 | cgroup_init_subsys(ss); | 3506 | cgroup_init_subsys(ss); |
3366 | if (ss->use_id) | 3507 | if (ss->use_id) |
3367 | cgroup_subsys_init_idr(ss); | 3508 | cgroup_init_idr(ss, init_css_set.subsys[ss->subsys_id]); |
3368 | } | 3509 | } |
3369 | 3510 | ||
3370 | /* Add init_css_set to the hash table */ | 3511 | /* Add init_css_set to the hash table */ |
@@ -4033,15 +4174,14 @@ err_out: | |||
4033 | 4174 | ||
4034 | } | 4175 | } |
4035 | 4176 | ||
4036 | static int __init cgroup_subsys_init_idr(struct cgroup_subsys *ss) | 4177 | static int __init_or_module cgroup_init_idr(struct cgroup_subsys *ss, |
4178 | struct cgroup_subsys_state *rootcss) | ||
4037 | { | 4179 | { |
4038 | struct css_id *newid; | 4180 | struct css_id *newid; |
4039 | struct cgroup_subsys_state *rootcss; | ||
4040 | 4181 | ||
4041 | spin_lock_init(&ss->id_lock); | 4182 | spin_lock_init(&ss->id_lock); |
4042 | idr_init(&ss->idr); | 4183 | idr_init(&ss->idr); |
4043 | 4184 | ||
4044 | rootcss = init_css_set.subsys[ss->subsys_id]; | ||
4045 | newid = get_new_cssid(ss, 0); | 4185 | newid = get_new_cssid(ss, 0); |
4046 | if (IS_ERR(newid)) | 4186 | if (IS_ERR(newid)) |
4047 | return PTR_ERR(newid); | 4187 | return PTR_ERR(newid); |