diff options
Diffstat (limited to 'kernel/cgroup.c')
| -rw-r--r-- | kernel/cgroup.c | 340 |
1 files changed, 65 insertions, 275 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 8bd9cfdc70d7..bc1dcabe9217 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
| @@ -90,6 +90,14 @@ static DEFINE_MUTEX(cgroup_mutex); | |||
| 90 | static DEFINE_MUTEX(cgroup_root_mutex); | 90 | static DEFINE_MUTEX(cgroup_root_mutex); |
| 91 | 91 | ||
| 92 | /* | 92 | /* |
| 93 | * cgroup destruction makes heavy use of work items and there can be a lot | ||
| 94 | * of concurrent destructions. Use a separate workqueue so that cgroup | ||
| 95 | * destruction work items don't end up filling up max_active of system_wq | ||
| 96 | * which may lead to deadlock. | ||
| 97 | */ | ||
| 98 | static struct workqueue_struct *cgroup_destroy_wq; | ||
| 99 | |||
| 100 | /* | ||
| 93 | * Generate an array of cgroup subsystem pointers. At boot time, this is | 101 | * Generate an array of cgroup subsystem pointers. At boot time, this is |
| 94 | * populated with the built in subsystems, and modular subsystems are | 102 | * populated with the built in subsystems, and modular subsystems are |
| 95 | * registered after that. The mutable section of this array is protected by | 103 | * registered after that. The mutable section of this array is protected by |
| @@ -125,38 +133,6 @@ struct cfent { | |||
| 125 | }; | 133 | }; |
| 126 | 134 | ||
| 127 | /* | 135 | /* |
| 128 | * CSS ID -- ID per subsys's Cgroup Subsys State(CSS). used only when | ||
| 129 | * cgroup_subsys->use_id != 0. | ||
| 130 | */ | ||
| 131 | #define CSS_ID_MAX (65535) | ||
| 132 | struct css_id { | ||
| 133 | /* | ||
| 134 | * The css to which this ID points. This pointer is set to valid value | ||
| 135 | * after cgroup is populated. If cgroup is removed, this will be NULL. | ||
| 136 | * This pointer is expected to be RCU-safe because destroy() | ||
| 137 | * is called after synchronize_rcu(). But for safe use, css_tryget() | ||
| 138 | * should be used for avoiding race. | ||
| 139 | */ | ||
| 140 | struct cgroup_subsys_state __rcu *css; | ||
| 141 | /* | ||
| 142 | * ID of this css. | ||
| 143 | */ | ||
| 144 | unsigned short id; | ||
| 145 | /* | ||
| 146 | * Depth in hierarchy which this ID belongs to. | ||
| 147 | */ | ||
| 148 | unsigned short depth; | ||
| 149 | /* | ||
| 150 | * ID is freed by RCU. (and lookup routine is RCU safe.) | ||
| 151 | */ | ||
| 152 | struct rcu_head rcu_head; | ||
| 153 | /* | ||
| 154 | * Hierarchy of CSS ID belongs to. | ||
| 155 | */ | ||
| 156 | unsigned short stack[0]; /* Array of Length (depth+1) */ | ||
| 157 | }; | ||
| 158 | |||
| 159 | /* | ||
| 160 | * cgroup_event represents events which userspace want to receive. | 136 | * cgroup_event represents events which userspace want to receive. |
| 161 | */ | 137 | */ |
| 162 | struct cgroup_event { | 138 | struct cgroup_event { |
| @@ -223,6 +199,7 @@ static void cgroup_destroy_css_killed(struct cgroup *cgrp); | |||
| 223 | static int cgroup_destroy_locked(struct cgroup *cgrp); | 199 | static int cgroup_destroy_locked(struct cgroup *cgrp); |
| 224 | static int cgroup_addrm_files(struct cgroup *cgrp, struct cftype cfts[], | 200 | static int cgroup_addrm_files(struct cgroup *cgrp, struct cftype cfts[], |
| 225 | bool is_add); | 201 | bool is_add); |
| 202 | static int cgroup_file_release(struct inode *inode, struct file *file); | ||
| 226 | 203 | ||
| 227 | /** | 204 | /** |
| 228 | * cgroup_css - obtain a cgroup's css for the specified subsystem | 205 | * cgroup_css - obtain a cgroup's css for the specified subsystem |
| @@ -387,9 +364,6 @@ struct cgrp_cset_link { | |||
| 387 | static struct css_set init_css_set; | 364 | static struct css_set init_css_set; |
| 388 | static struct cgrp_cset_link init_cgrp_cset_link; | 365 | static struct cgrp_cset_link init_cgrp_cset_link; |
| 389 | 366 | ||
| 390 | static int cgroup_init_idr(struct cgroup_subsys *ss, | ||
| 391 | struct cgroup_subsys_state *css); | ||
| 392 | |||
| 393 | /* | 367 | /* |
| 394 | * css_set_lock protects the list of css_set objects, and the chain of | 368 | * css_set_lock protects the list of css_set objects, and the chain of |
| 395 | * tasks off each css_set. Nests outside task->alloc_lock due to | 369 | * tasks off each css_set. Nests outside task->alloc_lock due to |
| @@ -841,8 +815,6 @@ static struct backing_dev_info cgroup_backing_dev_info = { | |||
| 841 | .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK, | 815 | .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK, |
| 842 | }; | 816 | }; |
| 843 | 817 | ||
| 844 | static int alloc_css_id(struct cgroup_subsys_state *child_css); | ||
| 845 | |||
| 846 | static struct inode *cgroup_new_inode(umode_t mode, struct super_block *sb) | 818 | static struct inode *cgroup_new_inode(umode_t mode, struct super_block *sb) |
| 847 | { | 819 | { |
| 848 | struct inode *inode = new_inode(sb); | 820 | struct inode *inode = new_inode(sb); |
| @@ -908,7 +880,7 @@ static void cgroup_free_rcu(struct rcu_head *head) | |||
| 908 | struct cgroup *cgrp = container_of(head, struct cgroup, rcu_head); | 880 | struct cgroup *cgrp = container_of(head, struct cgroup, rcu_head); |
| 909 | 881 | ||
| 910 | INIT_WORK(&cgrp->destroy_work, cgroup_free_fn); | 882 | INIT_WORK(&cgrp->destroy_work, cgroup_free_fn); |
| 911 | schedule_work(&cgrp->destroy_work); | 883 | queue_work(cgroup_destroy_wq, &cgrp->destroy_work); |
| 912 | } | 884 | } |
| 913 | 885 | ||
| 914 | static void cgroup_diput(struct dentry *dentry, struct inode *inode) | 886 | static void cgroup_diput(struct dentry *dentry, struct inode *inode) |
| @@ -918,6 +890,16 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode) | |||
| 918 | struct cgroup *cgrp = dentry->d_fsdata; | 890 | struct cgroup *cgrp = dentry->d_fsdata; |
| 919 | 891 | ||
| 920 | BUG_ON(!(cgroup_is_dead(cgrp))); | 892 | BUG_ON(!(cgroup_is_dead(cgrp))); |
| 893 | |||
| 894 | /* | ||
| 895 | * XXX: cgrp->id is only used to look up css's. As cgroup | ||
| 896 | * and css's lifetimes will be decoupled, it should be made | ||
| 897 | * per-subsystem and moved to css->id so that lookups are | ||
| 898 | * successful until the target css is released. | ||
| 899 | */ | ||
| 900 | idr_remove(&cgrp->root->cgroup_idr, cgrp->id); | ||
| 901 | cgrp->id = -1; | ||
| 902 | |||
| 921 | call_rcu(&cgrp->rcu_head, cgroup_free_rcu); | 903 | call_rcu(&cgrp->rcu_head, cgroup_free_rcu); |
| 922 | } else { | 904 | } else { |
| 923 | struct cfent *cfe = __d_cfe(dentry); | 905 | struct cfent *cfe = __d_cfe(dentry); |
| @@ -932,11 +914,6 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode) | |||
| 932 | iput(inode); | 914 | iput(inode); |
| 933 | } | 915 | } |
| 934 | 916 | ||
| 935 | static int cgroup_delete(const struct dentry *d) | ||
| 936 | { | ||
| 937 | return 1; | ||
| 938 | } | ||
| 939 | |||
| 940 | static void remove_dir(struct dentry *d) | 917 | static void remove_dir(struct dentry *d) |
| 941 | { | 918 | { |
| 942 | struct dentry *parent = dget(d->d_parent); | 919 | struct dentry *parent = dget(d->d_parent); |
| @@ -1523,7 +1500,7 @@ static int cgroup_get_rootdir(struct super_block *sb) | |||
| 1523 | { | 1500 | { |
| 1524 | static const struct dentry_operations cgroup_dops = { | 1501 | static const struct dentry_operations cgroup_dops = { |
| 1525 | .d_iput = cgroup_diput, | 1502 | .d_iput = cgroup_diput, |
| 1526 | .d_delete = cgroup_delete, | 1503 | .d_delete = always_delete_dentry, |
| 1527 | }; | 1504 | }; |
| 1528 | 1505 | ||
| 1529 | struct inode *inode = | 1506 | struct inode *inode = |
| @@ -2463,7 +2440,7 @@ static const struct file_operations cgroup_seqfile_operations = { | |||
| 2463 | .read = seq_read, | 2440 | .read = seq_read, |
| 2464 | .write = cgroup_file_write, | 2441 | .write = cgroup_file_write, |
| 2465 | .llseek = seq_lseek, | 2442 | .llseek = seq_lseek, |
| 2466 | .release = single_release, | 2443 | .release = cgroup_file_release, |
| 2467 | }; | 2444 | }; |
| 2468 | 2445 | ||
| 2469 | static int cgroup_file_open(struct inode *inode, struct file *file) | 2446 | static int cgroup_file_open(struct inode *inode, struct file *file) |
| @@ -2524,6 +2501,8 @@ static int cgroup_file_release(struct inode *inode, struct file *file) | |||
| 2524 | ret = cft->release(inode, file); | 2501 | ret = cft->release(inode, file); |
| 2525 | if (css->ss) | 2502 | if (css->ss) |
| 2526 | css_put(css); | 2503 | css_put(css); |
| 2504 | if (file->f_op == &cgroup_seqfile_operations) | ||
| 2505 | single_release(inode, file); | ||
| 2527 | return ret; | 2506 | return ret; |
| 2528 | } | 2507 | } |
| 2529 | 2508 | ||
| @@ -4240,21 +4219,6 @@ static int cgroup_populate_dir(struct cgroup *cgrp, unsigned long subsys_mask) | |||
| 4240 | goto err; | 4219 | goto err; |
| 4241 | } | 4220 | } |
| 4242 | } | 4221 | } |
| 4243 | |||
| 4244 | /* This cgroup is ready now */ | ||
| 4245 | for_each_root_subsys(cgrp->root, ss) { | ||
| 4246 | struct cgroup_subsys_state *css = cgroup_css(cgrp, ss); | ||
| 4247 | struct css_id *id = rcu_dereference_protected(css->id, true); | ||
| 4248 | |||
| 4249 | /* | ||
| 4250 | * Update id->css pointer and make this css visible from | ||
| 4251 | * CSS ID functions. This pointer will be dereferened | ||
| 4252 | * from RCU-read-side without locks. | ||
| 4253 | */ | ||
| 4254 | if (id) | ||
| 4255 | rcu_assign_pointer(id->css, css); | ||
| 4256 | } | ||
| 4257 | |||
| 4258 | return 0; | 4222 | return 0; |
| 4259 | err: | 4223 | err: |
| 4260 | cgroup_clear_dir(cgrp, subsys_mask); | 4224 | cgroup_clear_dir(cgrp, subsys_mask); |
| @@ -4306,7 +4270,7 @@ static void css_free_rcu_fn(struct rcu_head *rcu_head) | |||
| 4306 | * css_put(). dput() requires process context which we don't have. | 4270 | * css_put(). dput() requires process context which we don't have. |
| 4307 | */ | 4271 | */ |
| 4308 | INIT_WORK(&css->destroy_work, css_free_work_fn); | 4272 | INIT_WORK(&css->destroy_work, css_free_work_fn); |
| 4309 | schedule_work(&css->destroy_work); | 4273 | queue_work(cgroup_destroy_wq, &css->destroy_work); |
| 4310 | } | 4274 | } |
| 4311 | 4275 | ||
| 4312 | static void css_release(struct percpu_ref *ref) | 4276 | static void css_release(struct percpu_ref *ref) |
| @@ -4314,6 +4278,7 @@ static void css_release(struct percpu_ref *ref) | |||
| 4314 | struct cgroup_subsys_state *css = | 4278 | struct cgroup_subsys_state *css = |
| 4315 | container_of(ref, struct cgroup_subsys_state, refcnt); | 4279 | container_of(ref, struct cgroup_subsys_state, refcnt); |
| 4316 | 4280 | ||
| 4281 | rcu_assign_pointer(css->cgroup->subsys[css->ss->subsys_id], NULL); | ||
| 4317 | call_rcu(&css->rcu_head, css_free_rcu_fn); | 4282 | call_rcu(&css->rcu_head, css_free_rcu_fn); |
| 4318 | } | 4283 | } |
| 4319 | 4284 | ||
| @@ -4323,7 +4288,6 @@ static void init_css(struct cgroup_subsys_state *css, struct cgroup_subsys *ss, | |||
| 4323 | css->cgroup = cgrp; | 4288 | css->cgroup = cgrp; |
| 4324 | css->ss = ss; | 4289 | css->ss = ss; |
| 4325 | css->flags = 0; | 4290 | css->flags = 0; |
| 4326 | css->id = NULL; | ||
| 4327 | 4291 | ||
| 4328 | if (cgrp->parent) | 4292 | if (cgrp->parent) |
| 4329 | css->parent = cgroup_css(cgrp->parent, ss); | 4293 | css->parent = cgroup_css(cgrp->parent, ss); |
| @@ -4455,12 +4419,6 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, | |||
| 4455 | goto err_free_all; | 4419 | goto err_free_all; |
| 4456 | 4420 | ||
| 4457 | init_css(css, ss, cgrp); | 4421 | init_css(css, ss, cgrp); |
| 4458 | |||
| 4459 | if (ss->use_id) { | ||
| 4460 | err = alloc_css_id(css); | ||
| 4461 | if (err) | ||
| 4462 | goto err_free_all; | ||
| 4463 | } | ||
| 4464 | } | 4422 | } |
| 4465 | 4423 | ||
| 4466 | /* | 4424 | /* |
| @@ -4479,14 +4437,6 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, | |||
| 4479 | list_add_tail_rcu(&cgrp->sibling, &cgrp->parent->children); | 4437 | list_add_tail_rcu(&cgrp->sibling, &cgrp->parent->children); |
| 4480 | root->number_of_cgroups++; | 4438 | root->number_of_cgroups++; |
| 4481 | 4439 | ||
| 4482 | /* each css holds a ref to the cgroup's dentry and the parent css */ | ||
| 4483 | for_each_root_subsys(root, ss) { | ||
| 4484 | struct cgroup_subsys_state *css = css_ar[ss->subsys_id]; | ||
| 4485 | |||
| 4486 | dget(dentry); | ||
| 4487 | css_get(css->parent); | ||
| 4488 | } | ||
| 4489 | |||
| 4490 | /* hold a ref to the parent's dentry */ | 4440 | /* hold a ref to the parent's dentry */ |
| 4491 | dget(parent->dentry); | 4441 | dget(parent->dentry); |
| 4492 | 4442 | ||
| @@ -4498,6 +4448,13 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, | |||
| 4498 | if (err) | 4448 | if (err) |
| 4499 | goto err_destroy; | 4449 | goto err_destroy; |
| 4500 | 4450 | ||
| 4451 | /* each css holds a ref to the cgroup's dentry and parent css */ | ||
| 4452 | dget(dentry); | ||
| 4453 | css_get(css->parent); | ||
| 4454 | |||
| 4455 | /* mark it consumed for error path */ | ||
| 4456 | css_ar[ss->subsys_id] = NULL; | ||
| 4457 | |||
| 4501 | if (ss->broken_hierarchy && !ss->warned_broken_hierarchy && | 4458 | if (ss->broken_hierarchy && !ss->warned_broken_hierarchy && |
| 4502 | parent->parent) { | 4459 | parent->parent) { |
| 4503 | pr_warning("cgroup: %s (%d) created nested cgroup for controller \"%s\" which has incomplete hierarchy support. Nested cgroups may change behavior in the future.\n", | 4460 | pr_warning("cgroup: %s (%d) created nested cgroup for controller \"%s\" which has incomplete hierarchy support. Nested cgroups may change behavior in the future.\n", |
| @@ -4544,6 +4501,14 @@ err_free_cgrp: | |||
| 4544 | return err; | 4501 | return err; |
| 4545 | 4502 | ||
| 4546 | err_destroy: | 4503 | err_destroy: |
| 4504 | for_each_root_subsys(root, ss) { | ||
| 4505 | struct cgroup_subsys_state *css = css_ar[ss->subsys_id]; | ||
| 4506 | |||
| 4507 | if (css) { | ||
| 4508 | percpu_ref_cancel_init(&css->refcnt); | ||
| 4509 | ss->css_free(css); | ||
| 4510 | } | ||
| 4511 | } | ||
| 4547 | cgroup_destroy_locked(cgrp); | 4512 | cgroup_destroy_locked(cgrp); |
| 4548 | mutex_unlock(&cgroup_mutex); | 4513 | mutex_unlock(&cgroup_mutex); |
| 4549 | mutex_unlock(&dentry->d_inode->i_mutex); | 4514 | mutex_unlock(&dentry->d_inode->i_mutex); |
| @@ -4603,7 +4568,7 @@ static void css_killed_ref_fn(struct percpu_ref *ref) | |||
| 4603 | container_of(ref, struct cgroup_subsys_state, refcnt); | 4568 | container_of(ref, struct cgroup_subsys_state, refcnt); |
| 4604 | 4569 | ||
| 4605 | INIT_WORK(&css->destroy_work, css_killed_work_fn); | 4570 | INIT_WORK(&css->destroy_work, css_killed_work_fn); |
| 4606 | schedule_work(&css->destroy_work); | 4571 | queue_work(cgroup_destroy_wq, &css->destroy_work); |
| 4607 | } | 4572 | } |
| 4608 | 4573 | ||
| 4609 | /** | 4574 | /** |
| @@ -4705,8 +4670,12 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) | |||
| 4705 | * will be invoked to perform the rest of destruction once the | 4670 | * will be invoked to perform the rest of destruction once the |
| 4706 | * percpu refs of all css's are confirmed to be killed. | 4671 | * percpu refs of all css's are confirmed to be killed. |
| 4707 | */ | 4672 | */ |
| 4708 | for_each_root_subsys(cgrp->root, ss) | 4673 | for_each_root_subsys(cgrp->root, ss) { |
| 4709 | kill_css(cgroup_css(cgrp, ss)); | 4674 | struct cgroup_subsys_state *css = cgroup_css(cgrp, ss); |
| 4675 | |||
| 4676 | if (css) | ||
| 4677 | kill_css(css); | ||
| 4678 | } | ||
| 4710 | 4679 | ||
| 4711 | /* | 4680 | /* |
| 4712 | * Mark @cgrp dead. This prevents further task migration and child | 4681 | * Mark @cgrp dead. This prevents further task migration and child |
| @@ -4775,14 +4744,6 @@ static void cgroup_destroy_css_killed(struct cgroup *cgrp) | |||
| 4775 | /* delete this cgroup from parent->children */ | 4744 | /* delete this cgroup from parent->children */ |
| 4776 | list_del_rcu(&cgrp->sibling); | 4745 | list_del_rcu(&cgrp->sibling); |
| 4777 | 4746 | ||
| 4778 | /* | ||
| 4779 | * We should remove the cgroup object from idr before its grace | ||
| 4780 | * period starts, so we won't be looking up a cgroup while the | ||
| 4781 | * cgroup is being freed. | ||
| 4782 | */ | ||
| 4783 | idr_remove(&cgrp->root->cgroup_idr, cgrp->id); | ||
| 4784 | cgrp->id = -1; | ||
| 4785 | |||
| 4786 | dput(d); | 4747 | dput(d); |
| 4787 | 4748 | ||
| 4788 | set_bit(CGRP_RELEASABLE, &parent->flags); | 4749 | set_bit(CGRP_RELEASABLE, &parent->flags); |
| @@ -4925,12 +4886,6 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss) | |||
| 4925 | 4886 | ||
| 4926 | /* our new subsystem will be attached to the dummy hierarchy. */ | 4887 | /* our new subsystem will be attached to the dummy hierarchy. */ |
| 4927 | init_css(css, ss, cgroup_dummy_top); | 4888 | init_css(css, ss, cgroup_dummy_top); |
| 4928 | /* init_idr must be after init_css() because it sets css->id. */ | ||
| 4929 | if (ss->use_id) { | ||
| 4930 | ret = cgroup_init_idr(ss, css); | ||
| 4931 | if (ret) | ||
| 4932 | goto err_unload; | ||
| 4933 | } | ||
| 4934 | 4889 | ||
| 4935 | /* | 4890 | /* |
| 4936 | * Now we need to entangle the css into the existing css_sets. unlike | 4891 | * Now we need to entangle the css into the existing css_sets. unlike |
| @@ -4996,9 +4951,6 @@ void cgroup_unload_subsys(struct cgroup_subsys *ss) | |||
| 4996 | 4951 | ||
| 4997 | offline_css(cgroup_css(cgroup_dummy_top, ss)); | 4952 | offline_css(cgroup_css(cgroup_dummy_top, ss)); |
| 4998 | 4953 | ||
| 4999 | if (ss->use_id) | ||
| 5000 | idr_destroy(&ss->idr); | ||
| 5001 | |||
| 5002 | /* deassign the subsys_id */ | 4954 | /* deassign the subsys_id */ |
| 5003 | cgroup_subsys[ss->subsys_id] = NULL; | 4955 | cgroup_subsys[ss->subsys_id] = NULL; |
| 5004 | 4956 | ||
| @@ -5025,8 +4977,7 @@ void cgroup_unload_subsys(struct cgroup_subsys *ss) | |||
| 5025 | /* | 4977 | /* |
| 5026 | * remove subsystem's css from the cgroup_dummy_top and free it - | 4978 | * remove subsystem's css from the cgroup_dummy_top and free it - |
| 5027 | * need to free before marking as null because ss->css_free needs | 4979 | * need to free before marking as null because ss->css_free needs |
| 5028 | * the cgrp->subsys pointer to find their state. note that this | 4980 | * the cgrp->subsys pointer to find their state. |
| 5029 | * also takes care of freeing the css_id. | ||
| 5030 | */ | 4981 | */ |
| 5031 | ss->css_free(cgroup_css(cgroup_dummy_top, ss)); | 4982 | ss->css_free(cgroup_css(cgroup_dummy_top, ss)); |
| 5032 | RCU_INIT_POINTER(cgroup_dummy_top->subsys[ss->subsys_id], NULL); | 4983 | RCU_INIT_POINTER(cgroup_dummy_top->subsys[ss->subsys_id], NULL); |
| @@ -5097,8 +5048,6 @@ int __init cgroup_init(void) | |||
| 5097 | for_each_builtin_subsys(ss, i) { | 5048 | for_each_builtin_subsys(ss, i) { |
| 5098 | if (!ss->early_init) | 5049 | if (!ss->early_init) |
| 5099 | cgroup_init_subsys(ss); | 5050 | cgroup_init_subsys(ss); |
| 5100 | if (ss->use_id) | ||
| 5101 | cgroup_init_idr(ss, init_css_set.subsys[ss->subsys_id]); | ||
| 5102 | } | 5051 | } |
| 5103 | 5052 | ||
| 5104 | /* allocate id for the dummy hierarchy */ | 5053 | /* allocate id for the dummy hierarchy */ |
| @@ -5139,6 +5088,22 @@ out: | |||
| 5139 | return err; | 5088 | return err; |
| 5140 | } | 5089 | } |
| 5141 | 5090 | ||
| 5091 | static int __init cgroup_wq_init(void) | ||
| 5092 | { | ||
| 5093 | /* | ||
| 5094 | * There isn't much point in executing destruction path in | ||
| 5095 | * parallel. Good chunk is serialized with cgroup_mutex anyway. | ||
| 5096 | * Use 1 for @max_active. | ||
| 5097 | * | ||
| 5098 | * We would prefer to do this in cgroup_init() above, but that | ||
| 5099 | * is called before init_workqueues(): so leave this until after. | ||
| 5100 | */ | ||
| 5101 | cgroup_destroy_wq = alloc_workqueue("cgroup_destroy", 0, 1); | ||
| 5102 | BUG_ON(!cgroup_destroy_wq); | ||
| 5103 | return 0; | ||
| 5104 | } | ||
| 5105 | core_initcall(cgroup_wq_init); | ||
| 5106 | |||
| 5142 | /* | 5107 | /* |
| 5143 | * proc_cgroup_show() | 5108 | * proc_cgroup_show() |
| 5144 | * - Print task's cgroup paths into seq_file, one line for each hierarchy | 5109 | * - Print task's cgroup paths into seq_file, one line for each hierarchy |
| @@ -5518,181 +5483,6 @@ static int __init cgroup_disable(char *str) | |||
| 5518 | } | 5483 | } |
| 5519 | __setup("cgroup_disable=", cgroup_disable); | 5484 | __setup("cgroup_disable=", cgroup_disable); |
| 5520 | 5485 | ||
| 5521 | /* | ||
| 5522 | * Functons for CSS ID. | ||
| 5523 | */ | ||
| 5524 | |||
| 5525 | /* to get ID other than 0, this should be called when !cgroup_is_dead() */ | ||
| 5526 | unsigned short css_id(struct cgroup_subsys_state *css) | ||
| 5527 | { | ||
| 5528 | struct css_id *cssid; | ||
| 5529 | |||
| 5530 | /* | ||
| 5531 | * This css_id() can return correct value when somone has refcnt | ||
| 5532 | * on this or this is under rcu_read_lock(). Once css->id is allocated, | ||
| 5533 | * it's unchanged until freed. | ||
| 5534 | */ | ||
| 5535 | cssid = rcu_dereference_raw(css->id); | ||
| 5536 | |||
| 5537 | if (cssid) | ||
| 5538 | return cssid->id; | ||
| 5539 | return 0; | ||
| 5540 | } | ||
| 5541 | EXPORT_SYMBOL_GPL(css_id); | ||
| 5542 | |||
| 5543 | /** | ||
| 5544 | * css_is_ancestor - test "root" css is an ancestor of "child" | ||
| 5545 | * @child: the css to be tested. | ||
| 5546 | * @root: the css supporsed to be an ancestor of the child. | ||
| 5547 | * | ||
| 5548 | * Returns true if "root" is an ancestor of "child" in its hierarchy. Because | ||
| 5549 | * this function reads css->id, the caller must hold rcu_read_lock(). | ||
| 5550 | * But, considering usual usage, the csses should be valid objects after test. | ||
| 5551 | * Assuming that the caller will do some action to the child if this returns | ||
| 5552 | * returns true, the caller must take "child";s reference count. | ||
| 5553 | * If "child" is valid object and this returns true, "root" is valid, too. | ||
| 5554 | */ | ||
| 5555 | |||
| 5556 | bool css_is_ancestor(struct cgroup_subsys_state *child, | ||
| 5557 | const struct cgroup_subsys_state *root) | ||
| 5558 | { | ||
| 5559 | struct css_id *child_id; | ||
| 5560 | struct css_id *root_id; | ||
| 5561 | |||
| 5562 | child_id = rcu_dereference(child->id); | ||
| 5563 | if (!child_id) | ||
| 5564 | return false; | ||
| 5565 | root_id = rcu_dereference(root->id); | ||
| 5566 | if (!root_id) | ||
| 5567 | return false; | ||
| 5568 | if (child_id->depth < root_id->depth) | ||
| 5569 | return false; | ||
| 5570 | if (child_id->stack[root_id->depth] != root_id->id) | ||
| 5571 | return false; | ||
| 5572 | return true; | ||
| 5573 | } | ||
| 5574 | |||
| 5575 | void free_css_id(struct cgroup_subsys *ss, struct cgroup_subsys_state *css) | ||
| 5576 | { | ||
| 5577 | struct css_id *id = rcu_dereference_protected(css->id, true); | ||
| 5578 | |||
| 5579 | /* When this is called before css_id initialization, id can be NULL */ | ||
| 5580 | if (!id) | ||
| 5581 | return; | ||
| 5582 | |||
| 5583 | BUG_ON(!ss->use_id); | ||
| 5584 | |||
| 5585 | rcu_assign_pointer(id->css, NULL); | ||
| 5586 | rcu_assign_pointer(css->id, NULL); | ||
| 5587 | spin_lock(&ss->id_lock); | ||
| 5588 | idr_remove(&ss->idr, id->id); | ||
| 5589 | spin_unlock(&ss->id_lock); | ||
| 5590 | kfree_rcu(id, rcu_head); | ||
| 5591 | } | ||
| 5592 | EXPORT_SYMBOL_GPL(free_css_id); | ||
| 5593 | |||
| 5594 | /* | ||
| 5595 | * This is called by init or create(). Then, calls to this function are | ||
| 5596 | * always serialized (By cgroup_mutex() at create()). | ||
| 5597 | */ | ||
| 5598 | |||
| 5599 | static struct css_id *get_new_cssid(struct cgroup_subsys *ss, int depth) | ||
| 5600 | { | ||
| 5601 | struct css_id *newid; | ||
| 5602 | int ret, size; | ||
| 5603 | |||
| 5604 | BUG_ON(!ss->use_id); | ||
| 5605 | |||
| 5606 | size = sizeof(*newid) + sizeof(unsigned short) * (depth + 1); | ||
| 5607 | newid = kzalloc(size, GFP_KERNEL); | ||
| 5608 | if (!newid) | ||
| 5609 | return ERR_PTR(-ENOMEM); | ||
| 5610 | |||
| 5611 | idr_preload(GFP_KERNEL); | ||
| 5612 | spin_lock(&ss->id_lock); | ||
| 5613 | /* Don't use 0. allocates an ID of 1-65535 */ | ||
| 5614 | ret = idr_alloc(&ss->idr, newid, 1, CSS_ID_MAX + 1, GFP_NOWAIT); | ||
| 5615 | spin_unlock(&ss->id_lock); | ||
| 5616 | idr_preload_end(); | ||
| 5617 | |||
| 5618 | /* Returns error when there are no free spaces for new ID.*/ | ||
| 5619 | if (ret < 0) | ||
| 5620 | goto err_out; | ||
| 5621 | |||
| 5622 | newid->id = ret; | ||
| 5623 | newid->depth = depth; | ||
| 5624 | return newid; | ||
| 5625 | err_out: | ||
| 5626 | kfree(newid); | ||
| 5627 | return ERR_PTR(ret); | ||
| 5628 | |||
| 5629 | } | ||
| 5630 | |||
| 5631 | static int __init_or_module cgroup_init_idr(struct cgroup_subsys *ss, | ||
| 5632 | struct cgroup_subsys_state *rootcss) | ||
| 5633 | { | ||
| 5634 | struct css_id *newid; | ||
| 5635 | |||
| 5636 | spin_lock_init(&ss->id_lock); | ||
| 5637 | idr_init(&ss->idr); | ||
| 5638 | |||
| 5639 | newid = get_new_cssid(ss, 0); | ||
| 5640 | if (IS_ERR(newid)) | ||
| 5641 | return PTR_ERR(newid); | ||
| 5642 | |||
| 5643 | newid->stack[0] = newid->id; | ||
| 5644 | RCU_INIT_POINTER(newid->css, rootcss); | ||
| 5645 | RCU_INIT_POINTER(rootcss->id, newid); | ||
| 5646 | return 0; | ||
| 5647 | } | ||
| 5648 | |||
| 5649 | static int alloc_css_id(struct cgroup_subsys_state *child_css) | ||
| 5650 | { | ||
| 5651 | struct cgroup_subsys_state *parent_css = css_parent(child_css); | ||
| 5652 | struct css_id *child_id, *parent_id; | ||
| 5653 | int i, depth; | ||
| 5654 | |||
| 5655 | parent_id = rcu_dereference_protected(parent_css->id, true); | ||
| 5656 | depth = parent_id->depth + 1; | ||
| 5657 | |||
| 5658 | child_id = get_new_cssid(child_css->ss, depth); | ||
| 5659 | if (IS_ERR(child_id)) | ||
| 5660 | return PTR_ERR(child_id); | ||
| 5661 | |||
| 5662 | for (i = 0; i < depth; i++) | ||
| 5663 | child_id->stack[i] = parent_id->stack[i]; | ||
| 5664 | child_id->stack[depth] = child_id->id; | ||
| 5665 | /* | ||
| 5666 | * child_id->css pointer will be set after this cgroup is available | ||
| 5667 | * see cgroup_populate_dir() | ||
| 5668 | */ | ||
| 5669 | rcu_assign_pointer(child_css->id, child_id); | ||
| 5670 | |||
| 5671 | return 0; | ||
| 5672 | } | ||
| 5673 | |||
| 5674 | /** | ||
| 5675 | * css_lookup - lookup css by id | ||
| 5676 | * @ss: cgroup subsys to be looked into. | ||
| 5677 | * @id: the id | ||
| 5678 | * | ||
| 5679 | * Returns pointer to cgroup_subsys_state if there is valid one with id. | ||
| 5680 | * NULL if not. Should be called under rcu_read_lock() | ||
| 5681 | */ | ||
| 5682 | struct cgroup_subsys_state *css_lookup(struct cgroup_subsys *ss, int id) | ||
| 5683 | { | ||
| 5684 | struct css_id *cssid = NULL; | ||
| 5685 | |||
| 5686 | BUG_ON(!ss->use_id); | ||
| 5687 | cssid = idr_find(&ss->idr, id); | ||
| 5688 | |||
| 5689 | if (unlikely(!cssid)) | ||
| 5690 | return NULL; | ||
| 5691 | |||
| 5692 | return rcu_dereference(cssid->css); | ||
| 5693 | } | ||
| 5694 | EXPORT_SYMBOL_GPL(css_lookup); | ||
| 5695 | |||
| 5696 | /** | 5486 | /** |
| 5697 | * css_from_dir - get corresponding css from the dentry of a cgroup dir | 5487 | * css_from_dir - get corresponding css from the dentry of a cgroup dir |
| 5698 | * @dentry: directory dentry of interest | 5488 | * @dentry: directory dentry of interest |
