Skip to content

Commit

Permalink
SLUB: accurately compare debug flags during slab cache merge
Browse files Browse the repository at this point in the history
This was posted on Aug 28 and fixes an issue that could cause troubles
when slab caches >=128k are created.

http://marc.info/?l=linux-mm&m=118798149918424&w=2

Currently we simply add the debug flags unconditional when checking for a
matching slab.  This creates issues for sysfs processing when slabs exist
that are exempt from debugging due to their huge size or because only a
subset of slabs was selected for debugging.

We need to only add the flags if kmem_cache_open() would also add them.

Create a function to calculate the flags that would be set
if the cache would be opened and use that function to determine
the flags before looking for a compatible slab.

[akpm@linux-foundation.org: fixlets]
Signed-off-by: Christoph Lameter <clameter@sgi.com>
Cc: Chuck Ebbert <cebbert@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Christoph Lameter authored and Linus Torvalds committed Sep 12, 2007
1 parent 4150d3f commit ba0268a
Showing 1 changed file with 23 additions and 15 deletions.
38 changes: 23 additions & 15 deletions mm/slub.c
Original file line number Diff line number Diff line change
Expand Up @@ -986,7 +986,9 @@ static int __init setup_slub_debug(char *str)

__setup("slub_debug", setup_slub_debug);

static void kmem_cache_open_debug_check(struct kmem_cache *s)
static unsigned long kmem_cache_flags(unsigned long objsize,
unsigned long flags, const char *name,
void (*ctor)(void *, struct kmem_cache *, unsigned long))
{
/*
* The page->offset field is only 16 bit wide. This is an offset
Expand All @@ -1000,19 +1002,21 @@ static void kmem_cache_open_debug_check(struct kmem_cache *s)
* Debugging or ctor may create a need to move the free
* pointer. Fail if this happens.
*/
if (s->objsize >= 65535 * sizeof(void *)) {
BUG_ON(s->flags & (SLAB_RED_ZONE | SLAB_POISON |
if (objsize >= 65535 * sizeof(void *)) {
BUG_ON(flags & (SLAB_RED_ZONE | SLAB_POISON |
SLAB_STORE_USER | SLAB_DESTROY_BY_RCU));
BUG_ON(s->ctor);
}
else
BUG_ON(ctor);
} else {
/*
* Enable debugging if selected on the kernel commandline.
*/
if (slub_debug && (!slub_debug_slabs ||
strncmp(slub_debug_slabs, s->name,
strncmp(slub_debug_slabs, name,
strlen(slub_debug_slabs)) == 0))
s->flags |= slub_debug;
flags |= slub_debug;
}

return flags;
}
#else
static inline void setup_object_debug(struct kmem_cache *s,
Expand All @@ -1029,7 +1033,12 @@ static inline int slab_pad_check(struct kmem_cache *s, struct page *page)
static inline int check_object(struct kmem_cache *s, struct page *page,
void *object, int active) { return 1; }
static inline void add_full(struct kmem_cache_node *n, struct page *page) {}
static inline void kmem_cache_open_debug_check(struct kmem_cache *s) {}
static inline unsigned long kmem_cache_flags(unsigned long objsize,
unsigned long flags, const char *name,
void (*ctor)(void *, struct kmem_cache *, unsigned long))
{
return flags;
}
#define slub_debug 0
#endif
/*
Expand Down Expand Up @@ -2088,9 +2097,8 @@ static int kmem_cache_open(struct kmem_cache *s, gfp_t gfpflags,
s->name = name;
s->ctor = ctor;
s->objsize = size;
s->flags = flags;
s->align = align;
kmem_cache_open_debug_check(s);
s->flags = kmem_cache_flags(size, flags, name, ctor);

if (!calculate_sizes(s))
goto error;
Expand Down Expand Up @@ -2660,7 +2668,7 @@ static int slab_unmergeable(struct kmem_cache *s)
}

static struct kmem_cache *find_mergeable(size_t size,
size_t align, unsigned long flags,
size_t align, unsigned long flags, const char *name,
void (*ctor)(void *, struct kmem_cache *, unsigned long))
{
struct kmem_cache *s;
Expand All @@ -2674,6 +2682,7 @@ static struct kmem_cache *find_mergeable(size_t size,
size = ALIGN(size, sizeof(void *));
align = calculate_alignment(flags, align, size);
size = ALIGN(size, align);
flags = kmem_cache_flags(size, flags, name, NULL);

list_for_each_entry(s, &slab_caches, list) {
if (slab_unmergeable(s))
Expand All @@ -2682,8 +2691,7 @@ static struct kmem_cache *find_mergeable(size_t size,
if (size > s->size)
continue;

if (((flags | slub_debug) & SLUB_MERGE_SAME) !=
(s->flags & SLUB_MERGE_SAME))
if ((flags & SLUB_MERGE_SAME) != (s->flags & SLUB_MERGE_SAME))
continue;
/*
* Check if alignment is compatible.
Expand All @@ -2707,7 +2715,7 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size,
struct kmem_cache *s;

down_write(&slub_lock);
s = find_mergeable(size, align, flags, ctor);
s = find_mergeable(size, align, flags, name, ctor);
if (s) {
s->refcount++;
/*
Expand Down

0 comments on commit ba0268a

Please sign in to comment.