diff options
-rw-r--r-- | include/linux/cgroup.h | 3 | ||||
-rw-r--r-- | kernel/cgroup.c | 53 |
2 files changed, 39 insertions, 17 deletions
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 71e77e7cdb6f..c24bd0b9f93a 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h | |||
@@ -82,7 +82,8 @@ struct cgroup_subsys_state { | |||
82 | /* ID for this css, if possible */ | 82 | /* ID for this css, if possible */ |
83 | struct css_id __rcu *id; | 83 | struct css_id __rcu *id; |
84 | 84 | ||
85 | /* percpu_ref killing and putting dentry on the last css_put() */ | 85 | /* percpu_ref killing and RCU release */ |
86 | struct rcu_head rcu_head; | ||
86 | struct work_struct destroy_work; | 87 | struct work_struct destroy_work; |
87 | }; | 88 | }; |
88 | 89 | ||
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 3137e38995b0..66d01078eebe 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -869,18 +869,8 @@ static struct cgroup_name *cgroup_alloc_name(struct dentry *dentry) | |||
869 | static void cgroup_free_fn(struct work_struct *work) | 869 | static void cgroup_free_fn(struct work_struct *work) |
870 | { | 870 | { |
871 | struct cgroup *cgrp = container_of(work, struct cgroup, destroy_work); | 871 | struct cgroup *cgrp = container_of(work, struct cgroup, destroy_work); |
872 | struct cgroup_subsys *ss; | ||
873 | 872 | ||
874 | mutex_lock(&cgroup_mutex); | 873 | mutex_lock(&cgroup_mutex); |
875 | /* | ||
876 | * Release the subsystem state objects. | ||
877 | */ | ||
878 | for_each_root_subsys(cgrp->root, ss) { | ||
879 | struct cgroup_subsys_state *css = cgroup_css(cgrp, ss->subsys_id); | ||
880 | |||
881 | ss->css_free(css); | ||
882 | } | ||
883 | |||
884 | cgrp->root->number_of_cgroups--; | 874 | cgrp->root->number_of_cgroups--; |
885 | mutex_unlock(&cgroup_mutex); | 875 | mutex_unlock(&cgroup_mutex); |
886 | 876 | ||
@@ -4281,32 +4271,62 @@ err: | |||
4281 | return ret; | 4271 | return ret; |
4282 | } | 4272 | } |
4283 | 4273 | ||
4274 | /* | ||
4275 | * css destruction is four-stage process. | ||
4276 | * | ||
4277 | * 1. Destruction starts. Killing of the percpu_ref is initiated. | ||
4278 | * Implemented in kill_css(). | ||
4279 | * | ||
4280 | * 2. When the percpu_ref is confirmed to be visible as killed on all CPUs | ||
4281 | * and thus css_tryget() is guaranteed to fail, the css can be offlined | ||
4282 | * by invoking offline_css(). After offlining, the base ref is put. | ||
4283 | * Implemented in css_killed_work_fn(). | ||
4284 | * | ||
4285 | * 3. When the percpu_ref reaches zero, the only possible remaining | ||
4286 | * accessors are inside RCU read sections. css_release() schedules the | ||
4287 | * RCU callback. | ||
4288 | * | ||
4289 | * 4. After the grace period, the css can be freed. Implemented in | ||
4290 | * css_free_work_fn(). | ||
4291 | * | ||
4292 | * It is actually hairier because both step 2 and 4 require process context | ||
4293 | * and thus involve punting to css->destroy_work adding two additional | ||
4294 | * steps to the already complex sequence. | ||
4295 | */ | ||
4284 | static void css_free_work_fn(struct work_struct *work) | 4296 | static void css_free_work_fn(struct work_struct *work) |
4285 | { | 4297 | { |
4286 | struct cgroup_subsys_state *css = | 4298 | struct cgroup_subsys_state *css = |
4287 | container_of(work, struct cgroup_subsys_state, destroy_work); | 4299 | container_of(work, struct cgroup_subsys_state, destroy_work); |
4300 | struct cgroup *cgrp = css->cgroup; | ||
4288 | 4301 | ||
4289 | if (css->parent) | 4302 | if (css->parent) |
4290 | css_put(css->parent); | 4303 | css_put(css->parent); |
4291 | 4304 | ||
4292 | cgroup_dput(css->cgroup); | 4305 | css->ss->css_free(css); |
4306 | cgroup_dput(cgrp); | ||
4293 | } | 4307 | } |
4294 | 4308 | ||
4295 | static void css_release(struct percpu_ref *ref) | 4309 | static void css_free_rcu_fn(struct rcu_head *rcu_head) |
4296 | { | 4310 | { |
4297 | struct cgroup_subsys_state *css = | 4311 | struct cgroup_subsys_state *css = |
4298 | container_of(ref, struct cgroup_subsys_state, refcnt); | 4312 | container_of(rcu_head, struct cgroup_subsys_state, rcu_head); |
4299 | 4313 | ||
4300 | /* | 4314 | /* |
4301 | * css holds an extra ref to @cgrp->dentry which is put on the last | 4315 | * css holds an extra ref to @cgrp->dentry which is put on the last |
4302 | * css_put(). dput() requires process context, which css_put() may | 4316 | * css_put(). dput() requires process context which we don't have. |
4303 | * be called without. @css->destroy_work will be used to invoke | ||
4304 | * dput() asynchronously from css_put(). | ||
4305 | */ | 4317 | */ |
4306 | INIT_WORK(&css->destroy_work, css_free_work_fn); | 4318 | INIT_WORK(&css->destroy_work, css_free_work_fn); |
4307 | schedule_work(&css->destroy_work); | 4319 | schedule_work(&css->destroy_work); |
4308 | } | 4320 | } |
4309 | 4321 | ||
4322 | static void css_release(struct percpu_ref *ref) | ||
4323 | { | ||
4324 | struct cgroup_subsys_state *css = | ||
4325 | container_of(ref, struct cgroup_subsys_state, refcnt); | ||
4326 | |||
4327 | call_rcu(&css->rcu_head, css_free_rcu_fn); | ||
4328 | } | ||
4329 | |||
4310 | static void init_css(struct cgroup_subsys_state *css, struct cgroup_subsys *ss, | 4330 | static void init_css(struct cgroup_subsys_state *css, struct cgroup_subsys *ss, |
4311 | struct cgroup *cgrp) | 4331 | struct cgroup *cgrp) |
4312 | { | 4332 | { |
@@ -4356,6 +4376,7 @@ static void offline_css(struct cgroup_subsys_state *css) | |||
4356 | 4376 | ||
4357 | css->flags &= ~CSS_ONLINE; | 4377 | css->flags &= ~CSS_ONLINE; |
4358 | css->cgroup->nr_css--; | 4378 | css->cgroup->nr_css--; |
4379 | RCU_INIT_POINTER(css->cgroup->subsys[ss->subsys_id], css); | ||
4359 | } | 4380 | } |
4360 | 4381 | ||
4361 | /* | 4382 | /* |