Re: [linux-next-20130422] Bug in SLAB?

From: Tetsuo Handa
Date: Mon Apr 29 2013 - 17:46:21 EST


Christoph Lameter wrote:
> Ok so the maximum allocation is 11+12=23 which is 8M. KMALLOC_MAX_SIZE
> amd KMALLOC_SHIFT_HIGH are wrong.
>
> Take the -1 off the constants under #ifdef CONFIG_SLAB in

Current diff is:

---------- patch start ----------
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 0c62175..889d6ef 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -189,8 +189,8 @@ struct kmem_cache {
* to do various tricks to work around compiler limitations in order to
* ensure proper constant folding.
*/
-#define KMALLOC_SHIFT_HIGH ((MAX_ORDER + PAGE_SHIFT - 1) <= 25 ? \
- (MAX_ORDER + PAGE_SHIFT - 1) : 25)
+#define KMALLOC_SHIFT_HIGH ((MAX_ORDER + PAGE_SHIFT) <= 26 ? \
+ (MAX_ORDER + PAGE_SHIFT) : 26)
#define KMALLOC_SHIFT_MAX KMALLOC_SHIFT_HIGH
#ifndef KMALLOC_SHIFT_LOW
#define KMALLOC_SHIFT_LOW 5
@@ -221,9 +221,9 @@ struct kmem_cache {
#define KMALLOC_MIN_SIZE (1 << KMALLOC_SHIFT_LOW)
#endif

-extern struct kmem_cache *kmalloc_caches[KMALLOC_SHIFT_HIGH + 1];
+extern struct kmem_cache *kmalloc_caches[KMALLOC_SHIFT_HIGH];
#ifdef CONFIG_ZONE_DMA
-extern struct kmem_cache *kmalloc_dma_caches[KMALLOC_SHIFT_HIGH + 1];
+extern struct kmem_cache *kmalloc_dma_caches[KMALLOC_SHIFT_HIGH];
#endif

/*
diff --git a/include/linux/slab_def.h b/include/linux/slab_def.h
index 113ec08..be1446a 100644
--- a/include/linux/slab_def.h
+++ b/include/linux/slab_def.h
@@ -126,6 +126,9 @@ static __always_inline void *kmalloc(size_t size, gfp_t flags)
if (!size)
return ZERO_SIZE_PTR;

+ if (size > KMALLOC_MAX_SIZE)
+ goto not_found;
+
i = kmalloc_index(size);

#ifdef CONFIG_ZONE_DMA
@@ -139,6 +142,7 @@ static __always_inline void *kmalloc(size_t size, gfp_t flags)

return ret;
}
+not_found:
return __kmalloc(size, flags);
}

@@ -172,8 +176,10 @@ static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node)
if (!size)
return ZERO_SIZE_PTR;

- i = kmalloc_index(size);
+ if (size > KMALLOC_MAX_SIZE)
+ goto not_found;

+ i = kmalloc_index(size);
#ifdef CONFIG_ZONE_DMA
if (flags & GFP_DMA)
cachep = kmalloc_dma_caches[i];
@@ -183,6 +189,7 @@ static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node)

return kmem_cache_alloc_node_trace(cachep, flags, node, size);
}
+not_found:
return __kmalloc_node(size, flags, node);
}

diff --git a/mm/slab_common.c b/mm/slab_common.c
index 2f0e7d5..083e7c7 100644
--- a/mm/slab_common.c
+++ b/mm/slab_common.c
@@ -319,11 +319,11 @@ struct kmem_cache *__init create_kmalloc_cache(const char *name, size_t size,
return s;
}

-struct kmem_cache *kmalloc_caches[KMALLOC_SHIFT_HIGH + 1];
+struct kmem_cache *kmalloc_caches[KMALLOC_SHIFT_HIGH];
EXPORT_SYMBOL(kmalloc_caches);

#ifdef CONFIG_ZONE_DMA
-struct kmem_cache *kmalloc_dma_caches[KMALLOC_SHIFT_HIGH + 1];
+struct kmem_cache *kmalloc_dma_caches[KMALLOC_SHIFT_HIGH];
EXPORT_SYMBOL(kmalloc_dma_caches);
#endif

---------- patch end ----------

Current testcases are:

---------- testcases start ----------
volatile unsigned int size;
void *ptr;
ptr = kmalloc(0, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 0, ptr);
kfree(ptr);
ptr = kmalloc(1, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 1, ptr);
kfree(ptr);
ptr = kmalloc(2, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 2, ptr);
kfree(ptr);
ptr = kmalloc(4, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 4, ptr);
kfree(ptr);
ptr = kmalloc(8, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 8, ptr);
kfree(ptr);
ptr = kmalloc(16, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 16, ptr);
kfree(ptr);
ptr = kmalloc(32, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 32, ptr);
kfree(ptr);
ptr = kmalloc(64, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 64, ptr);
kfree(ptr);
ptr = kmalloc(128, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 128, ptr);
kfree(ptr);
ptr = kmalloc(256, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 256, ptr);
kfree(ptr);
ptr = kmalloc(512, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 512, ptr);
kfree(ptr);
ptr = kmalloc(1024, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 1024, ptr);
kfree(ptr);
ptr = kmalloc(2 * 1024, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 2 * 1024, ptr);
kfree(ptr);
ptr = kmalloc(4 * 1024, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 4 * 1024, ptr);
kfree(ptr);
ptr = kmalloc(8 * 1024, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 8 * 1024, ptr);
kfree(ptr);
ptr = kmalloc(16 * 1024, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 16 * 1024, ptr);
kfree(ptr);
ptr = kmalloc(32 * 1024, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 32 * 1024, ptr);
kfree(ptr);
ptr = kmalloc(64 * 1024, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 64 * 1024, ptr);
kfree(ptr);
ptr = kmalloc(128 * 1024, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 128 * 1024, ptr);
kfree(ptr);
ptr = kmalloc(256 * 1024, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 256 * 1024, ptr);
kfree(ptr);
ptr = kmalloc(512 * 1024, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 512 * 1024, ptr);
kfree(ptr);
ptr = kmalloc(1024 * 1024, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 1024 * 1024, ptr);
kfree(ptr);
ptr = kmalloc(2 * 1024 * 1024, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 2 * 1024 * 1024, ptr);
kfree(ptr);
ptr = kmalloc(4 * 1024 * 1024, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 4 * 1024 * 1024, ptr);
kfree(ptr);
ptr = kmalloc(8 * 1024 * 1024, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 8 * 1024 * 1024, ptr);
kfree(ptr);
ptr = kmalloc(16 * 1024 * 1024, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 16 * 1024 * 1024, ptr);
kfree(ptr);
ptr = kmalloc(32 * 1024 * 1024, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 32 * 1024 * 1024, ptr);
kfree(ptr);
ptr = kmalloc(64 * 1024 * 1024, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 64 * 1024 * 1024, ptr);
kfree(ptr);
ptr = kmalloc(128 * 1024 * 1024, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 128 * 1024 * 1024, ptr);
kfree(ptr);
ptr = kmalloc(256 * 1024 * 1024, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 256 * 1024 * 1024, ptr);
kfree(ptr);
ptr = kmalloc(512 * 1024 * 1024, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 512 * 1024 * 1024, ptr);
kfree(ptr);
ptr = kmalloc(1024 * 1024 * 1024, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 1024 * 1024 * 1024, ptr);
kfree(ptr);
ptr = kmalloc(2 * 1024 * 1024 * 1024, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 2 * 1024 * 1024 * 1024, ptr);
kfree(ptr);
ptr = kmalloc(2 * 1024 * 1024 * 1024 + 1, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", 2 * 1024 * 1024 * 1024 + 1, ptr);
kfree(ptr);
for (size = 0; size; size <<= 1) {
ptr = kmalloc(size, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", size, ptr);
kfree(ptr);
if (!size)
size = 1;
}
for (size = 1; size; size <<= 1) {
ptr = kmalloc(size + 1, GFP_KERNEL);
printk("kmalloc(%u)=%p\n", size + 1, ptr);
kfree(ptr);
}
---------- testcases end ----------

The testcases still trigger BUG() at 32M:

---------- dmesg start ----------
(...snipped...)
kmalloc(2097152)=dde00000
kmalloc(4194304)=d9c00000
------------[ cut here ]------------
WARNING: at mm/page_alloc.c:2410 __alloc_pages_nodemask+0x179/0x650()
(...snipped...)
---[ end trace c08f36179e2d8ff2 ]---
SLAB: Unable to allocate memory on node 0 (gfp=0xd0)
cache: kmalloc-8388608, object size: 8388608, order: 11
node 0: slabs: 0/0, objs: 0/0, free: 0
kmalloc(8388608)= (null)
kmalloc(16777216)= (null)
------------[ cut here ]------------
Kernel BUG at c10b9c9b [verbose debug info unavailable]
invalid opcode: 0000 [#1] SMP
(...snipped...)
---------- dmesg end ----------

This means that redirecting to !__builtin_constant_p(size) case does not help.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/