diff options
-rw-r--r-- | include/linux/cgroup.h | 6 | ||||
-rw-r--r-- | kernel/cgroup.c | 31 | ||||
-rw-r--r-- | mm/memcontrol.c | 7 |
3 files changed, 15 insertions, 29 deletions
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 02e09c0e98ab..a3098046250b 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h | |||
@@ -85,7 +85,6 @@ struct cgroup_subsys_state { | |||
85 | /* bits in struct cgroup_subsys_state flags field */ | 85 | /* bits in struct cgroup_subsys_state flags field */ |
86 | enum { | 86 | enum { |
87 | CSS_ROOT, /* This CSS is the root of the subsystem */ | 87 | CSS_ROOT, /* This CSS is the root of the subsystem */ |
88 | CSS_REMOVED, /* This CSS is dead */ | ||
89 | }; | 88 | }; |
90 | 89 | ||
91 | /* Caller must verify that the css is not for root cgroup */ | 90 | /* Caller must verify that the css is not for root cgroup */ |
@@ -108,11 +107,6 @@ static inline void css_get(struct cgroup_subsys_state *css) | |||
108 | __css_get(css, 1); | 107 | __css_get(css, 1); |
109 | } | 108 | } |
110 | 109 | ||
111 | static inline bool css_is_removed(struct cgroup_subsys_state *css) | ||
112 | { | ||
113 | return test_bit(CSS_REMOVED, &css->flags); | ||
114 | } | ||
115 | |||
116 | /* | 110 | /* |
117 | * Call css_tryget() to take a reference on a css if your existing | 111 | * Call css_tryget() to take a reference on a css if your existing |
118 | * (known-valid) reference isn't already ref-counted. Returns false if | 112 | * (known-valid) reference isn't already ref-counted. Returns false if |
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 8c605e2bdd1a..c194f9e4fc7b 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -170,8 +170,8 @@ struct css_id { | |||
170 | * The css to which this ID points. This pointer is set to valid value | 170 | * The css to which this ID points. This pointer is set to valid value |
171 | * after cgroup is populated. If cgroup is removed, this will be NULL. | 171 | * after cgroup is populated. If cgroup is removed, this will be NULL. |
172 | * This pointer is expected to be RCU-safe because destroy() | 172 | * This pointer is expected to be RCU-safe because destroy() |
173 | * is called after synchronize_rcu(). But for safe use, css_is_removed() | 173 | * is called after synchronize_rcu(). But for safe use, css_tryget() |
174 | * css_tryget() should be used for avoiding race. | 174 | * should be used for avoiding race. |
175 | */ | 175 | */ |
176 | struct cgroup_subsys_state __rcu *css; | 176 | struct cgroup_subsys_state __rcu *css; |
177 | /* | 177 | /* |
@@ -4112,8 +4112,6 @@ static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry) | |||
4112 | } | 4112 | } |
4113 | prepare_to_wait(&cgroup_rmdir_waitq, &wait, TASK_INTERRUPTIBLE); | 4113 | prepare_to_wait(&cgroup_rmdir_waitq, &wait, TASK_INTERRUPTIBLE); |
4114 | 4114 | ||
4115 | local_irq_disable(); | ||
4116 | |||
4117 | /* block new css_tryget() by deactivating refcnt */ | 4115 | /* block new css_tryget() by deactivating refcnt */ |
4118 | for_each_subsys(cgrp->root, ss) { | 4116 | for_each_subsys(cgrp->root, ss) { |
4119 | struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id]; | 4117 | struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id]; |
@@ -4123,21 +4121,14 @@ static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry) | |||
4123 | } | 4121 | } |
4124 | 4122 | ||
4125 | /* | 4123 | /* |
4126 | * Set REMOVED. All in-progress css_tryget() will be released. | ||
4127 | * Put all the base refs. Each css holds an extra reference to the | 4124 | * Put all the base refs. Each css holds an extra reference to the |
4128 | * cgroup's dentry and cgroup removal proceeds regardless of css | 4125 | * cgroup's dentry and cgroup removal proceeds regardless of css |
4129 | * refs. On the last put of each css, whenever that may be, the | 4126 | * refs. On the last put of each css, whenever that may be, the |
4130 | * extra dentry ref is put so that dentry destruction happens only | 4127 | * extra dentry ref is put so that dentry destruction happens only |
4131 | * after all css's are released. | 4128 | * after all css's are released. |
4132 | */ | 4129 | */ |
4133 | for_each_subsys(cgrp->root, ss) { | 4130 | for_each_subsys(cgrp->root, ss) |
4134 | struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id]; | 4131 | css_put(cgrp->subsys[ss->subsys_id]); |
4135 | |||
4136 | set_bit(CSS_REMOVED, &css->flags); | ||
4137 | css_put(css); | ||
4138 | } | ||
4139 | |||
4140 | local_irq_enable(); | ||
4141 | 4132 | ||
4142 | finish_wait(&cgroup_rmdir_waitq, &wait); | 4133 | finish_wait(&cgroup_rmdir_waitq, &wait); |
4143 | clear_bit(CGRP_WAIT_ON_RMDIR, &cgrp->flags); | 4134 | clear_bit(CGRP_WAIT_ON_RMDIR, &cgrp->flags); |
@@ -4861,15 +4852,17 @@ static void check_for_release(struct cgroup *cgrp) | |||
4861 | /* Caller must verify that the css is not for root cgroup */ | 4852 | /* Caller must verify that the css is not for root cgroup */ |
4862 | bool __css_tryget(struct cgroup_subsys_state *css) | 4853 | bool __css_tryget(struct cgroup_subsys_state *css) |
4863 | { | 4854 | { |
4864 | do { | 4855 | while (true) { |
4865 | int v = css_refcnt(css); | 4856 | int t, v; |
4866 | 4857 | ||
4867 | if (atomic_cmpxchg(&css->refcnt, v, v + 1) == v) | 4858 | v = css_refcnt(css); |
4859 | t = atomic_cmpxchg(&css->refcnt, v, v + 1); | ||
4860 | if (likely(t == v)) | ||
4868 | return true; | 4861 | return true; |
4862 | else if (t < 0) | ||
4863 | return false; | ||
4869 | cpu_relax(); | 4864 | cpu_relax(); |
4870 | } while (!test_bit(CSS_REMOVED, &css->flags)); | 4865 | } |
4871 | |||
4872 | return false; | ||
4873 | } | 4866 | } |
4874 | EXPORT_SYMBOL_GPL(__css_tryget); | 4867 | EXPORT_SYMBOL_GPL(__css_tryget); |
4875 | 4868 | ||
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 5a1d584ffed3..37c356646544 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -2343,7 +2343,6 @@ static int __mem_cgroup_try_charge(struct mm_struct *mm, | |||
2343 | again: | 2343 | again: |
2344 | if (*ptr) { /* css should be a valid one */ | 2344 | if (*ptr) { /* css should be a valid one */ |
2345 | memcg = *ptr; | 2345 | memcg = *ptr; |
2346 | VM_BUG_ON(css_is_removed(&memcg->css)); | ||
2347 | if (mem_cgroup_is_root(memcg)) | 2346 | if (mem_cgroup_is_root(memcg)) |
2348 | goto done; | 2347 | goto done; |
2349 | if (nr_pages == 1 && consume_stock(memcg)) | 2348 | if (nr_pages == 1 && consume_stock(memcg)) |
@@ -2483,9 +2482,9 @@ static void __mem_cgroup_cancel_local_charge(struct mem_cgroup *memcg, | |||
2483 | 2482 | ||
2484 | /* | 2483 | /* |
2485 | * A helper function to get mem_cgroup from ID. must be called under | 2484 | * A helper function to get mem_cgroup from ID. must be called under |
2486 | * rcu_read_lock(). The caller must check css_is_removed() or some if | 2485 | * rcu_read_lock(). The caller is responsible for calling css_tryget if |
2487 | * it's concern. (dropping refcnt from swap can be called against removed | 2486 | * the mem_cgroup is used for charging. (dropping refcnt from swap can be |
2488 | * memcg.) | 2487 | * called against removed memcg.) |
2489 | */ | 2488 | */ |
2490 | static struct mem_cgroup *mem_cgroup_lookup(unsigned short id) | 2489 | static struct mem_cgroup *mem_cgroup_lookup(unsigned short id) |
2491 | { | 2490 | { |