diff options
-rw-r--r-- | include/linux/cgroup.h | 7 | ||||
-rw-r--r-- | kernel/cgroup.c | 59 |
2 files changed, 53 insertions, 13 deletions
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 2d1d151258cf..f585b7cde87b 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h | |||
@@ -156,6 +156,12 @@ struct css_set { | |||
156 | struct list_head list; | 156 | struct list_head list; |
157 | 157 | ||
158 | /* | 158 | /* |
159 | * List running through all cgroup groups in the same hash | ||
160 | * slot. Protected by css_set_lock | ||
161 | */ | ||
162 | struct hlist_node hlist; | ||
163 | |||
164 | /* | ||
159 | * List running through all tasks using this cgroup | 165 | * List running through all tasks using this cgroup |
160 | * group. Protected by css_set_lock | 166 | * group. Protected by css_set_lock |
161 | */ | 167 | */ |
@@ -174,7 +180,6 @@ struct css_set { | |||
174 | * during subsystem registration (at boot time). | 180 | * during subsystem registration (at boot time). |
175 | */ | 181 | */ |
176 | struct cgroup_subsys_state *subsys[CGROUP_SUBSYS_COUNT]; | 182 | struct cgroup_subsys_state *subsys[CGROUP_SUBSYS_COUNT]; |
177 | |||
178 | }; | 183 | }; |
179 | 184 | ||
180 | /* | 185 | /* |
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 7c8cc5141877..c447c29f8749 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include <linux/kmod.h> | 44 | #include <linux/kmod.h> |
45 | #include <linux/delayacct.h> | 45 | #include <linux/delayacct.h> |
46 | #include <linux/cgroupstats.h> | 46 | #include <linux/cgroupstats.h> |
47 | #include <linux/hash.h> | ||
47 | 48 | ||
48 | #include <asm/atomic.h> | 49 | #include <asm/atomic.h> |
49 | 50 | ||
@@ -193,6 +194,27 @@ static struct cg_cgroup_link init_css_set_link; | |||
193 | static DEFINE_RWLOCK(css_set_lock); | 194 | static DEFINE_RWLOCK(css_set_lock); |
194 | static int css_set_count; | 195 | static int css_set_count; |
195 | 196 | ||
197 | /* hash table for cgroup groups. This improves the performance to | ||
198 | * find an existing css_set */ | ||
199 | #define CSS_SET_HASH_BITS 7 | ||
200 | #define CSS_SET_TABLE_SIZE (1 << CSS_SET_HASH_BITS) | ||
201 | static struct hlist_head css_set_table[CSS_SET_TABLE_SIZE]; | ||
202 | |||
203 | static struct hlist_head *css_set_hash(struct cgroup_subsys_state *css[]) | ||
204 | { | ||
205 | int i; | ||
206 | int index; | ||
207 | unsigned long tmp = 0UL; | ||
208 | |||
209 | for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) | ||
210 | tmp += (unsigned long)css[i]; | ||
211 | tmp = (tmp >> 16) ^ tmp; | ||
212 | |||
213 | index = hash_long(tmp, CSS_SET_HASH_BITS); | ||
214 | |||
215 | return &css_set_table[index]; | ||
216 | } | ||
217 | |||
196 | /* We don't maintain the lists running through each css_set to its | 218 | /* We don't maintain the lists running through each css_set to its |
197 | * task until after the first call to cgroup_iter_start(). This | 219 | * task until after the first call to cgroup_iter_start(). This |
198 | * reduces the fork()/exit() overhead for people who have cgroups | 220 | * reduces the fork()/exit() overhead for people who have cgroups |
@@ -219,6 +241,7 @@ static int use_task_css_set_links; | |||
219 | static void unlink_css_set(struct css_set *cg) | 241 | static void unlink_css_set(struct css_set *cg) |
220 | { | 242 | { |
221 | write_lock(&css_set_lock); | 243 | write_lock(&css_set_lock); |
244 | hlist_del(&cg->hlist); | ||
222 | list_del(&cg->list); | 245 | list_del(&cg->list); |
223 | css_set_count--; | 246 | css_set_count--; |
224 | while (!list_empty(&cg->cg_links)) { | 247 | while (!list_empty(&cg->cg_links)) { |
@@ -284,9 +307,7 @@ static inline void put_css_set_taskexit(struct css_set *cg) | |||
284 | /* | 307 | /* |
285 | * find_existing_css_set() is a helper for | 308 | * find_existing_css_set() is a helper for |
286 | * find_css_set(), and checks to see whether an existing | 309 | * find_css_set(), and checks to see whether an existing |
287 | * css_set is suitable. This currently walks a linked-list for | 310 | * css_set is suitable. |
288 | * simplicity; a later patch will use a hash table for better | ||
289 | * performance | ||
290 | * | 311 | * |
291 | * oldcg: the cgroup group that we're using before the cgroup | 312 | * oldcg: the cgroup group that we're using before the cgroup |
292 | * transition | 313 | * transition |
@@ -303,7 +324,9 @@ static struct css_set *find_existing_css_set( | |||
303 | { | 324 | { |
304 | int i; | 325 | int i; |
305 | struct cgroupfs_root *root = cgrp->root; | 326 | struct cgroupfs_root *root = cgrp->root; |
306 | struct list_head *l = &init_css_set.list; | 327 | struct hlist_head *hhead; |
328 | struct hlist_node *node; | ||
329 | struct css_set *cg; | ||
307 | 330 | ||
308 | /* Built the set of subsystem state objects that we want to | 331 | /* Built the set of subsystem state objects that we want to |
309 | * see in the new css_set */ | 332 | * see in the new css_set */ |
@@ -320,18 +343,13 @@ static struct css_set *find_existing_css_set( | |||
320 | } | 343 | } |
321 | } | 344 | } |
322 | 345 | ||
323 | /* Look through existing cgroup groups to find one to reuse */ | 346 | hhead = css_set_hash(template); |
324 | do { | 347 | hlist_for_each_entry(cg, node, hhead, hlist) { |
325 | struct css_set *cg = | ||
326 | list_entry(l, struct css_set, list); | ||
327 | |||
328 | if (!memcmp(template, cg->subsys, sizeof(cg->subsys))) { | 348 | if (!memcmp(template, cg->subsys, sizeof(cg->subsys))) { |
329 | /* All subsystems matched */ | 349 | /* All subsystems matched */ |
330 | return cg; | 350 | return cg; |
331 | } | 351 | } |
332 | /* Try the next cgroup group */ | 352 | } |
333 | l = l->next; | ||
334 | } while (l != &init_css_set.list); | ||
335 | 353 | ||
336 | /* No existing cgroup group matched */ | 354 | /* No existing cgroup group matched */ |
337 | return NULL; | 355 | return NULL; |
@@ -393,6 +411,8 @@ static struct css_set *find_css_set( | |||
393 | struct list_head tmp_cg_links; | 411 | struct list_head tmp_cg_links; |
394 | struct cg_cgroup_link *link; | 412 | struct cg_cgroup_link *link; |
395 | 413 | ||
414 | struct hlist_head *hhead; | ||
415 | |||
396 | /* First see if we already have a cgroup group that matches | 416 | /* First see if we already have a cgroup group that matches |
397 | * the desired set */ | 417 | * the desired set */ |
398 | write_lock(&css_set_lock); | 418 | write_lock(&css_set_lock); |
@@ -417,6 +437,7 @@ static struct css_set *find_css_set( | |||
417 | kref_init(&res->ref); | 437 | kref_init(&res->ref); |
418 | INIT_LIST_HEAD(&res->cg_links); | 438 | INIT_LIST_HEAD(&res->cg_links); |
419 | INIT_LIST_HEAD(&res->tasks); | 439 | INIT_LIST_HEAD(&res->tasks); |
440 | INIT_HLIST_NODE(&res->hlist); | ||
420 | 441 | ||
421 | /* Copy the set of subsystem state objects generated in | 442 | /* Copy the set of subsystem state objects generated in |
422 | * find_existing_css_set() */ | 443 | * find_existing_css_set() */ |
@@ -459,6 +480,11 @@ static struct css_set *find_css_set( | |||
459 | /* Link this cgroup group into the list */ | 480 | /* Link this cgroup group into the list */ |
460 | list_add(&res->list, &init_css_set.list); | 481 | list_add(&res->list, &init_css_set.list); |
461 | css_set_count++; | 482 | css_set_count++; |
483 | |||
484 | /* Add this cgroup group to the hash table */ | ||
485 | hhead = css_set_hash(res->subsys); | ||
486 | hlist_add_head(&res->hlist, hhead); | ||
487 | |||
462 | write_unlock(&css_set_lock); | 488 | write_unlock(&css_set_lock); |
463 | 489 | ||
464 | return res; | 490 | return res; |
@@ -2508,6 +2534,7 @@ int __init cgroup_init_early(void) | |||
2508 | INIT_LIST_HEAD(&init_css_set.list); | 2534 | INIT_LIST_HEAD(&init_css_set.list); |
2509 | INIT_LIST_HEAD(&init_css_set.cg_links); | 2535 | INIT_LIST_HEAD(&init_css_set.cg_links); |
2510 | INIT_LIST_HEAD(&init_css_set.tasks); | 2536 | INIT_LIST_HEAD(&init_css_set.tasks); |
2537 | INIT_HLIST_NODE(&init_css_set.hlist); | ||
2511 | css_set_count = 1; | 2538 | css_set_count = 1; |
2512 | init_cgroup_root(&rootnode); | 2539 | init_cgroup_root(&rootnode); |
2513 | list_add(&rootnode.root_list, &roots); | 2540 | list_add(&rootnode.root_list, &roots); |
@@ -2520,6 +2547,9 @@ int __init cgroup_init_early(void) | |||
2520 | list_add(&init_css_set_link.cg_link_list, | 2547 | list_add(&init_css_set_link.cg_link_list, |
2521 | &init_css_set.cg_links); | 2548 | &init_css_set.cg_links); |
2522 | 2549 | ||
2550 | for (i = 0; i < CSS_SET_TABLE_SIZE; i++) | ||
2551 | INIT_HLIST_HEAD(&css_set_table[i]); | ||
2552 | |||
2523 | for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) { | 2553 | for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) { |
2524 | struct cgroup_subsys *ss = subsys[i]; | 2554 | struct cgroup_subsys *ss = subsys[i]; |
2525 | 2555 | ||
@@ -2549,6 +2579,7 @@ int __init cgroup_init(void) | |||
2549 | { | 2579 | { |
2550 | int err; | 2580 | int err; |
2551 | int i; | 2581 | int i; |
2582 | struct hlist_head *hhead; | ||
2552 | 2583 | ||
2553 | err = bdi_init(&cgroup_backing_dev_info); | 2584 | err = bdi_init(&cgroup_backing_dev_info); |
2554 | if (err) | 2585 | if (err) |
@@ -2560,6 +2591,10 @@ int __init cgroup_init(void) | |||
2560 | cgroup_init_subsys(ss); | 2591 | cgroup_init_subsys(ss); |
2561 | } | 2592 | } |
2562 | 2593 | ||
2594 | /* Add init_css_set to the hash table */ | ||
2595 | hhead = css_set_hash(init_css_set.subsys); | ||
2596 | hlist_add_head(&init_css_set.hlist, hhead); | ||
2597 | |||
2563 | err = register_filesystem(&cgroup_fs_type); | 2598 | err = register_filesystem(&cgroup_fs_type); |
2564 | if (err < 0) | 2599 | if (err < 0) |
2565 | goto out; | 2600 | goto out; |