Commit 4f12bb4f authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] slab: don't BUG on duplicated cache

slab presently goes BUG if someone tries to register an already-registered
cache.

But this can happen if the user accidentally loads a module which is already
statically linked into the kernel.  Nuking the kernel is rather a harsh
reaction.

Change it into a warning, and just fail the kmem_cache_alloc() attempt.  If
the module is well-behaved, the modprobe will fail and all is well.

Notes:

- Swaps the ranking of cache_chain_sem and lock_cpu_hotplug().  Doesn't seem
  important.
Acked-by: default avatarManfred Spraul <manfred@colorfullife.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 7fd93cf3
...@@ -1502,6 +1502,7 @@ kmem_cache_create (const char *name, size_t size, size_t align, ...@@ -1502,6 +1502,7 @@ kmem_cache_create (const char *name, size_t size, size_t align,
{ {
size_t left_over, slab_size, ralign; size_t left_over, slab_size, ralign;
kmem_cache_t *cachep = NULL; kmem_cache_t *cachep = NULL;
struct list_head *p;
/* /*
* Sanity checks... these are all serious usage bugs. * Sanity checks... these are all serious usage bugs.
...@@ -1516,6 +1517,35 @@ kmem_cache_create (const char *name, size_t size, size_t align, ...@@ -1516,6 +1517,35 @@ kmem_cache_create (const char *name, size_t size, size_t align,
BUG(); BUG();
} }
down(&cache_chain_sem);
list_for_each(p, &cache_chain) {
kmem_cache_t *pc = list_entry(p, kmem_cache_t, next);
mm_segment_t old_fs = get_fs();
char tmp;
int res;
/*
* This happens when the module gets unloaded and doesn't
* destroy its slab cache and no-one else reuses the vmalloc
* area of the module. Print a warning.
*/
set_fs(KERNEL_DS);
res = __get_user(tmp, pc->name);
set_fs(old_fs);
if (res) {
printk("SLAB: cache with size %d has lost its name\n",
pc->objsize);
continue;
}
if (!strcmp(pc->name,name)) {
printk("kmem_cache_create: duplicate cache %s\n", name);
dump_stack();
goto oops;
}
}
#if DEBUG #if DEBUG
WARN_ON(strchr(name, ' ')); /* It confuses parsers */ WARN_ON(strchr(name, ' ')); /* It confuses parsers */
if ((flags & SLAB_DEBUG_INITIAL) && !ctor) { if ((flags & SLAB_DEBUG_INITIAL) && !ctor) {
...@@ -1592,7 +1622,7 @@ kmem_cache_create (const char *name, size_t size, size_t align, ...@@ -1592,7 +1622,7 @@ kmem_cache_create (const char *name, size_t size, size_t align,
/* Get cache's description obj. */ /* Get cache's description obj. */
cachep = (kmem_cache_t *) kmem_cache_alloc(&cache_cache, SLAB_KERNEL); cachep = (kmem_cache_t *) kmem_cache_alloc(&cache_cache, SLAB_KERNEL);
if (!cachep) if (!cachep)
goto opps; goto oops;
memset(cachep, 0, sizeof(kmem_cache_t)); memset(cachep, 0, sizeof(kmem_cache_t));
#if DEBUG #if DEBUG
...@@ -1686,7 +1716,7 @@ next: ...@@ -1686,7 +1716,7 @@ next:
printk("kmem_cache_create: couldn't create cache %s.\n", name); printk("kmem_cache_create: couldn't create cache %s.\n", name);
kmem_cache_free(&cache_cache, cachep); kmem_cache_free(&cache_cache, cachep);
cachep = NULL; cachep = NULL;
goto opps; goto oops;
} }
slab_size = ALIGN(cachep->num*sizeof(kmem_bufctl_t) slab_size = ALIGN(cachep->num*sizeof(kmem_bufctl_t)
+ sizeof(struct slab), align); + sizeof(struct slab), align);
...@@ -1781,43 +1811,14 @@ next: ...@@ -1781,43 +1811,14 @@ next:
cachep->limit = BOOT_CPUCACHE_ENTRIES; cachep->limit = BOOT_CPUCACHE_ENTRIES;
} }
/* Need the semaphore to access the chain. */
down(&cache_chain_sem);
{
struct list_head *p;
mm_segment_t old_fs;
old_fs = get_fs();
set_fs(KERNEL_DS);
list_for_each(p, &cache_chain) {
kmem_cache_t *pc = list_entry(p, kmem_cache_t, next);
char tmp;
/* This happens when the module gets unloaded and doesn't
destroy its slab cache and noone else reuses the vmalloc
area of the module. Print a warning. */
if (__get_user(tmp,pc->name)) {
printk("SLAB: cache with size %d has lost its name\n",
pc->objsize);
continue;
}
if (!strcmp(pc->name,name)) {
printk("kmem_cache_create: duplicate cache %s\n",name);
up(&cache_chain_sem);
unlock_cpu_hotplug();
BUG();
}
}
set_fs(old_fs);
}
/* cache setup completed, link it into the list */ /* cache setup completed, link it into the list */
list_add(&cachep->next, &cache_chain); list_add(&cachep->next, &cache_chain);
up(&cache_chain_sem);
unlock_cpu_hotplug(); unlock_cpu_hotplug();
opps: oops:
if (!cachep && (flags & SLAB_PANIC)) if (!cachep && (flags & SLAB_PANIC))
panic("kmem_cache_create(): failed to create slab `%s'\n", panic("kmem_cache_create(): failed to create slab `%s'\n",
name); name);
up(&cache_chain_sem);
return cachep; return cachep;
} }
EXPORT_SYMBOL(kmem_cache_create); EXPORT_SYMBOL(kmem_cache_create);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment