From: Mark Fortescue , David Woodhouse Verious alignment fixes in the SLAB alocator that increased the size of the RedZone words failed to ensure that RedZone word 2 is aligned on a 64bit boundary. This resulted in random invalid instruction occourances on Sparc32 (sun4c). These additional changes should ensure that the RedZone words are correctly aligned on a 64bit boundary for architectures that require this. Signed-off-by: Mark Fortescue --- Tested on Sparc32:sun4c Additional testing desirable on PowerPC32, Sparc64, PowerPC64 and any other platforms where alignment changes may be of concirn. --- linux-2.6/mm/slab.c 2007-07-03 19:09:48.000000000 +0100 +++ linux-test/mm/slab.c 2007-07-04 04:14:15.000000000 +0100 @@ -137,6 +137,7 @@ /* Shouldn't this be in a header file somewhere? */ #define BYTES_PER_WORD sizeof(void *) +#define RED_ZONE_ALIGN (max(__alignof__(void *), __alignof(unsigned long long)) - 1) #ifndef cache_line_size #define cache_line_size() L1_CACHE_BYTES @@ -547,7 +548,7 @@ static unsigned long long *dbg_redzone2( if (cachep->flags & SLAB_STORE_USER) return (unsigned long long *)(objp + cachep->buffer_size - sizeof(unsigned long long) - - BYTES_PER_WORD); + max(BYTES_PER_WORD, __alignof__(unsigned long long))); return (unsigned long long *) (objp + cachep->buffer_size - sizeof(unsigned long long)); } @@ -2178,7 +2179,8 @@ kmem_cache_create (const char *name, siz * above the next power of two: caches with object sizes just above a * power of two have a significant amount of internal fragmentation. */ - if (size < 4096 || fls(size - 1) == fls(size-1 + 3 * BYTES_PER_WORD)) + if (size < 4096 || fls(size - 1) == fls(size-1 + 2 * sizeof(unsigned long long) + + max(BYTES_PER_WORD, __alignof__(unsigned long long)))) flags |= SLAB_RED_ZONE | SLAB_STORE_USER; if (!(flags & SLAB_DESTROY_BY_RCU)) flags |= SLAB_POISON; @@ -2197,9 +2199,9 @@ kmem_cache_create (const char *name, siz * unaligned accesses for some archs when redzoning is used, and makes * sure any on-slab bufctl's are also correctly aligned. */ - if (size & (BYTES_PER_WORD - 1)) { - size += (BYTES_PER_WORD - 1); - size &= ~(BYTES_PER_WORD - 1); + if (size & RED_ZONE_ALIGN) { + size += RED_ZONE_ALIGN; + size &= ~RED_ZONE_ALIGN; } /* calculate the final buffer alignment: */ @@ -2261,9 +2263,14 @@ kmem_cache_create (const char *name, siz } if (flags & SLAB_STORE_USER) { /* user store requires one word storage behind the end of - * the real object. + * the real object. But if the second red zone must be + * aligned 'better' than that, allow for it. */ - size += BYTES_PER_WORD; + if (flags & SLAB_RED_ZONE + && BYTES_PER_WORD < __alignof__(unsigned long long)) + size += __alignof__(unsigned long long); + else + size += BYTES_PER_WORD; } #if FORCED_DEBUG && defined(CONFIG_DEBUG_PAGEALLOC) if (size >= malloc_sizes[INDEX_L3 + 1].cs_size