Commit 415cb479 authored by Pekka Enberg's avatar Pekka Enberg

Merge branches 'slab/fixes', 'slob/fixes', 'slub/cleanups' and 'slub/fixes' into for-linus

...@@ -128,7 +128,6 @@ enum pageflags { ...@@ -128,7 +128,6 @@ enum pageflags {
/* SLUB */ /* SLUB */
PG_slub_frozen = PG_active, PG_slub_frozen = PG_active,
PG_slub_debug = PG_error,
}; };
#ifndef __GENERATING_BOUNDS_H #ifndef __GENERATING_BOUNDS_H
...@@ -215,7 +214,6 @@ PAGEFLAG(SwapBacked, swapbacked) __CLEARPAGEFLAG(SwapBacked, swapbacked) ...@@ -215,7 +214,6 @@ PAGEFLAG(SwapBacked, swapbacked) __CLEARPAGEFLAG(SwapBacked, swapbacked)
__PAGEFLAG(SlobFree, slob_free) __PAGEFLAG(SlobFree, slob_free)
__PAGEFLAG(SlubFrozen, slub_frozen) __PAGEFLAG(SlubFrozen, slub_frozen)
__PAGEFLAG(SlubDebug, slub_debug)
/* /*
* Private page markings that may be used by the filesystem that owns the page * Private page markings that may be used by the filesystem that owns the page
......
...@@ -268,7 +268,8 @@ static inline void *kmem_cache_alloc_node(struct kmem_cache *cachep, ...@@ -268,7 +268,8 @@ static inline void *kmem_cache_alloc_node(struct kmem_cache *cachep,
* allocator where we care about the real place the memory allocation * allocator where we care about the real place the memory allocation
* request comes from. * request comes from.
*/ */
#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB) #if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB) || \
(defined(CONFIG_SLAB) && defined(CONFIG_TRACING))
extern void *__kmalloc_track_caller(size_t, gfp_t, unsigned long); extern void *__kmalloc_track_caller(size_t, gfp_t, unsigned long);
#define kmalloc_track_caller(size, flags) \ #define kmalloc_track_caller(size, flags) \
__kmalloc_track_caller(size, flags, _RET_IP_) __kmalloc_track_caller(size, flags, _RET_IP_)
...@@ -286,7 +287,8 @@ extern void *__kmalloc_track_caller(size_t, gfp_t, unsigned long); ...@@ -286,7 +287,8 @@ extern void *__kmalloc_track_caller(size_t, gfp_t, unsigned long);
* standard allocator where we care about the real place the memory * standard allocator where we care about the real place the memory
* allocation request comes from. * allocation request comes from.
*/ */
#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB) #if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB) || \
(defined(CONFIG_SLAB) && defined(CONFIG_TRACING))
extern void *__kmalloc_node_track_caller(size_t, gfp_t, int, unsigned long); extern void *__kmalloc_node_track_caller(size_t, gfp_t, int, unsigned long);
#define kmalloc_node_track_caller(size, flags, node) \ #define kmalloc_node_track_caller(size, flags, node) \
__kmalloc_node_track_caller(size, flags, node, \ __kmalloc_node_track_caller(size, flags, node, \
......
...@@ -861,7 +861,7 @@ static void __cpuinit start_cpu_timer(int cpu) ...@@ -861,7 +861,7 @@ static void __cpuinit start_cpu_timer(int cpu)
*/ */
if (keventd_up() && reap_work->work.func == NULL) { if (keventd_up() && reap_work->work.func == NULL) {
init_reap_node(cpu); init_reap_node(cpu);
INIT_DELAYED_WORK(reap_work, cache_reap); INIT_DELAYED_WORK_DEFERRABLE(reap_work, cache_reap);
schedule_delayed_work_on(cpu, reap_work, schedule_delayed_work_on(cpu, reap_work,
__round_jiffies_relative(HZ, cpu)); __round_jiffies_relative(HZ, cpu));
} }
......
...@@ -394,6 +394,7 @@ static void slob_free(void *block, int size) ...@@ -394,6 +394,7 @@ static void slob_free(void *block, int size)
slob_t *prev, *next, *b = (slob_t *)block; slob_t *prev, *next, *b = (slob_t *)block;
slobidx_t units; slobidx_t units;
unsigned long flags; unsigned long flags;
struct list_head *slob_list;
if (unlikely(ZERO_OR_NULL_PTR(block))) if (unlikely(ZERO_OR_NULL_PTR(block)))
return; return;
...@@ -422,7 +423,13 @@ static void slob_free(void *block, int size) ...@@ -422,7 +423,13 @@ static void slob_free(void *block, int size)
set_slob(b, units, set_slob(b, units,
(void *)((unsigned long)(b + (void *)((unsigned long)(b +
SLOB_UNITS(PAGE_SIZE)) & PAGE_MASK)); SLOB_UNITS(PAGE_SIZE)) & PAGE_MASK));
set_slob_page_free(sp, &free_slob_small); if (size < SLOB_BREAK1)
slob_list = &free_slob_small;
else if (size < SLOB_BREAK2)
slob_list = &free_slob_medium;
else
slob_list = &free_slob_large;
set_slob_page_free(sp, slob_list);
goto out; goto out;
} }
......
...@@ -107,11 +107,17 @@ ...@@ -107,11 +107,17 @@
* the fast path and disables lockless freelists. * the fast path and disables lockless freelists.
*/ */
#define SLAB_DEBUG_FLAGS (SLAB_RED_ZONE | SLAB_POISON | SLAB_STORE_USER | \
SLAB_TRACE | SLAB_DEBUG_FREE)
static inline int kmem_cache_debug(struct kmem_cache *s)
{
#ifdef CONFIG_SLUB_DEBUG #ifdef CONFIG_SLUB_DEBUG
#define SLABDEBUG 1 return unlikely(s->flags & SLAB_DEBUG_FLAGS);
#else #else
#define SLABDEBUG 0 return 0;
#endif #endif
}
/* /*
* Issues still to be resolved: * Issues still to be resolved:
...@@ -162,8 +168,8 @@ ...@@ -162,8 +168,8 @@
#define MAX_OBJS_PER_PAGE 65535 /* since page.objects is u16 */ #define MAX_OBJS_PER_PAGE 65535 /* since page.objects is u16 */
/* Internal SLUB flags */ /* Internal SLUB flags */
#define __OBJECT_POISON 0x80000000 /* Poison object */ #define __OBJECT_POISON 0x80000000UL /* Poison object */
#define __SYSFS_ADD_DEFERRED 0x40000000 /* Not yet visible via sysfs */ #define __SYSFS_ADD_DEFERRED 0x40000000UL /* Not yet visible via sysfs */
static int kmem_size = sizeof(struct kmem_cache); static int kmem_size = sizeof(struct kmem_cache);
...@@ -1073,7 +1079,7 @@ static inline struct page *alloc_slab_page(gfp_t flags, int node, ...@@ -1073,7 +1079,7 @@ static inline struct page *alloc_slab_page(gfp_t flags, int node,
flags |= __GFP_NOTRACK; flags |= __GFP_NOTRACK;
if (node == -1) if (node == NUMA_NO_NODE)
return alloc_pages(flags, order); return alloc_pages(flags, order);
else else
return alloc_pages_exact_node(node, flags, order); return alloc_pages_exact_node(node, flags, order);
...@@ -1157,9 +1163,6 @@ static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node) ...@@ -1157,9 +1163,6 @@ static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
inc_slabs_node(s, page_to_nid(page), page->objects); inc_slabs_node(s, page_to_nid(page), page->objects);
page->slab = s; page->slab = s;
page->flags |= 1 << PG_slab; page->flags |= 1 << PG_slab;
if (s->flags & (SLAB_DEBUG_FREE | SLAB_RED_ZONE | SLAB_POISON |
SLAB_STORE_USER | SLAB_TRACE))
__SetPageSlubDebug(page);
start = page_address(page); start = page_address(page);
...@@ -1186,14 +1189,13 @@ static void __free_slab(struct kmem_cache *s, struct page *page) ...@@ -1186,14 +1189,13 @@ static void __free_slab(struct kmem_cache *s, struct page *page)
int order = compound_order(page); int order = compound_order(page);
int pages = 1 << order; int pages = 1 << order;
if (unlikely(SLABDEBUG && PageSlubDebug(page))) { if (kmem_cache_debug(s)) {
void *p; void *p;
slab_pad_check(s, page); slab_pad_check(s, page);
for_each_object(p, s, page_address(page), for_each_object(p, s, page_address(page),
page->objects) page->objects)
check_object(s, page, p, 0); check_object(s, page, p, 0);
__ClearPageSlubDebug(page);
} }
kmemcheck_free_shadow(page, compound_order(page)); kmemcheck_free_shadow(page, compound_order(page));
...@@ -1387,10 +1389,10 @@ static struct page *get_any_partial(struct kmem_cache *s, gfp_t flags) ...@@ -1387,10 +1389,10 @@ static struct page *get_any_partial(struct kmem_cache *s, gfp_t flags)
static struct page *get_partial(struct kmem_cache *s, gfp_t flags, int node) static struct page *get_partial(struct kmem_cache *s, gfp_t flags, int node)
{ {
struct page *page; struct page *page;
int searchnode = (node == -1) ? numa_node_id() : node; int searchnode = (node == NUMA_NO_NODE) ? numa_node_id() : node;
page = get_partial_node(get_node(s, searchnode)); page = get_partial_node(get_node(s, searchnode));
if (page || (flags & __GFP_THISNODE)) if (page || node != -1)
return page; return page;
return get_any_partial(s, flags); return get_any_partial(s, flags);
...@@ -1415,8 +1417,7 @@ static void unfreeze_slab(struct kmem_cache *s, struct page *page, int tail) ...@@ -1415,8 +1417,7 @@ static void unfreeze_slab(struct kmem_cache *s, struct page *page, int tail)
stat(s, tail ? DEACTIVATE_TO_TAIL : DEACTIVATE_TO_HEAD); stat(s, tail ? DEACTIVATE_TO_TAIL : DEACTIVATE_TO_HEAD);
} else { } else {
stat(s, DEACTIVATE_FULL); stat(s, DEACTIVATE_FULL);
if (SLABDEBUG && PageSlubDebug(page) && if (kmem_cache_debug(s) && (s->flags & SLAB_STORE_USER))
(s->flags & SLAB_STORE_USER))
add_full(n, page); add_full(n, page);
} }
slab_unlock(page); slab_unlock(page);
...@@ -1515,7 +1516,7 @@ static void flush_all(struct kmem_cache *s) ...@@ -1515,7 +1516,7 @@ static void flush_all(struct kmem_cache *s)
static inline int node_match(struct kmem_cache_cpu *c, int node) static inline int node_match(struct kmem_cache_cpu *c, int node)
{ {
#ifdef CONFIG_NUMA #ifdef CONFIG_NUMA
if (node != -1 && c->node != node) if (node != NUMA_NO_NODE && c->node != node)
return 0; return 0;
#endif #endif
return 1; return 1;
...@@ -1624,7 +1625,7 @@ static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node, ...@@ -1624,7 +1625,7 @@ static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
object = c->page->freelist; object = c->page->freelist;
if (unlikely(!object)) if (unlikely(!object))
goto another_slab; goto another_slab;
if (unlikely(SLABDEBUG && PageSlubDebug(c->page))) if (kmem_cache_debug(s))
goto debug; goto debug;
c->freelist = get_freepointer(s, object); c->freelist = get_freepointer(s, object);
...@@ -1727,7 +1728,7 @@ static __always_inline void *slab_alloc(struct kmem_cache *s, ...@@ -1727,7 +1728,7 @@ static __always_inline void *slab_alloc(struct kmem_cache *s,
void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags) void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags)
{ {
void *ret = slab_alloc(s, gfpflags, -1, _RET_IP_); void *ret = slab_alloc(s, gfpflags, NUMA_NO_NODE, _RET_IP_);
trace_kmem_cache_alloc(_RET_IP_, ret, s->objsize, s->size, gfpflags); trace_kmem_cache_alloc(_RET_IP_, ret, s->objsize, s->size, gfpflags);
...@@ -1738,7 +1739,7 @@ EXPORT_SYMBOL(kmem_cache_alloc); ...@@ -1738,7 +1739,7 @@ EXPORT_SYMBOL(kmem_cache_alloc);
#ifdef CONFIG_TRACING #ifdef CONFIG_TRACING
void *kmem_cache_alloc_notrace(struct kmem_cache *s, gfp_t gfpflags) void *kmem_cache_alloc_notrace(struct kmem_cache *s, gfp_t gfpflags)
{ {
return slab_alloc(s, gfpflags, -1, _RET_IP_); return slab_alloc(s, gfpflags, NUMA_NO_NODE, _RET_IP_);
} }
EXPORT_SYMBOL(kmem_cache_alloc_notrace); EXPORT_SYMBOL(kmem_cache_alloc_notrace);
#endif #endif
...@@ -1783,7 +1784,7 @@ static void __slab_free(struct kmem_cache *s, struct page *page, ...@@ -1783,7 +1784,7 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
stat(s, FREE_SLOWPATH); stat(s, FREE_SLOWPATH);
slab_lock(page); slab_lock(page);
if (unlikely(SLABDEBUG && PageSlubDebug(page))) if (kmem_cache_debug(s))
goto debug; goto debug;
checks_ok: checks_ok:
...@@ -2490,7 +2491,6 @@ void kmem_cache_destroy(struct kmem_cache *s) ...@@ -2490,7 +2491,6 @@ void kmem_cache_destroy(struct kmem_cache *s)
s->refcount--; s->refcount--;
if (!s->refcount) { if (!s->refcount) {
list_del(&s->list); list_del(&s->list);
up_write(&slub_lock);
if (kmem_cache_close(s)) { if (kmem_cache_close(s)) {
printk(KERN_ERR "SLUB %s: %s called for cache that " printk(KERN_ERR "SLUB %s: %s called for cache that "
"still has objects.\n", s->name, __func__); "still has objects.\n", s->name, __func__);
...@@ -2499,7 +2499,7 @@ void kmem_cache_destroy(struct kmem_cache *s) ...@@ -2499,7 +2499,7 @@ void kmem_cache_destroy(struct kmem_cache *s)
if (s->flags & SLAB_DESTROY_BY_RCU) if (s->flags & SLAB_DESTROY_BY_RCU)
rcu_barrier(); rcu_barrier();
sysfs_slab_remove(s); sysfs_slab_remove(s);
} else }
up_write(&slub_lock); up_write(&slub_lock);
} }
EXPORT_SYMBOL(kmem_cache_destroy); EXPORT_SYMBOL(kmem_cache_destroy);
...@@ -2728,7 +2728,7 @@ void *__kmalloc(size_t size, gfp_t flags) ...@@ -2728,7 +2728,7 @@ void *__kmalloc(size_t size, gfp_t flags)
if (unlikely(ZERO_OR_NULL_PTR(s))) if (unlikely(ZERO_OR_NULL_PTR(s)))
return s; return s;
ret = slab_alloc(s, flags, -1, _RET_IP_); ret = slab_alloc(s, flags, NUMA_NO_NODE, _RET_IP_);
trace_kmalloc(_RET_IP_, ret, size, s->size, flags); trace_kmalloc(_RET_IP_, ret, size, s->size, flags);
...@@ -3118,9 +3118,12 @@ void __init kmem_cache_init(void) ...@@ -3118,9 +3118,12 @@ void __init kmem_cache_init(void)
slab_state = UP; slab_state = UP;
/* Provide the correct kmalloc names now that the caches are up */ /* Provide the correct kmalloc names now that the caches are up */
for (i = KMALLOC_SHIFT_LOW; i < SLUB_PAGE_SHIFT; i++) for (i = KMALLOC_SHIFT_LOW; i < SLUB_PAGE_SHIFT; i++) {
kmalloc_caches[i]. name = char *s = kasprintf(GFP_NOWAIT, "kmalloc-%d", 1 << i);
kasprintf(GFP_NOWAIT, "kmalloc-%d", 1 << i);
BUG_ON(!s);
kmalloc_caches[i].name = s;
}
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
register_cpu_notifier(&slab_notifier); register_cpu_notifier(&slab_notifier);
...@@ -3223,14 +3226,12 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size, ...@@ -3223,14 +3226,12 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size,
*/ */
s->objsize = max(s->objsize, (int)size); s->objsize = max(s->objsize, (int)size);
s->inuse = max_t(int, s->inuse, ALIGN(size, sizeof(void *))); s->inuse = max_t(int, s->inuse, ALIGN(size, sizeof(void *)));
up_write(&slub_lock);
if (sysfs_slab_alias(s, name)) { if (sysfs_slab_alias(s, name)) {
down_write(&slub_lock);
s->refcount--; s->refcount--;
up_write(&slub_lock);
goto err; goto err;
} }
up_write(&slub_lock);
return s; return s;
} }
...@@ -3239,14 +3240,12 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size, ...@@ -3239,14 +3240,12 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size,
if (kmem_cache_open(s, GFP_KERNEL, name, if (kmem_cache_open(s, GFP_KERNEL, name,
size, align, flags, ctor)) { size, align, flags, ctor)) {
list_add(&s->list, &slab_caches); list_add(&s->list, &slab_caches);
up_write(&slub_lock);
if (sysfs_slab_add(s)) { if (sysfs_slab_add(s)) {
down_write(&slub_lock);
list_del(&s->list); list_del(&s->list);
up_write(&slub_lock);
kfree(s); kfree(s);
goto err; goto err;
} }
up_write(&slub_lock);
return s; return s;
} }
kfree(s); kfree(s);
...@@ -3312,7 +3311,7 @@ void *__kmalloc_track_caller(size_t size, gfp_t gfpflags, unsigned long caller) ...@@ -3312,7 +3311,7 @@ void *__kmalloc_track_caller(size_t size, gfp_t gfpflags, unsigned long caller)
if (unlikely(ZERO_OR_NULL_PTR(s))) if (unlikely(ZERO_OR_NULL_PTR(s)))
return s; return s;
ret = slab_alloc(s, gfpflags, -1, caller); ret = slab_alloc(s, gfpflags, NUMA_NO_NODE, caller);
/* Honor the call site pointer we recieved. */ /* Honor the call site pointer we recieved. */
trace_kmalloc(caller, ret, size, s->size, gfpflags); trace_kmalloc(caller, ret, size, s->size, gfpflags);
...@@ -3395,16 +3394,6 @@ static void validate_slab_slab(struct kmem_cache *s, struct page *page, ...@@ -3395,16 +3394,6 @@ static void validate_slab_slab(struct kmem_cache *s, struct page *page,
} else } else
printk(KERN_INFO "SLUB %s: Skipped busy slab 0x%p\n", printk(KERN_INFO "SLUB %s: Skipped busy slab 0x%p\n",
s->name, page); s->name, page);
if (s->flags & DEBUG_DEFAULT_FLAGS) {
if (!PageSlubDebug(page))
printk(KERN_ERR "SLUB %s: SlubDebug not set "
"on slab 0x%p\n", s->name, page);
} else {
if (PageSlubDebug(page))
printk(KERN_ERR "SLUB %s: SlubDebug set on "
"slab 0x%p\n", s->name, page);
}
} }
static int validate_slab_node(struct kmem_cache *s, static int validate_slab_node(struct kmem_cache *s,
...@@ -4504,6 +4493,13 @@ static int sysfs_slab_add(struct kmem_cache *s) ...@@ -4504,6 +4493,13 @@ static int sysfs_slab_add(struct kmem_cache *s)
static void sysfs_slab_remove(struct kmem_cache *s) static void sysfs_slab_remove(struct kmem_cache *s)
{ {
if (slab_state < SYSFS)
/*
* Sysfs has not been setup yet so no need to remove the
* cache from sysfs.
*/
return;
kobject_uevent(&s->kobj, KOBJ_REMOVE); kobject_uevent(&s->kobj, KOBJ_REMOVE);
kobject_del(&s->kobj); kobject_del(&s->kobj);
kobject_put(&s->kobj); kobject_put(&s->kobj);
...@@ -4549,8 +4545,11 @@ static int __init slab_sysfs_init(void) ...@@ -4549,8 +4545,11 @@ static int __init slab_sysfs_init(void)
struct kmem_cache *s; struct kmem_cache *s;
int err; int err;
down_write(&slub_lock);
slab_kset = kset_create_and_add("slab", &slab_uevent_ops, kernel_kobj); slab_kset = kset_create_and_add("slab", &slab_uevent_ops, kernel_kobj);
if (!slab_kset) { if (!slab_kset) {
up_write(&slub_lock);
printk(KERN_ERR "Cannot register slab subsystem.\n"); printk(KERN_ERR "Cannot register slab subsystem.\n");
return -ENOSYS; return -ENOSYS;
} }
...@@ -4575,6 +4574,7 @@ static int __init slab_sysfs_init(void) ...@@ -4575,6 +4574,7 @@ static int __init slab_sysfs_init(void)
kfree(al); kfree(al);
} }
up_write(&slub_lock);
resiliency_test(); resiliency_test();
return 0; return 0;
} }
......
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