Commit bff157b3 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'slab/next' of git://git.kernel.org/pub/scm/linux/kernel/git/penberg/linux

Pull SLAB update from Pekka Enberg:
 "Nothing terribly exciting here apart from Christoph's kmalloc
  unification patches that brings sl[aou]b implementations closer to
  each other"

* 'slab/next' of git://git.kernel.org/pub/scm/linux/kernel/git/penberg/linux:
  slab: Use correct GFP_DMA constant
  slub: remove verify_mem_not_deleted()
  mm/sl[aou]b: Move kmallocXXX functions to common code
  mm, slab_common: add 'unlikely' to size check of kmalloc_slab()
  mm/slub.c: beautify code for removing redundancy 'break' statement.
  slub: Remove unnecessary page NULL check
  slub: don't use cpu partial pages on UP
  mm/slub: beautify code for 80 column limitation and tab alignment
  mm/slub: remove 'per_cpu' which is useless variable
parents 8bf5e36d 23774a2f
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
* (C) SGI 2006, Christoph Lameter * (C) SGI 2006, Christoph Lameter
* Cleaned up and restructured to ease the addition of alternative * Cleaned up and restructured to ease the addition of alternative
* implementations of SLAB allocators. * implementations of SLAB allocators.
* (C) Linux Foundation 2008-2013
* Unified interface for all slab allocators
*/ */
#ifndef _LINUX_SLAB_H #ifndef _LINUX_SLAB_H
...@@ -94,6 +96,7 @@ ...@@ -94,6 +96,7 @@
#define ZERO_OR_NULL_PTR(x) ((unsigned long)(x) <= \ #define ZERO_OR_NULL_PTR(x) ((unsigned long)(x) <= \
(unsigned long)ZERO_SIZE_PTR) (unsigned long)ZERO_SIZE_PTR)
#include <linux/kmemleak.h>
struct mem_cgroup; struct mem_cgroup;
/* /*
...@@ -289,6 +292,57 @@ static __always_inline int kmalloc_index(size_t size) ...@@ -289,6 +292,57 @@ static __always_inline int kmalloc_index(size_t size)
} }
#endif /* !CONFIG_SLOB */ #endif /* !CONFIG_SLOB */
void *__kmalloc(size_t size, gfp_t flags);
void *kmem_cache_alloc(struct kmem_cache *, gfp_t flags);
#ifdef CONFIG_NUMA
void *__kmalloc_node(size_t size, gfp_t flags, int node);
void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
#else
static __always_inline void *__kmalloc_node(size_t size, gfp_t flags, int node)
{
return __kmalloc(size, flags);
}
static __always_inline void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t flags, int node)
{
return kmem_cache_alloc(s, flags);
}
#endif
#ifdef CONFIG_TRACING
extern void *kmem_cache_alloc_trace(struct kmem_cache *, gfp_t, size_t);
#ifdef CONFIG_NUMA
extern void *kmem_cache_alloc_node_trace(struct kmem_cache *s,
gfp_t gfpflags,
int node, size_t size);
#else
static __always_inline void *
kmem_cache_alloc_node_trace(struct kmem_cache *s,
gfp_t gfpflags,
int node, size_t size)
{
return kmem_cache_alloc_trace(s, gfpflags, size);
}
#endif /* CONFIG_NUMA */
#else /* CONFIG_TRACING */
static __always_inline void *kmem_cache_alloc_trace(struct kmem_cache *s,
gfp_t flags, size_t size)
{
return kmem_cache_alloc(s, flags);
}
static __always_inline void *
kmem_cache_alloc_node_trace(struct kmem_cache *s,
gfp_t gfpflags,
int node, size_t size)
{
return kmem_cache_alloc_node(s, gfpflags, node);
}
#endif /* CONFIG_TRACING */
#ifdef CONFIG_SLAB #ifdef CONFIG_SLAB
#include <linux/slab_def.h> #include <linux/slab_def.h>
#endif #endif
...@@ -297,9 +351,60 @@ static __always_inline int kmalloc_index(size_t size) ...@@ -297,9 +351,60 @@ static __always_inline int kmalloc_index(size_t size)
#include <linux/slub_def.h> #include <linux/slub_def.h>
#endif #endif
#ifdef CONFIG_SLOB static __always_inline void *
#include <linux/slob_def.h> kmalloc_order(size_t size, gfp_t flags, unsigned int order)
{
void *ret;
flags |= (__GFP_COMP | __GFP_KMEMCG);
ret = (void *) __get_free_pages(flags, order);
kmemleak_alloc(ret, size, 1, flags);
return ret;
}
#ifdef CONFIG_TRACING
extern void *kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order);
#else
static __always_inline void *
kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order)
{
return kmalloc_order(size, flags, order);
}
#endif
static __always_inline void *kmalloc_large(size_t size, gfp_t flags)
{
unsigned int order = get_order(size);
return kmalloc_order_trace(size, flags, order);
}
/**
* kmalloc - allocate memory
* @size: how many bytes of memory are required.
* @flags: the type of memory to allocate (see kcalloc).
*
* kmalloc is the normal method of allocating memory
* for objects smaller than page size in the kernel.
*/
static __always_inline void *kmalloc(size_t size, gfp_t flags)
{
if (__builtin_constant_p(size)) {
if (size > KMALLOC_MAX_CACHE_SIZE)
return kmalloc_large(size, flags);
#ifndef CONFIG_SLOB
if (!(flags & GFP_DMA)) {
int index = kmalloc_index(size);
if (!index)
return ZERO_SIZE_PTR;
return kmem_cache_alloc_trace(kmalloc_caches[index],
flags, size);
}
#endif #endif
}
return __kmalloc(size, flags);
}
/* /*
* Determine size used for the nth kmalloc cache. * Determine size used for the nth kmalloc cache.
...@@ -321,6 +426,23 @@ static __always_inline int kmalloc_size(int n) ...@@ -321,6 +426,23 @@ static __always_inline int kmalloc_size(int n)
return 0; return 0;
} }
static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node)
{
#ifndef CONFIG_SLOB
if (__builtin_constant_p(size) &&
size <= KMALLOC_MAX_CACHE_SIZE && !(flags & GFP_DMA)) {
int i = kmalloc_index(size);
if (!i)
return ZERO_SIZE_PTR;
return kmem_cache_alloc_node_trace(kmalloc_caches[i],
flags, node, size);
}
#endif
return __kmalloc_node(size, flags, node);
}
/* /*
* Setting ARCH_SLAB_MINALIGN in arch headers allows a different alignment. * Setting ARCH_SLAB_MINALIGN in arch headers allows a different alignment.
* Intended for arches that get misalignment faults even for 64 bit integer * Intended for arches that get misalignment faults even for 64 bit integer
...@@ -451,36 +573,6 @@ static inline void *kcalloc(size_t n, size_t size, gfp_t flags) ...@@ -451,36 +573,6 @@ static inline void *kcalloc(size_t n, size_t size, gfp_t flags)
return kmalloc_array(n, size, flags | __GFP_ZERO); return kmalloc_array(n, size, flags | __GFP_ZERO);
} }
#if !defined(CONFIG_NUMA) && !defined(CONFIG_SLOB)
/**
* kmalloc_node - allocate memory from a specific node
* @size: how many bytes of memory are required.
* @flags: the type of memory to allocate (see kmalloc).
* @node: node to allocate from.
*
* kmalloc() for non-local nodes, used to allocate from a specific node
* if available. Equivalent to kmalloc() in the non-NUMA single-node
* case.
*/
static inline void *kmalloc_node(size_t size, gfp_t flags, int node)
{
return kmalloc(size, flags);
}
static inline void *__kmalloc_node(size_t size, gfp_t flags, int node)
{
return __kmalloc(size, flags);
}
void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
static inline void *kmem_cache_alloc_node(struct kmem_cache *cachep,
gfp_t flags, int node)
{
return kmem_cache_alloc(cachep, flags);
}
#endif /* !CONFIG_NUMA && !CONFIG_SLOB */
/* /*
* kmalloc_track_caller is a special version of kmalloc that records the * kmalloc_track_caller is a special version of kmalloc that records the
* calling function of the routine calling it for slab leak tracking instead * calling function of the routine calling it for slab leak tracking instead
......
...@@ -3,20 +3,6 @@ ...@@ -3,20 +3,6 @@
/* /*
* Definitions unique to the original Linux SLAB allocator. * Definitions unique to the original Linux SLAB allocator.
*
* What we provide here is a way to optimize the frequent kmalloc
* calls in the kernel by selecting the appropriate general cache
* if kmalloc was called with a size that can be established at
* compile time.
*/
#include <linux/init.h>
#include <linux/compiler.h>
/*
* struct kmem_cache
*
* manages a cache.
*/ */
struct kmem_cache { struct kmem_cache {
...@@ -102,96 +88,4 @@ struct kmem_cache { ...@@ -102,96 +88,4 @@ struct kmem_cache {
*/ */
}; };
void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
void *__kmalloc(size_t size, gfp_t flags);
#ifdef CONFIG_TRACING
extern void *kmem_cache_alloc_trace(struct kmem_cache *, gfp_t, size_t);
#else
static __always_inline void *
kmem_cache_alloc_trace(struct kmem_cache *cachep, gfp_t flags, size_t size)
{
return kmem_cache_alloc(cachep, flags);
}
#endif
static __always_inline void *kmalloc(size_t size, gfp_t flags)
{
struct kmem_cache *cachep;
void *ret;
if (__builtin_constant_p(size)) {
int i;
if (!size)
return ZERO_SIZE_PTR;
if (WARN_ON_ONCE(size > KMALLOC_MAX_SIZE))
return NULL;
i = kmalloc_index(size);
#ifdef CONFIG_ZONE_DMA
if (flags & GFP_DMA)
cachep = kmalloc_dma_caches[i];
else
#endif
cachep = kmalloc_caches[i];
ret = kmem_cache_alloc_trace(cachep, flags, size);
return ret;
}
return __kmalloc(size, flags);
}
#ifdef CONFIG_NUMA
extern void *__kmalloc_node(size_t size, gfp_t flags, int node);
extern void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
#ifdef CONFIG_TRACING
extern void *kmem_cache_alloc_node_trace(struct kmem_cache *cachep,
gfp_t flags,
int nodeid,
size_t size);
#else
static __always_inline void *
kmem_cache_alloc_node_trace(struct kmem_cache *cachep,
gfp_t flags,
int nodeid,
size_t size)
{
return kmem_cache_alloc_node(cachep, flags, nodeid);
}
#endif
static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node)
{
struct kmem_cache *cachep;
if (__builtin_constant_p(size)) {
int i;
if (!size)
return ZERO_SIZE_PTR;
if (WARN_ON_ONCE(size > KMALLOC_MAX_SIZE))
return NULL;
i = kmalloc_index(size);
#ifdef CONFIG_ZONE_DMA
if (flags & GFP_DMA)
cachep = kmalloc_dma_caches[i];
else
#endif
cachep = kmalloc_caches[i];
return kmem_cache_alloc_node_trace(cachep, flags, node, size);
}
return __kmalloc_node(size, flags, node);
}
#endif /* CONFIG_NUMA */
#endif /* _LINUX_SLAB_DEF_H */ #endif /* _LINUX_SLAB_DEF_H */
#ifndef __LINUX_SLOB_DEF_H
#define __LINUX_SLOB_DEF_H
#include <linux/numa.h>
void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
static __always_inline void *kmem_cache_alloc(struct kmem_cache *cachep,
gfp_t flags)
{
return kmem_cache_alloc_node(cachep, flags, NUMA_NO_NODE);
}
void *__kmalloc_node(size_t size, gfp_t flags, int node);
static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node)
{
return __kmalloc_node(size, flags, node);
}
static __always_inline void *kmalloc(size_t size, gfp_t flags)
{
return __kmalloc_node(size, flags, NUMA_NO_NODE);
}
static __always_inline void *__kmalloc(size_t size, gfp_t flags)
{
return kmalloc(size, flags);
}
#endif /* __LINUX_SLOB_DEF_H */
...@@ -6,14 +6,8 @@ ...@@ -6,14 +6,8 @@
* *
* (C) 2007 SGI, Christoph Lameter * (C) 2007 SGI, Christoph Lameter
*/ */
#include <linux/types.h>
#include <linux/gfp.h>
#include <linux/bug.h>
#include <linux/workqueue.h>
#include <linux/kobject.h> #include <linux/kobject.h>
#include <linux/kmemleak.h>
enum stat_item { enum stat_item {
ALLOC_FASTPATH, /* Allocation from cpu slab */ ALLOC_FASTPATH, /* Allocation from cpu slab */
ALLOC_SLOWPATH, /* Allocation by getting a new cpu slab */ ALLOC_SLOWPATH, /* Allocation by getting a new cpu slab */
...@@ -104,108 +98,4 @@ struct kmem_cache { ...@@ -104,108 +98,4 @@ struct kmem_cache {
struct kmem_cache_node *node[MAX_NUMNODES]; struct kmem_cache_node *node[MAX_NUMNODES];
}; };
void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
void *__kmalloc(size_t size, gfp_t flags);
static __always_inline void *
kmalloc_order(size_t size, gfp_t flags, unsigned int order)
{
void *ret;
flags |= (__GFP_COMP | __GFP_KMEMCG);
ret = (void *) __get_free_pages(flags, order);
kmemleak_alloc(ret, size, 1, flags);
return ret;
}
/**
* Calling this on allocated memory will check that the memory
* is expected to be in use, and print warnings if not.
*/
#ifdef CONFIG_SLUB_DEBUG
extern bool verify_mem_not_deleted(const void *x);
#else
static inline bool verify_mem_not_deleted(const void *x)
{
return true;
}
#endif
#ifdef CONFIG_TRACING
extern void *
kmem_cache_alloc_trace(struct kmem_cache *s, gfp_t gfpflags, size_t size);
extern void *kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order);
#else
static __always_inline void *
kmem_cache_alloc_trace(struct kmem_cache *s, gfp_t gfpflags, size_t size)
{
return kmem_cache_alloc(s, gfpflags);
}
static __always_inline void *
kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order)
{
return kmalloc_order(size, flags, order);
}
#endif
static __always_inline void *kmalloc_large(size_t size, gfp_t flags)
{
unsigned int order = get_order(size);
return kmalloc_order_trace(size, flags, order);
}
static __always_inline void *kmalloc(size_t size, gfp_t flags)
{
if (__builtin_constant_p(size)) {
if (size > KMALLOC_MAX_CACHE_SIZE)
return kmalloc_large(size, flags);
if (!(flags & GFP_DMA)) {
int index = kmalloc_index(size);
if (!index)
return ZERO_SIZE_PTR;
return kmem_cache_alloc_trace(kmalloc_caches[index],
flags, size);
}
}
return __kmalloc(size, flags);
}
#ifdef CONFIG_NUMA
void *__kmalloc_node(size_t size, gfp_t flags, int node);
void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
#ifdef CONFIG_TRACING
extern void *kmem_cache_alloc_node_trace(struct kmem_cache *s,
gfp_t gfpflags,
int node, size_t size);
#else
static __always_inline void *
kmem_cache_alloc_node_trace(struct kmem_cache *s,
gfp_t gfpflags,
int node, size_t size)
{
return kmem_cache_alloc_node(s, gfpflags, node);
}
#endif
static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node)
{
if (__builtin_constant_p(size) &&
size <= KMALLOC_MAX_CACHE_SIZE && !(flags & GFP_DMA)) {
int index = kmalloc_index(size);
if (!index)
return ZERO_SIZE_PTR;
return kmem_cache_alloc_node_trace(kmalloc_caches[index],
flags, node, size);
}
return __kmalloc_node(size, flags, node);
}
#endif
#endif /* _LINUX_SLUB_DEF_H */ #endif /* _LINUX_SLUB_DEF_H */
...@@ -1602,7 +1602,7 @@ endchoice ...@@ -1602,7 +1602,7 @@ endchoice
config SLUB_CPU_PARTIAL config SLUB_CPU_PARTIAL
default y default y
depends on SLUB depends on SLUB && SMP
bool "SLUB per cpu partial cache" bool "SLUB per cpu partial cache"
help help
Per cpu partial caches accellerate objects allocation and freeing Per cpu partial caches accellerate objects allocation and freeing
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
#include <asm/page.h> #include <asm/page.h>
#include <linux/memcontrol.h> #include <linux/memcontrol.h>
#include <trace/events/kmem.h>
#include "slab.h" #include "slab.h"
...@@ -373,7 +374,7 @@ struct kmem_cache *kmalloc_slab(size_t size, gfp_t flags) ...@@ -373,7 +374,7 @@ struct kmem_cache *kmalloc_slab(size_t size, gfp_t flags)
{ {
int index; int index;
if (size > KMALLOC_MAX_SIZE) { if (unlikely(size > KMALLOC_MAX_SIZE)) {
WARN_ON_ONCE(!(flags & __GFP_NOWARN)); WARN_ON_ONCE(!(flags & __GFP_NOWARN));
return NULL; return NULL;
} }
...@@ -495,6 +496,15 @@ void __init create_kmalloc_caches(unsigned long flags) ...@@ -495,6 +496,15 @@ void __init create_kmalloc_caches(unsigned long flags)
} }
#endif /* !CONFIG_SLOB */ #endif /* !CONFIG_SLOB */
#ifdef CONFIG_TRACING
void *kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order)
{
void *ret = kmalloc_order(size, flags, order);
trace_kmalloc(_RET_IP_, ret, size, PAGE_SIZE << order, flags);
return ret;
}
EXPORT_SYMBOL(kmalloc_order_trace);
#endif
#ifdef CONFIG_SLABINFO #ifdef CONFIG_SLABINFO
......
...@@ -462,11 +462,11 @@ __do_kmalloc_node(size_t size, gfp_t gfp, int node, unsigned long caller) ...@@ -462,11 +462,11 @@ __do_kmalloc_node(size_t size, gfp_t gfp, int node, unsigned long caller)
return ret; return ret;
} }
void *__kmalloc_node(size_t size, gfp_t gfp, int node) void *__kmalloc(size_t size, gfp_t gfp)
{ {
return __do_kmalloc_node(size, gfp, node, _RET_IP_); return __do_kmalloc_node(size, gfp, NUMA_NO_NODE, _RET_IP_);
} }
EXPORT_SYMBOL(__kmalloc_node); EXPORT_SYMBOL(__kmalloc);
#ifdef CONFIG_TRACING #ifdef CONFIG_TRACING
void *__kmalloc_track_caller(size_t size, gfp_t gfp, unsigned long caller) void *__kmalloc_track_caller(size_t size, gfp_t gfp, unsigned long caller)
...@@ -534,7 +534,7 @@ int __kmem_cache_create(struct kmem_cache *c, unsigned long flags) ...@@ -534,7 +534,7 @@ int __kmem_cache_create(struct kmem_cache *c, unsigned long flags)
return 0; return 0;
} }
void *kmem_cache_alloc_node(struct kmem_cache *c, gfp_t flags, int node) void *slob_alloc_node(struct kmem_cache *c, gfp_t flags, int node)
{ {
void *b; void *b;
...@@ -560,7 +560,27 @@ void *kmem_cache_alloc_node(struct kmem_cache *c, gfp_t flags, int node) ...@@ -560,7 +560,27 @@ void *kmem_cache_alloc_node(struct kmem_cache *c, gfp_t flags, int node)
kmemleak_alloc_recursive(b, c->size, 1, c->flags, flags); kmemleak_alloc_recursive(b, c->size, 1, c->flags, flags);
return b; return b;
} }
EXPORT_SYMBOL(slob_alloc_node);
void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags)
{
return slob_alloc_node(cachep, flags, NUMA_NO_NODE);
}
EXPORT_SYMBOL(kmem_cache_alloc);
#ifdef CONFIG_NUMA
void *__kmalloc_node(size_t size, gfp_t gfp, int node)
{
return __do_kmalloc_node(size, gfp, node, _RET_IP_);
}
EXPORT_SYMBOL(__kmalloc_node);
void *kmem_cache_alloc_node(struct kmem_cache *cachep, gfp_t gfp, int node)
{
return slob_alloc_node(cachep, gfp, node);
}
EXPORT_SYMBOL(kmem_cache_alloc_node); EXPORT_SYMBOL(kmem_cache_alloc_node);
#endif
static void __kmem_cache_free(void *b, int size) static void __kmem_cache_free(void *b, int size)
{ {
......
...@@ -373,7 +373,8 @@ static inline bool __cmpxchg_double_slab(struct kmem_cache *s, struct page *page ...@@ -373,7 +373,8 @@ static inline bool __cmpxchg_double_slab(struct kmem_cache *s, struct page *page
#endif #endif
{ {
slab_lock(page); slab_lock(page);
if (page->freelist == freelist_old && page->counters == counters_old) { if (page->freelist == freelist_old &&
page->counters == counters_old) {
page->freelist = freelist_new; page->freelist = freelist_new;
page->counters = counters_new; page->counters = counters_new;
slab_unlock(page); slab_unlock(page);
...@@ -411,7 +412,8 @@ static inline bool cmpxchg_double_slab(struct kmem_cache *s, struct page *page, ...@@ -411,7 +412,8 @@ static inline bool cmpxchg_double_slab(struct kmem_cache *s, struct page *page,
local_irq_save(flags); local_irq_save(flags);
slab_lock(page); slab_lock(page);
if (page->freelist == freelist_old && page->counters == counters_old) { if (page->freelist == freelist_old &&
page->counters == counters_old) {
page->freelist = freelist_new; page->freelist = freelist_new;
page->counters = counters_new; page->counters = counters_new;
slab_unlock(page); slab_unlock(page);
...@@ -553,7 +555,8 @@ static void print_tracking(struct kmem_cache *s, void *object) ...@@ -553,7 +555,8 @@ static void print_tracking(struct kmem_cache *s, void *object)
static void print_page_info(struct page *page) static void print_page_info(struct page *page)
{ {
printk(KERN_ERR "INFO: Slab 0x%p objects=%u used=%u fp=0x%p flags=0x%04lx\n", printk(KERN_ERR
"INFO: Slab 0x%p objects=%u used=%u fp=0x%p flags=0x%04lx\n",
page, page->objects, page->inuse, page->freelist, page->flags); page, page->objects, page->inuse, page->freelist, page->flags);
} }
...@@ -629,7 +632,8 @@ static void object_err(struct kmem_cache *s, struct page *page, ...@@ -629,7 +632,8 @@ static void object_err(struct kmem_cache *s, struct page *page,
print_trailer(s, page, object); print_trailer(s, page, object);
} }
static void slab_err(struct kmem_cache *s, struct page *page, const char *fmt, ...) static void slab_err(struct kmem_cache *s, struct page *page,
const char *fmt, ...)
{ {
va_list args; va_list args;
char buf[100]; char buf[100];
...@@ -788,7 +792,8 @@ static int check_object(struct kmem_cache *s, struct page *page, ...@@ -788,7 +792,8 @@ static int check_object(struct kmem_cache *s, struct page *page,
} else { } else {
if ((s->flags & SLAB_POISON) && s->object_size < s->inuse) { if ((s->flags & SLAB_POISON) && s->object_size < s->inuse) {
check_bytes_and_report(s, page, p, "Alignment padding", check_bytes_and_report(s, page, p, "Alignment padding",
endobject, POISON_INUSE, s->inuse - s->object_size); endobject, POISON_INUSE,
s->inuse - s->object_size);
} }
} }
...@@ -873,7 +878,6 @@ static int on_freelist(struct kmem_cache *s, struct page *page, void *search) ...@@ -873,7 +878,6 @@ static int on_freelist(struct kmem_cache *s, struct page *page, void *search)
object_err(s, page, object, object_err(s, page, object,
"Freechain corrupt"); "Freechain corrupt");
set_freepointer(s, object, NULL); set_freepointer(s, object, NULL);
break;
} else { } else {
slab_err(s, page, "Freepointer corrupt"); slab_err(s, page, "Freepointer corrupt");
page->freelist = NULL; page->freelist = NULL;
...@@ -918,7 +922,8 @@ static void trace(struct kmem_cache *s, struct page *page, void *object, ...@@ -918,7 +922,8 @@ static void trace(struct kmem_cache *s, struct page *page, void *object,
page->freelist); page->freelist);
if (!alloc) if (!alloc)
print_section("Object ", (void *)object, s->object_size); print_section("Object ", (void *)object,
s->object_size);
dump_stack(); dump_stack();
} }
...@@ -937,7 +942,8 @@ static inline int slab_pre_alloc_hook(struct kmem_cache *s, gfp_t flags) ...@@ -937,7 +942,8 @@ static inline int slab_pre_alloc_hook(struct kmem_cache *s, gfp_t flags)
return should_failslab(s->object_size, flags, s->flags); return should_failslab(s->object_size, flags, s->flags);
} }
static inline void slab_post_alloc_hook(struct kmem_cache *s, gfp_t flags, void *object) static inline void slab_post_alloc_hook(struct kmem_cache *s,
gfp_t flags, void *object)
{ {
flags &= gfp_allowed_mask; flags &= gfp_allowed_mask;
kmemcheck_slab_alloc(s, flags, object, slab_ksize(s)); kmemcheck_slab_alloc(s, flags, object, slab_ksize(s));
...@@ -1039,7 +1045,8 @@ static void setup_object_debug(struct kmem_cache *s, struct page *page, ...@@ -1039,7 +1045,8 @@ static void setup_object_debug(struct kmem_cache *s, struct page *page,
init_tracking(s, object); init_tracking(s, object);
} }
static noinline int alloc_debug_processing(struct kmem_cache *s, struct page *page, static noinline int alloc_debug_processing(struct kmem_cache *s,
struct page *page,
void *object, unsigned long addr) void *object, unsigned long addr)
{ {
if (!check_slab(s, page)) if (!check_slab(s, page))
...@@ -1743,7 +1750,8 @@ static void init_kmem_cache_cpus(struct kmem_cache *s) ...@@ -1743,7 +1750,8 @@ static void init_kmem_cache_cpus(struct kmem_cache *s)
/* /*
* Remove the cpu slab * Remove the cpu slab
*/ */
static void deactivate_slab(struct kmem_cache *s, struct page *page, void *freelist) static void deactivate_slab(struct kmem_cache *s, struct page *page,
void *freelist)
{ {
enum slab_modes { M_NONE, M_PARTIAL, M_FULL, M_FREE }; enum slab_modes { M_NONE, M_PARTIAL, M_FULL, M_FREE };
struct kmem_cache_node *n = get_node(s, page_to_nid(page)); struct kmem_cache_node *n = get_node(s, page_to_nid(page));
...@@ -1999,7 +2007,8 @@ static void put_cpu_partial(struct kmem_cache *s, struct page *page, int drain) ...@@ -1999,7 +2007,8 @@ static void put_cpu_partial(struct kmem_cache *s, struct page *page, int drain)
page->pobjects = pobjects; page->pobjects = pobjects;
page->next = oldpage; page->next = oldpage;
} while (this_cpu_cmpxchg(s->cpu_slab->partial, oldpage, page) != oldpage); } while (this_cpu_cmpxchg(s->cpu_slab->partial, oldpage, page)
!= oldpage);
#endif #endif
} }
...@@ -2169,8 +2178,8 @@ static inline bool pfmemalloc_match(struct page *page, gfp_t gfpflags) ...@@ -2169,8 +2178,8 @@ static inline bool pfmemalloc_match(struct page *page, gfp_t gfpflags)
} }
/* /*
* Check the page->freelist of a page and either transfer the freelist to the per cpu freelist * Check the page->freelist of a page and either transfer the freelist to the
* or deactivate the page. * per cpu freelist or deactivate the page.
* *
* The page is still frozen if the return value is not NULL. * The page is still frozen if the return value is not NULL.
* *
...@@ -2314,7 +2323,8 @@ static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node, ...@@ -2314,7 +2323,8 @@ static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
goto load_freelist; goto load_freelist;
/* Only entered in the debug case */ /* Only entered in the debug case */
if (kmem_cache_debug(s) && !alloc_debug_processing(s, page, freelist, addr)) if (kmem_cache_debug(s) &&
!alloc_debug_processing(s, page, freelist, addr))
goto new_slab; /* Slab failed checks. Next slab needed */ goto new_slab; /* Slab failed checks. Next slab needed */
deactivate_slab(s, page, get_freepointer(s, freelist)); deactivate_slab(s, page, get_freepointer(s, freelist));
...@@ -2372,7 +2382,7 @@ static __always_inline void *slab_alloc_node(struct kmem_cache *s, ...@@ -2372,7 +2382,7 @@ static __always_inline void *slab_alloc_node(struct kmem_cache *s,
object = c->freelist; object = c->freelist;
page = c->page; page = c->page;
if (unlikely(!object || !page || !node_match(page, node))) if (unlikely(!object || !node_match(page, node)))
object = __slab_alloc(s, gfpflags, node, addr, c); object = __slab_alloc(s, gfpflags, node, addr, c);
else { else {
...@@ -2382,13 +2392,15 @@ static __always_inline void *slab_alloc_node(struct kmem_cache *s, ...@@ -2382,13 +2392,15 @@ static __always_inline void *slab_alloc_node(struct kmem_cache *s,
* The cmpxchg will only match if there was no additional * The cmpxchg will only match if there was no additional
* operation and if we are on the right processor. * operation and if we are on the right processor.
* *
* The cmpxchg does the following atomically (without lock semantics!) * The cmpxchg does the following atomically (without lock
* semantics!)
* 1. Relocate first pointer to the current per cpu area. * 1. Relocate first pointer to the current per cpu area.
* 2. Verify that tid and freelist have not been changed * 2. Verify that tid and freelist have not been changed
* 3. If they were not changed replace tid and freelist * 3. If they were not changed replace tid and freelist
* *
* Since this is without lock semantics the protection is only against * Since this is without lock semantics the protection is only
* code executing on this cpu *not* from access by other cpus. * against code executing on this cpu *not* from access by
* other cpus.
*/ */
if (unlikely(!this_cpu_cmpxchg_double( if (unlikely(!this_cpu_cmpxchg_double(
s->cpu_slab->freelist, s->cpu_slab->tid, s->cpu_slab->freelist, s->cpu_slab->tid,
...@@ -2420,7 +2432,8 @@ void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags) ...@@ -2420,7 +2432,8 @@ void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags)
{ {
void *ret = slab_alloc(s, gfpflags, _RET_IP_); void *ret = slab_alloc(s, gfpflags, _RET_IP_);
trace_kmem_cache_alloc(_RET_IP_, ret, s->object_size, s->size, gfpflags); trace_kmem_cache_alloc(_RET_IP_, ret, s->object_size,
s->size, gfpflags);
return ret; return ret;
} }
...@@ -2434,14 +2447,6 @@ void *kmem_cache_alloc_trace(struct kmem_cache *s, gfp_t gfpflags, size_t size) ...@@ -2434,14 +2447,6 @@ void *kmem_cache_alloc_trace(struct kmem_cache *s, gfp_t gfpflags, size_t size)
return ret; return ret;
} }
EXPORT_SYMBOL(kmem_cache_alloc_trace); EXPORT_SYMBOL(kmem_cache_alloc_trace);
void *kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order)
{
void *ret = kmalloc_order(size, flags, order);
trace_kmalloc(_RET_IP_, ret, size, PAGE_SIZE << order, flags);
return ret;
}
EXPORT_SYMBOL(kmalloc_order_trace);
#endif #endif
#ifdef CONFIG_NUMA #ifdef CONFIG_NUMA
...@@ -2512,8 +2517,10 @@ static void __slab_free(struct kmem_cache *s, struct page *page, ...@@ -2512,8 +2517,10 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
if (kmem_cache_has_cpu_partial(s) && !prior) if (kmem_cache_has_cpu_partial(s) && !prior)
/* /*
* Slab was on no list before and will be partially empty * Slab was on no list before and will be
* We can defer the list move and instead freeze it. * partially empty
* We can defer the list move and instead
* freeze it.
*/ */
new.frozen = 1; new.frozen = 1;
...@@ -3071,8 +3078,8 @@ static int kmem_cache_open(struct kmem_cache *s, unsigned long flags) ...@@ -3071,8 +3078,8 @@ static int kmem_cache_open(struct kmem_cache *s, unsigned long flags)
* A) The number of objects from per cpu partial slabs dumped to the * A) The number of objects from per cpu partial slabs dumped to the
* per node list when we reach the limit. * per node list when we reach the limit.
* B) The number of objects in cpu partial slabs to extract from the * B) The number of objects in cpu partial slabs to extract from the
* per node list when we run out of per cpu objects. We only fetch 50% * per node list when we run out of per cpu objects. We only fetch
* to keep some capacity around for frees. * 50% to keep some capacity around for frees.
*/ */
if (!kmem_cache_has_cpu_partial(s)) if (!kmem_cache_has_cpu_partial(s))
s->cpu_partial = 0; s->cpu_partial = 0;
...@@ -3099,8 +3106,8 @@ static int kmem_cache_open(struct kmem_cache *s, unsigned long flags) ...@@ -3099,8 +3106,8 @@ static int kmem_cache_open(struct kmem_cache *s, unsigned long flags)
if (flags & SLAB_PANIC) if (flags & SLAB_PANIC)
panic("Cannot create slab %s size=%lu realsize=%u " panic("Cannot create slab %s size=%lu realsize=%u "
"order=%u offset=%u flags=%lx\n", "order=%u offset=%u flags=%lx\n",
s->name, (unsigned long)s->size, s->size, oo_order(s->oo), s->name, (unsigned long)s->size, s->size,
s->offset, flags); oo_order(s->oo), s->offset, flags);
return -EINVAL; return -EINVAL;
} }
...@@ -3316,42 +3323,6 @@ size_t ksize(const void *object) ...@@ -3316,42 +3323,6 @@ size_t ksize(const void *object)
} }
EXPORT_SYMBOL(ksize); EXPORT_SYMBOL(ksize);
#ifdef CONFIG_SLUB_DEBUG
bool verify_mem_not_deleted(const void *x)
{
struct page *page;
void *object = (void *)x;
unsigned long flags;
bool rv;
if (unlikely(ZERO_OR_NULL_PTR(x)))
return false;
local_irq_save(flags);
page = virt_to_head_page(x);
if (unlikely(!PageSlab(page))) {
/* maybe it was from stack? */
rv = true;
goto out_unlock;
}
slab_lock(page);
if (on_freelist(page->slab_cache, page, object)) {
object_err(page->slab_cache, page, object, "Object is on free-list");
rv = false;
} else {
rv = true;
}
slab_unlock(page);
out_unlock:
local_irq_restore(flags);
return rv;
}
EXPORT_SYMBOL(verify_mem_not_deleted);
#endif
void kfree(const void *x) void kfree(const void *x)
{ {
struct page *page; struct page *page;
...@@ -4162,14 +4133,16 @@ static int list_locations(struct kmem_cache *s, char *buf, ...@@ -4162,14 +4133,16 @@ static int list_locations(struct kmem_cache *s, char *buf,
!cpumask_empty(to_cpumask(l->cpus)) && !cpumask_empty(to_cpumask(l->cpus)) &&
len < PAGE_SIZE - 60) { len < PAGE_SIZE - 60) {
len += sprintf(buf + len, " cpus="); len += sprintf(buf + len, " cpus=");
len += cpulist_scnprintf(buf + len, PAGE_SIZE - len - 50, len += cpulist_scnprintf(buf + len,
PAGE_SIZE - len - 50,
to_cpumask(l->cpus)); to_cpumask(l->cpus));
} }
if (nr_online_nodes > 1 && !nodes_empty(l->nodes) && if (nr_online_nodes > 1 && !nodes_empty(l->nodes) &&
len < PAGE_SIZE - 60) { len < PAGE_SIZE - 60) {
len += sprintf(buf + len, " nodes="); len += sprintf(buf + len, " nodes=");
len += nodelist_scnprintf(buf + len, PAGE_SIZE - len - 50, len += nodelist_scnprintf(buf + len,
PAGE_SIZE - len - 50,
l->nodes); l->nodes);
} }
...@@ -4268,18 +4241,17 @@ static ssize_t show_slab_objects(struct kmem_cache *s, ...@@ -4268,18 +4241,17 @@ static ssize_t show_slab_objects(struct kmem_cache *s,
int node; int node;
int x; int x;
unsigned long *nodes; unsigned long *nodes;
unsigned long *per_cpu;
nodes = kzalloc(2 * sizeof(unsigned long) * nr_node_ids, GFP_KERNEL); nodes = kzalloc(sizeof(unsigned long) * nr_node_ids, GFP_KERNEL);
if (!nodes) if (!nodes)
return -ENOMEM; return -ENOMEM;
per_cpu = nodes + nr_node_ids;
if (flags & SO_CPU) { if (flags & SO_CPU) {
int cpu; int cpu;
for_each_possible_cpu(cpu) { for_each_possible_cpu(cpu) {
struct kmem_cache_cpu *c = per_cpu_ptr(s->cpu_slab, cpu); struct kmem_cache_cpu *c = per_cpu_ptr(s->cpu_slab,
cpu);
int node; int node;
struct page *page; struct page *page;
...@@ -4304,8 +4276,6 @@ static ssize_t show_slab_objects(struct kmem_cache *s, ...@@ -4304,8 +4276,6 @@ static ssize_t show_slab_objects(struct kmem_cache *s,
total += x; total += x;
nodes[node] += x; nodes[node] += x;
} }
per_cpu[node]++;
} }
} }
...@@ -4320,7 +4290,6 @@ static ssize_t show_slab_objects(struct kmem_cache *s, ...@@ -4320,7 +4290,6 @@ static ssize_t show_slab_objects(struct kmem_cache *s,
else if (flags & SO_OBJECTS) else if (flags & SO_OBJECTS)
x = atomic_long_read(&n->total_objects) - x = atomic_long_read(&n->total_objects) -
count_partial(n, count_free); count_partial(n, count_free);
else else
x = atomic_long_read(&n->nr_slabs); x = atomic_long_read(&n->nr_slabs);
total += x; total += x;
...@@ -5136,7 +5105,8 @@ static char *create_unique_id(struct kmem_cache *s) ...@@ -5136,7 +5105,8 @@ static char *create_unique_id(struct kmem_cache *s)
#ifdef CONFIG_MEMCG_KMEM #ifdef CONFIG_MEMCG_KMEM
if (!is_root_cache(s)) if (!is_root_cache(s))
p += sprintf(p, "-%08d", memcg_cache_id(s->memcg_params->memcg)); p += sprintf(p, "-%08d",
memcg_cache_id(s->memcg_params->memcg));
#endif #endif
BUG_ON(p > name + ID_STR_LENGTH - 1); BUG_ON(p > name + ID_STR_LENGTH - 1);
......
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