Skip to content

Commit b1cb098

Browse files
JoonsooKimpenberg
authored andcommitted
slab: change the management method of free objects of the slab
Current free objects management method of the slab is weird, because it touch random position of the array of kmem_bufctl_t when we try to get free object. See following example. struct slab's free = 6 kmem_bufctl_t array: 1 END 5 7 0 4 3 2 To get free objects, we access this array with following pattern. 6 -> 3 -> 7 -> 2 -> 5 -> 4 -> 0 -> 1 -> END If we have many objects, this array would be larger and be not in the same cache line. It is not good for performance. We can do same thing through more easy way, like as the stack. Only thing we have to do is to maintain stack top to free object. I use free field of struct slab for this purpose. After that, if we need to get an object, we can get it at stack top and manipulate top pointer. That's all. This method already used in array_cache management. Following is an access pattern when we use this method. struct slab's free = 0 kmem_bufctl_t array: 6 3 7 2 5 4 0 1 To get free objects, we access this array with following pattern. 0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 This may help cache line footprint if slab has many objects, and, in addition, this makes code much much simpler. Acked-by: Andi Kleen <[email protected]> Signed-off-by: Joonsoo Kim <[email protected]> Signed-off-by: Pekka Enberg <[email protected]>
1 parent a57a498 commit b1cb098

File tree

1 file changed

+30
-64
lines changed

1 file changed

+30
-64
lines changed

mm/slab.c

Lines changed: 30 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -183,9 +183,6 @@ static bool pfmemalloc_active __read_mostly;
183183
*/
184184

185185
typedef unsigned int kmem_bufctl_t;
186-
#define BUFCTL_END (((kmem_bufctl_t)(~0U))-0)
187-
#define BUFCTL_FREE (((kmem_bufctl_t)(~0U))-1)
188-
#define BUFCTL_ACTIVE (((kmem_bufctl_t)(~0U))-2)
189186
#define SLAB_LIMIT (((kmem_bufctl_t)(~0U))-3)
190187

191188
/*
@@ -2653,9 +2650,8 @@ static void cache_init_objs(struct kmem_cache *cachep,
26532650
if (cachep->ctor)
26542651
cachep->ctor(objp);
26552652
#endif
2656-
slab_bufctl(slabp)[i] = i + 1;
2653+
slab_bufctl(slabp)[i] = i;
26572654
}
2658-
slab_bufctl(slabp)[i - 1] = BUFCTL_END;
26592655
}
26602656

26612657
static void kmem_flagcheck(struct kmem_cache *cachep, gfp_t flags)
@@ -2671,16 +2667,14 @@ static void kmem_flagcheck(struct kmem_cache *cachep, gfp_t flags)
26712667
static void *slab_get_obj(struct kmem_cache *cachep, struct slab *slabp,
26722668
int nodeid)
26732669
{
2674-
void *objp = index_to_obj(cachep, slabp, slabp->free);
2675-
kmem_bufctl_t next;
2670+
void *objp;
26762671

26772672
slabp->inuse++;
2678-
next = slab_bufctl(slabp)[slabp->free];
2673+
objp = index_to_obj(cachep, slabp, slab_bufctl(slabp)[slabp->free]);
26792674
#if DEBUG
2680-
slab_bufctl(slabp)[slabp->free] = BUFCTL_FREE;
26812675
WARN_ON(page_to_nid(virt_to_page(objp)) != nodeid);
26822676
#endif
2683-
slabp->free = next;
2677+
slabp->free++;
26842678

26852679
return objp;
26862680
}
@@ -2689,19 +2683,23 @@ static void slab_put_obj(struct kmem_cache *cachep, struct slab *slabp,
26892683
void *objp, int nodeid)
26902684
{
26912685
unsigned int objnr = obj_to_index(cachep, slabp, objp);
2692-
26932686
#if DEBUG
2687+
kmem_bufctl_t i;
2688+
26942689
/* Verify that the slab belongs to the intended node */
26952690
WARN_ON(page_to_nid(virt_to_page(objp)) != nodeid);
26962691

2697-
if (slab_bufctl(slabp)[objnr] + 1 <= SLAB_LIMIT + 1) {
2698-
printk(KERN_ERR "slab: double free detected in cache "
2699-
"'%s', objp %p\n", cachep->name, objp);
2700-
BUG();
2692+
/* Verify double free bug */
2693+
for (i = slabp->free; i < cachep->num; i++) {
2694+
if (slab_bufctl(slabp)[i] == objnr) {
2695+
printk(KERN_ERR "slab: double free detected in cache "
2696+
"'%s', objp %p\n", cachep->name, objp);
2697+
BUG();
2698+
}
27012699
}
27022700
#endif
2703-
slab_bufctl(slabp)[objnr] = slabp->free;
2704-
slabp->free = objnr;
2701+
slabp->free--;
2702+
slab_bufctl(slabp)[slabp->free] = objnr;
27052703
slabp->inuse--;
27062704
}
27072705

@@ -2862,9 +2860,6 @@ static void *cache_free_debugcheck(struct kmem_cache *cachep, void *objp,
28622860
BUG_ON(objnr >= cachep->num);
28632861
BUG_ON(objp != index_to_obj(cachep, slabp, objnr));
28642862

2865-
#ifdef CONFIG_DEBUG_SLAB_LEAK
2866-
slab_bufctl(slabp)[objnr] = BUFCTL_FREE;
2867-
#endif
28682863
if (cachep->flags & SLAB_POISON) {
28692864
#ifdef CONFIG_DEBUG_PAGEALLOC
28702865
if ((cachep->size % PAGE_SIZE)==0 && OFF_SLAB(cachep)) {
@@ -2881,33 +2876,9 @@ static void *cache_free_debugcheck(struct kmem_cache *cachep, void *objp,
28812876
return objp;
28822877
}
28832878

2884-
static void check_slabp(struct kmem_cache *cachep, struct slab *slabp)
2885-
{
2886-
kmem_bufctl_t i;
2887-
int entries = 0;
2888-
2889-
/* Check slab's freelist to see if this obj is there. */
2890-
for (i = slabp->free; i != BUFCTL_END; i = slab_bufctl(slabp)[i]) {
2891-
entries++;
2892-
if (entries > cachep->num || i >= cachep->num)
2893-
goto bad;
2894-
}
2895-
if (entries != cachep->num - slabp->inuse) {
2896-
bad:
2897-
printk(KERN_ERR "slab: Internal list corruption detected in "
2898-
"cache '%s'(%d), slabp %p(%d). Tainted(%s). Hexdump:\n",
2899-
cachep->name, cachep->num, slabp, slabp->inuse,
2900-
print_tainted());
2901-
print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 16, 1, slabp,
2902-
sizeof(*slabp) + cachep->num * sizeof(kmem_bufctl_t),
2903-
1);
2904-
BUG();
2905-
}
2906-
}
29072879
#else
29082880
#define kfree_debugcheck(x) do { } while(0)
29092881
#define cache_free_debugcheck(x,objp,z) (objp)
2910-
#define check_slabp(x,y) do { } while(0)
29112882
#endif
29122883

29132884
static void *cache_alloc_refill(struct kmem_cache *cachep, gfp_t flags,
@@ -2957,7 +2928,6 @@ static void *cache_alloc_refill(struct kmem_cache *cachep, gfp_t flags,
29572928
}
29582929

29592930
slabp = list_entry(entry, struct slab, list);
2960-
check_slabp(cachep, slabp);
29612931
check_spinlock_acquired(cachep);
29622932

29632933
/*
@@ -2975,11 +2945,10 @@ static void *cache_alloc_refill(struct kmem_cache *cachep, gfp_t flags,
29752945
ac_put_obj(cachep, ac, slab_get_obj(cachep, slabp,
29762946
node));
29772947
}
2978-
check_slabp(cachep, slabp);
29792948

29802949
/* move slabp to correct slabp list: */
29812950
list_del(&slabp->list);
2982-
if (slabp->free == BUFCTL_END)
2951+
if (slabp->free == cachep->num)
29832952
list_add(&slabp->list, &n->slabs_full);
29842953
else
29852954
list_add(&slabp->list, &n->slabs_partial);
@@ -3054,16 +3023,6 @@ static void *cache_alloc_debugcheck_after(struct kmem_cache *cachep,
30543023
*dbg_redzone1(cachep, objp) = RED_ACTIVE;
30553024
*dbg_redzone2(cachep, objp) = RED_ACTIVE;
30563025
}
3057-
#ifdef CONFIG_DEBUG_SLAB_LEAK
3058-
{
3059-
struct slab *slabp;
3060-
unsigned objnr;
3061-
3062-
slabp = virt_to_slab(objp);
3063-
objnr = (unsigned)(objp - slabp->s_mem) / cachep->size;
3064-
slab_bufctl(slabp)[objnr] = BUFCTL_ACTIVE;
3065-
}
3066-
#endif
30673026
objp += obj_offset(cachep);
30683027
if (cachep->ctor && cachep->flags & SLAB_POISON)
30693028
cachep->ctor(objp);
@@ -3269,7 +3228,6 @@ static void *____cache_alloc_node(struct kmem_cache *cachep, gfp_t flags,
32693228

32703229
slabp = list_entry(entry, struct slab, list);
32713230
check_spinlock_acquired_node(cachep, nodeid);
3272-
check_slabp(cachep, slabp);
32733231

32743232
STATS_INC_NODEALLOCS(cachep);
32753233
STATS_INC_ACTIVE(cachep);
@@ -3278,12 +3236,11 @@ static void *____cache_alloc_node(struct kmem_cache *cachep, gfp_t flags,
32783236
BUG_ON(slabp->inuse == cachep->num);
32793237

32803238
obj = slab_get_obj(cachep, slabp, nodeid);
3281-
check_slabp(cachep, slabp);
32823239
n->free_objects--;
32833240
/* move slabp to correct slabp list: */
32843241
list_del(&slabp->list);
32853242

3286-
if (slabp->free == BUFCTL_END)
3243+
if (slabp->free == cachep->num)
32873244
list_add(&slabp->list, &n->slabs_full);
32883245
else
32893246
list_add(&slabp->list, &n->slabs_partial);
@@ -3445,11 +3402,9 @@ static void free_block(struct kmem_cache *cachep, void **objpp, int nr_objects,
34453402
n = cachep->node[node];
34463403
list_del(&slabp->list);
34473404
check_spinlock_acquired_node(cachep, node);
3448-
check_slabp(cachep, slabp);
34493405
slab_put_obj(cachep, slabp, objp, node);
34503406
STATS_DEC_ACTIVE(cachep);
34513407
n->free_objects++;
3452-
check_slabp(cachep, slabp);
34533408

34543409
/* fixup slab chains */
34553410
if (slabp->inuse == 0) {
@@ -4308,12 +4263,23 @@ static inline int add_caller(unsigned long *n, unsigned long v)
43084263
static void handle_slab(unsigned long *n, struct kmem_cache *c, struct slab *s)
43094264
{
43104265
void *p;
4311-
int i;
4266+
int i, j;
4267+
43124268
if (n[0] == n[1])
43134269
return;
43144270
for (i = 0, p = s->s_mem; i < c->num; i++, p += c->size) {
4315-
if (slab_bufctl(s)[i] != BUFCTL_ACTIVE)
4271+
bool active = true;
4272+
4273+
for (j = s->free; j < c->num; j++) {
4274+
/* Skip freed item */
4275+
if (slab_bufctl(s)[j] == i) {
4276+
active = false;
4277+
break;
4278+
}
4279+
}
4280+
if (!active)
43164281
continue;
4282+
43174283
if (!add_caller(n, (unsigned long)*dbg_userword(c, p)))
43184284
return;
43194285
}

0 commit comments

Comments
 (0)