Skip to content

Commit

Permalink
mm/slab: make criteria for off slab determination robust and simple
Browse files Browse the repository at this point in the history
To become an off slab, there are some constraints to avoid bootstrapping
problem and recursive call.  This can be avoided differently by simply
checking that corresponding kmalloc cache is ready and it's not a off
slab.  It would be more robust because static size checking can be
affected by cache size change or architecture type but dynamic checking
isn't.

One check 'freelist_cache->size > cachep->size / 2' is added to check
benefit of choosing off slab, because, now, there is no size constraint
which ensures enough advantage when selecting off slab.

Signed-off-by: Joonsoo Kim <[email protected]>
Cc: Christoph Lameter <[email protected]>
Cc: Pekka Enberg <[email protected]>
Cc: David Rientjes <[email protected]>
Cc: Joonsoo Kim <[email protected]>
Cc: Jesper Dangaard Brouer <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
JoonsooKim authored and torvalds committed Mar 15, 2016
1 parent f3a3c32 commit 3217fd9
Showing 1 changed file with 17 additions and 28 deletions.
45 changes: 17 additions & 28 deletions mm/slab.c
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,6 @@ static void kmem_cache_node_init(struct kmem_cache_node *parent)

#define CFLGS_OFF_SLAB (0x80000000UL)
#define OFF_SLAB(x) ((x)->flags & CFLGS_OFF_SLAB)
#define OFF_SLAB_MIN_SIZE (max_t(size_t, PAGE_SIZE >> 5, KMALLOC_MIN_SIZE + 1))

#define BATCHREFILL_LIMIT 16
/*
Expand Down Expand Up @@ -1879,7 +1878,6 @@ static void slabs_destroy(struct kmem_cache *cachep, struct list_head *list)
static size_t calculate_slab_order(struct kmem_cache *cachep,
size_t size, unsigned long flags)
{
unsigned long offslab_limit;
size_t left_over = 0;
int gfporder;

Expand All @@ -1896,16 +1894,24 @@ static size_t calculate_slab_order(struct kmem_cache *cachep,
break;

if (flags & CFLGS_OFF_SLAB) {
struct kmem_cache *freelist_cache;
size_t freelist_size;

freelist_size = num * sizeof(freelist_idx_t);
freelist_cache = kmalloc_slab(freelist_size, 0u);
if (!freelist_cache)
continue;

/*
* Max number of objs-per-slab for caches which
* use off-slab slabs. Needed to avoid a possible
* looping condition in cache_grow().
* Needed to avoid possible looping condition
* in cache_grow()
*/
offslab_limit = size;
offslab_limit /= sizeof(freelist_idx_t);
if (OFF_SLAB(freelist_cache))
continue;

if (num > offslab_limit)
break;
/* check if off slab has enough benefit */
if (freelist_cache->size > cachep->size / 2)
continue;
}

/* Found something acceptable - save it away */
Expand Down Expand Up @@ -2031,17 +2037,9 @@ static bool set_off_slab_cache(struct kmem_cache *cachep,
cachep->num = 0;

/*
* Determine if the slab management is 'on' or 'off' slab.
* (bootstrapping cannot cope with offslab caches so don't do
* it too early on. Always use on-slab management when
* SLAB_NOLEAKTRACE to avoid recursive calls into kmemleak)
* Always use on-slab management when SLAB_NOLEAKTRACE
* to avoid recursive calls into kmemleak.
*/
if (size < OFF_SLAB_MIN_SIZE)
return false;

if (slab_early_init)
return false;

if (flags & SLAB_NOLEAKTRACE)
return false;

Expand Down Expand Up @@ -2205,7 +2203,6 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags)
* sized slab is initialized in current slab initialization sequence.
*/
if (debug_pagealloc_enabled() && (flags & SLAB_POISON) &&
!slab_early_init && size >= kmalloc_size(INDEX_NODE) &&
size >= 256 && cachep->object_size > cache_line_size()) {
if (size < PAGE_SIZE || size % PAGE_SIZE == 0) {
size_t tmp_size = ALIGN(size, PAGE_SIZE);
Expand Down Expand Up @@ -2254,14 +2251,6 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags)
if (OFF_SLAB(cachep)) {
cachep->freelist_cache =
kmalloc_slab(cachep->freelist_size, 0u);
/*
* This is a possibility for one of the kmalloc_{dma,}_caches.
* But since we go off slab only for object size greater than
* OFF_SLAB_MIN_SIZE, and kmalloc_{dma,}_caches get created
* in ascending order,this should not happen at all.
* But leave a BUG_ON for some lucky dude.
*/
BUG_ON(ZERO_OR_NULL_PTR(cachep->freelist_cache));
}

err = setup_cpu_cache(cachep, gfp);
Expand Down

0 comments on commit 3217fd9

Please sign in to comment.