diff options
author | Glauber Costa <glommer@parallels.com> | 2012-12-18 17:22:55 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-18 18:02:14 -0500 |
commit | 7cf2798240a2a2230cb16a391beef98d8a7ad362 (patch) | |
tree | 989f28b74d08bf91938cc5a7fe632faa32e7542f /mm | |
parent | 1f458cbf122288b23620ee822e19bcbb76c8d6ec (diff) |
memcg/sl[au]b: track all the memcg children of a kmem_cache
This enables us to remove all the children of a kmem_cache being
destroyed, if for example the kernel module it's being used in gets
unloaded. Otherwise, the children will still point to the destroyed
parent.
Signed-off-by: Suleiman Souhlal <suleiman@google.com>
Signed-off-by: Glauber Costa <glommer@parallels.com>
Cc: Christoph Lameter <cl@linux.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Frederic Weisbecker <fweisbec@redhat.com>
Cc: Greg Thelen <gthelen@google.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: JoonSoo Kim <js1304@gmail.com>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: Mel Gorman <mel@csn.ul.ie>
Cc: Michal Hocko <mhocko@suse.cz>
Cc: Pekka Enberg <penberg@cs.helsinki.fi>
Cc: Rik van Riel <riel@redhat.com>
Cc: Tejun Heo <tj@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r-- | mm/memcontrol.c | 49 | ||||
-rw-r--r-- | mm/slab_common.c | 3 |
2 files changed, 50 insertions, 2 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 270a36789859..4b68ec2c8df6 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -2772,6 +2772,8 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg, | |||
2772 | memcg_check_events(memcg, page); | 2772 | memcg_check_events(memcg, page); |
2773 | } | 2773 | } |
2774 | 2774 | ||
2775 | static DEFINE_MUTEX(set_limit_mutex); | ||
2776 | |||
2775 | #ifdef CONFIG_MEMCG_KMEM | 2777 | #ifdef CONFIG_MEMCG_KMEM |
2776 | static inline bool memcg_can_account_kmem(struct mem_cgroup *memcg) | 2778 | static inline bool memcg_can_account_kmem(struct mem_cgroup *memcg) |
2777 | { | 2779 | { |
@@ -3176,6 +3178,51 @@ out: | |||
3176 | return new_cachep; | 3178 | return new_cachep; |
3177 | } | 3179 | } |
3178 | 3180 | ||
3181 | void kmem_cache_destroy_memcg_children(struct kmem_cache *s) | ||
3182 | { | ||
3183 | struct kmem_cache *c; | ||
3184 | int i; | ||
3185 | |||
3186 | if (!s->memcg_params) | ||
3187 | return; | ||
3188 | if (!s->memcg_params->is_root_cache) | ||
3189 | return; | ||
3190 | |||
3191 | /* | ||
3192 | * If the cache is being destroyed, we trust that there is no one else | ||
3193 | * requesting objects from it. Even if there are, the sanity checks in | ||
3194 | * kmem_cache_destroy should caught this ill-case. | ||
3195 | * | ||
3196 | * Still, we don't want anyone else freeing memcg_caches under our | ||
3197 | * noses, which can happen if a new memcg comes to life. As usual, | ||
3198 | * we'll take the set_limit_mutex to protect ourselves against this. | ||
3199 | */ | ||
3200 | mutex_lock(&set_limit_mutex); | ||
3201 | for (i = 0; i < memcg_limited_groups_array_size; i++) { | ||
3202 | c = s->memcg_params->memcg_caches[i]; | ||
3203 | if (!c) | ||
3204 | continue; | ||
3205 | |||
3206 | /* | ||
3207 | * We will now manually delete the caches, so to avoid races | ||
3208 | * we need to cancel all pending destruction workers and | ||
3209 | * proceed with destruction ourselves. | ||
3210 | * | ||
3211 | * kmem_cache_destroy() will call kmem_cache_shrink internally, | ||
3212 | * and that could spawn the workers again: it is likely that | ||
3213 | * the cache still have active pages until this very moment. | ||
3214 | * This would lead us back to mem_cgroup_destroy_cache. | ||
3215 | * | ||
3216 | * But that will not execute at all if the "dead" flag is not | ||
3217 | * set, so flip it down to guarantee we are in control. | ||
3218 | */ | ||
3219 | c->memcg_params->dead = false; | ||
3220 | cancel_delayed_work_sync(&c->memcg_params->destroy); | ||
3221 | kmem_cache_destroy(c); | ||
3222 | } | ||
3223 | mutex_unlock(&set_limit_mutex); | ||
3224 | } | ||
3225 | |||
3179 | struct create_work { | 3226 | struct create_work { |
3180 | struct mem_cgroup *memcg; | 3227 | struct mem_cgroup *memcg; |
3181 | struct kmem_cache *cachep; | 3228 | struct kmem_cache *cachep; |
@@ -4284,8 +4331,6 @@ void mem_cgroup_print_bad_page(struct page *page) | |||
4284 | } | 4331 | } |
4285 | #endif | 4332 | #endif |
4286 | 4333 | ||
4287 | static DEFINE_MUTEX(set_limit_mutex); | ||
4288 | |||
4289 | static int mem_cgroup_resize_limit(struct mem_cgroup *memcg, | 4334 | static int mem_cgroup_resize_limit(struct mem_cgroup *memcg, |
4290 | unsigned long long val) | 4335 | unsigned long long val) |
4291 | { | 4336 | { |
diff --git a/mm/slab_common.c b/mm/slab_common.c index 1c424b6511bf..080a43804bf1 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c | |||
@@ -249,6 +249,9 @@ EXPORT_SYMBOL(kmem_cache_create); | |||
249 | 249 | ||
250 | void kmem_cache_destroy(struct kmem_cache *s) | 250 | void kmem_cache_destroy(struct kmem_cache *s) |
251 | { | 251 | { |
252 | /* Destroy all the children caches if we aren't a memcg cache */ | ||
253 | kmem_cache_destroy_memcg_children(s); | ||
254 | |||
252 | get_online_cpus(); | 255 | get_online_cpus(); |
253 | mutex_lock(&slab_mutex); | 256 | mutex_lock(&slab_mutex); |
254 | s->refcount--; | 257 | s->refcount--; |