mirror of
https://github.com/torvalds/linux.git
synced 2024-12-31 23:31:29 +00:00
[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: Manfred Spraul <manfred@colorfullife.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
7fd93cf30c
commit
4f12bb4f77
67
mm/slab.c
67
mm/slab.c
@ -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,
|
|||||||
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,
|
|||||||
/* 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:
|
|||||||
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:
|
|||||||
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);
|
||||||
|
Loading…
Reference in New Issue
Block a user