slab

slab

数据结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
struct kmem_cache {
struct array_cache *array[NR_CPUS];
unsigned int batchcount; //要转移本地高速缓存的大批对象的数量
unsigned int limit; //本地高速缓存中空闲对象的最大数目
unsigned int shared;
unsigned int buffer_size; //高速缓存的大小
u32 reciprocal_buffer_size;

unsigned int flags; //描述高速缓存永久属性的一组标志
unsigned int num; //封装在一个单独slab中的对象个数
unsigned int gfporder; // 一个单独slab中包含的连续页框数目的对数
gfp_t gfpflags;
size_t colour; //slab使用的颜色个数
unsigned_int colour_off; //slab中的基本对齐偏移

struct kmem_cache *slabp_cache;

unsigned int slab_size; //slab的大小
unsigned int dflags; //动态标志

void (*ctor)(void *,struct kmem_cache *,unsigned long); //构造函数
const char *name; //存放高速缓存名字的字符数组
struct list_head next; //高速缓存描述符双向链表使用的指针
...
struct kmem_list3 *nodelists[MAX_NUMNODES];//高速缓存中的slab链表

//下面三个参数待定
unsigned int objsize; //高速缓存中包含的对象的大小
unsigned int free_limit;//整个slab高速缓存中空闲对象的上限
spinlock_t spinlock;//高速缓存自旋锁
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

kmem_list3 {
struct list_head slabs_partial; //含有部分对象的链表
struct list_head slabs_full; //满对象链表
struct list_head slabs_free; //空对象链表
unsigned long free_objects;
unsigned int free_limit;
unsigned int colour_next; //每节点高速缓存的颜色
spinlock_t list_lock;
struct array_cache *shared; //每节点的共享高速缓存
struct array_cache **alien; //其他节点
unsigned long next_reap;
int free_touched; //
}
struct kmem_list3 __initdata initkmem_list3[NUM_INIT_LISTS];
1
2
3
4
5
6
7
8
struct slab {
struct list_head list; //slab描述符的三个双向循环链表中的一个
unsigned long colouroff; //slab中第一个对象
void *s_mem; //slab中第一个对象的地址
unsigned int inuse; //当前正在使用的slab中的对象的个数
kmem_bufctl_t free; //slab中第一个空闲对象的下标。
unsigned short nodeid;
}

上面三者的关系

slab 在页面的外部


slab在页面的内部

跟踪空闲对象

1
typedef unsigned int kmem_bufctl_t;

kmem_bufctl_t 数组保存在slab描述符之后,并且没有指针直接指向第一个元素,所以需要提供辅助宏。

1
2
#define slab_bufctl(slabp) \
((kmem_bufctl_t *)(((slab_t *)slabp)+1))

slabp+1是slab_t元素之后,其实就是kmem_bufctl_t的起始地址。
slab里下一个空闲对象的索引在slab_t->free中

指定大小的告诉缓存

数据结构

1
2
3
4
5
struct cache_sizes {
size_t cs_size;
struct kmem_cache *cs_cachep; 常规内存使用的高速缓存
struct kmem_cache *cs_dmacachep; DMA使用的高速缓存
};

静态数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#define CACHE(x) {.cs_size = (x) ,NULL ,NULL }

struct cache_sizes malloc_sizes[] = {

#if (PAGE_SIZE == 4096)
CACHE(32)
#endif
CACHE(64)
#if L1_CACHE_BYTES < 64 // L1_CACHE_BYTES = 128
CACHE(96)
#endif
CACHE(128)
#if L1_CACHE_BYTES < 128
CACHE(192)
#endif
CACHE(256)
CACHE(512)
CACHE(1024)
CACHE(2048)
CACHE(4096)
CACHE(8192)
CACHE(16384)
CACHE(32768)
CACHE(65536)
CACHE(131072)
#if KMALLOC_MAX_SIZE >= 262144
CACHE(262144)
#endif
#if KMALLOC_MAX_SIZE >= 524288
CACHE(524288)
#endif
#if KMALLOC_MAX_SIZE >= 1048576
CACHE(1048576)
#endif
#if KMALLOC_MAX_SIZE >= 2097152
CACHE(2097152)
#endif
#if KMALLOC_MAX_SIZE >= 4194304
CACHE(4194304)
#endif
#if KMALLOC_MAX_SIZE >= 8388608
CACHE(8388608)
#endif
#if KMALLOC_MAX_SIZE >= 16777216
CACHE(16777216)
#endif
#if KMALLOC_MAX_SIZE >= 33554432
CACHE(33554432)
#endif
CACHE(ULONG_MAX);
}

per-CPU高速缓存

结构体array_cache,空闲对象的本地高速缓存的一个描述符

1
2
3
4
5
6
7
8
struct array_cache {
unsigned int avail; //指向本地高速缓存可用对象的指针的个数
unsigned int limit; //本地高速缓存的大小,也就是本地高速缓存中指针的最大个数
unsigned int batchcount; //本地高速缓存重新填充或者是腾空时使用的块大小
unsigned int touched; //如果本地高随缓存最近已经被使用过,就将该标志设置为1
spinlock_t lock;
void *entry[0];
};

结构体arraycache_init

1
2
3
4
5
struct arraycache_init {
struct array_cache cache;
void *entries[BOOT_CPUCACHE_ENTRIES];
};
static struct arraycache_init initarray_cache __initdata={{0,BOOT_CPUCACHE_ENTRIES,1,0}};

一些重要的全局变量

第一个高速缓存的描述符cache_cache,第一个高速缓存叫做kmem_cache,包含由内核使用的其余高速缓存的高速缓存描述符。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
static struct kmem_cache cache_cache = {
.batchcount = 1,
.limit = BOOT_CPUCACHE_ENTRIES,
.shared = 1.
.buffer_size = sizeof(struct kmem_cache),
.name = "kmem_cache",
};


//初始化
static void kmem_list3_init(struct kmem_list3 *parent)
{
INIT_LIST_HEAD(&parent->slabs_full);
INIT_LIST_HEAD(&parent->slabs_partial);
INIT_LIST_HEAD(&parent->slabs_free);
parent->shared = NULL;
parent->alien = NULL;
parent->colour_next = 0;
spin_lock_init(&parent->list_lock);
parent->free_objects = 0;
parent->free_touched = 0;
}

kmem_cache初始化函数
kmem_cache_init();
kmem_cache_create();//这个函数的最终实现是kmem_cache_zalloc()->kmem_cache_alloc(,|__GFP_ZERO)->__cache_alloc()->__do_cache_alloc()->____cache_alloc()
cache_alloc_refill()