diff options
author | Pekka Enberg <penberg@kernel.org> | 2010-09-14 16:21:12 -0400 |
---|---|---|
committer | Pekka Enberg <penberg@kernel.org> | 2010-10-02 03:24:29 -0400 |
commit | 84c1cf62465e2fb0a692620dcfeb52323ab03d48 (patch) | |
tree | 704f4c7f7f0403aadd62be42d2e9d87abf2926fc /mm | |
parent | db210e70e5f191710a3b1d09f653b44885d397ea (diff) |
SLUB: Fix merged slab cache names
As explained by Linus "I'm Proud to be an American" Torvalds:
Looking at the merging code, I actually think it's totally
buggy. If you have something like this:
- load module A: create slab cache A
- load module B: create slab cache B that can merge with A
- unload module A
- "cat /proc/slabinfo": BOOM. Oops.
exactly because the name is not handled correctly, and you'll have
module B holding open a slab cache that has a name pointer that points
to module A that no longer exists.
This patch fixes the problem by using kstrdup() to allocate dynamic memory for
->name of "struct kmem_cache" as suggested by Christoph Lameter.
Acked-by: Christoph Lameter <cl@linux.com>
Cc: David Rientjes <rientjes@google.com>
Reported-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Pekka Enberg <penberg@kernel.org>
Conflicts:
mm/slub.c
Diffstat (limited to 'mm')
-rw-r--r-- | mm/slub.c | 21 |
1 files changed, 20 insertions, 1 deletions
@@ -209,6 +209,7 @@ static inline int sysfs_slab_alias(struct kmem_cache *s, const char *p) | |||
209 | { return 0; } | 209 | { return 0; } |
210 | static inline void sysfs_slab_remove(struct kmem_cache *s) | 210 | static inline void sysfs_slab_remove(struct kmem_cache *s) |
211 | { | 211 | { |
212 | kfree(s->name); | ||
212 | kfree(s); | 213 | kfree(s); |
213 | } | 214 | } |
214 | 215 | ||
@@ -3169,6 +3170,16 @@ void __init kmem_cache_init(void) | |||
3169 | slab_state = UP; | 3170 | slab_state = UP; |
3170 | 3171 | ||
3171 | /* Provide the correct kmalloc names now that the caches are up */ | 3172 | /* Provide the correct kmalloc names now that the caches are up */ |
3173 | if (KMALLOC_MIN_SIZE <= 32) { | ||
3174 | kmalloc_caches[1]->name = kstrdup(kmalloc_caches[1]->name, GFP_NOWAIT); | ||
3175 | BUG_ON(!kmalloc_caches[1]->name); | ||
3176 | } | ||
3177 | |||
3178 | if (KMALLOC_MIN_SIZE <= 64) { | ||
3179 | kmalloc_caches[2]->name = kstrdup(kmalloc_caches[2]->name, GFP_NOWAIT); | ||
3180 | BUG_ON(!kmalloc_caches[2]->name); | ||
3181 | } | ||
3182 | |||
3172 | for (i = KMALLOC_SHIFT_LOW; i < SLUB_PAGE_SHIFT; i++) { | 3183 | for (i = KMALLOC_SHIFT_LOW; i < SLUB_PAGE_SHIFT; i++) { |
3173 | char *s = kasprintf(GFP_NOWAIT, "kmalloc-%d", 1 << i); | 3184 | char *s = kasprintf(GFP_NOWAIT, "kmalloc-%d", 1 << i); |
3174 | 3185 | ||
@@ -3271,6 +3282,7 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size, | |||
3271 | size_t align, unsigned long flags, void (*ctor)(void *)) | 3282 | size_t align, unsigned long flags, void (*ctor)(void *)) |
3272 | { | 3283 | { |
3273 | struct kmem_cache *s; | 3284 | struct kmem_cache *s; |
3285 | char *n; | ||
3274 | 3286 | ||
3275 | if (WARN_ON(!name)) | 3287 | if (WARN_ON(!name)) |
3276 | return NULL; | 3288 | return NULL; |
@@ -3294,19 +3306,25 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size, | |||
3294 | return s; | 3306 | return s; |
3295 | } | 3307 | } |
3296 | 3308 | ||
3309 | n = kstrdup(name, GFP_KERNEL); | ||
3310 | if (!n) | ||
3311 | goto err; | ||
3312 | |||
3297 | s = kmalloc(kmem_size, GFP_KERNEL); | 3313 | s = kmalloc(kmem_size, GFP_KERNEL); |
3298 | if (s) { | 3314 | if (s) { |
3299 | if (kmem_cache_open(s, name, | 3315 | if (kmem_cache_open(s, n, |
3300 | size, align, flags, ctor)) { | 3316 | size, align, flags, ctor)) { |
3301 | list_add(&s->list, &slab_caches); | 3317 | list_add(&s->list, &slab_caches); |
3302 | if (sysfs_slab_add(s)) { | 3318 | if (sysfs_slab_add(s)) { |
3303 | list_del(&s->list); | 3319 | list_del(&s->list); |
3320 | kfree(n); | ||
3304 | kfree(s); | 3321 | kfree(s); |
3305 | goto err; | 3322 | goto err; |
3306 | } | 3323 | } |
3307 | up_write(&slub_lock); | 3324 | up_write(&slub_lock); |
3308 | return s; | 3325 | return s; |
3309 | } | 3326 | } |
3327 | kfree(n); | ||
3310 | kfree(s); | 3328 | kfree(s); |
3311 | } | 3329 | } |
3312 | up_write(&slub_lock); | 3330 | up_write(&slub_lock); |
@@ -4439,6 +4457,7 @@ static void kmem_cache_release(struct kobject *kobj) | |||
4439 | { | 4457 | { |
4440 | struct kmem_cache *s = to_slab(kobj); | 4458 | struct kmem_cache *s = to_slab(kobj); |
4441 | 4459 | ||
4460 | kfree(s->name); | ||
4442 | kfree(s); | 4461 | kfree(s); |
4443 | } | 4462 | } |
4444 | 4463 | ||