/*
下面的测试数据是在linux 2.6.16.36中进行的,这个版本没有支持slub
cache_cache是对所有cache描述符的管理
*/
/*
* Initialisation. Called after the page allocator have been initialised and
* before smp_init().
初始化操作,在页分配初始化后,smp_init()之前被调用
*/
void __init kmem_cache_init(void)
{
size_t left_over;
struct cache_sizes *sizes;
struct cache_names *names;
int i;
int order;
int node;
if (num_possible_nodes() == 1) { //num_possible_nodes() = 1
use_alien_caches = 0;
numa_platform = 0;
}
for (i = 0; i < NUM_INIT_LISTS; i++) { //NUM_INIT_LISTS = 3
kmem_list3_init(&initkmem_list3[i]);
if (i < MAX_NUMNODES)
cache_cache.nodelists[i] = NULL; //初始化当前CPU对应的kmem_list3为空
}
/*
* Fragmentation resistance on low memory - only use bigger
* page orders on machines with more than 32MB of memory.
* the value of num_physpages is 32752
*/
if (num_physpages > (32 << 20) >> PAGE_SHIFT)
slab_break_gfp_order = BREAK_GFP_ORDER_HI;
/*
slab_break_gfp_order = 1;
*/
/* Bootstrap is tricky, because several objects are allocated
* from caches that do not exist yet:
* 1) initialize the cache_cache cache: it contains the struct
* kmem_cache structures of all caches, except cache_cache itself:
* cache_cache is statically allocated.
* Initially an __init data area is used for the head array and the
* kmem_list3 structures, it's replaced with a kmalloc allocated
* array at the end of the bootstrap.
* 2) Create the first kmalloc cache.
* The struct kmem_cache for the new cache is allocated normally.
* An __init data area is used for the head array.
* 3) Create the remaining kmalloc caches, with minimally sized
* head arrays.
* 4) Replace the __init data head arrays for cache_cache and the first
* kmalloc cache with kmalloc allocated arrays.
* 5) Replace the __init data for kmem_list3 for cache_cache and
* the other cache's with kmalloc allocated memory.
* 6) Resize the head arrays of the kmalloc caches to their final sizes.
*/
node = numa_node_id();
/* 1) create the cache_cache */
/*
创建cache_cache
初始化cache_chain,即cache链
INIT_LIST_HEAD(&cache_chain);
*/
/*
将cache_cache作为cache_chain的头节点
*/
list_add(&cache_cache.next, &cache_chain);
/*
设置cache_cache 中slab的基本对齐偏移
*/
/*
在调试过程中,cache_line_size()的值为32
*/
cache_cache.colour_off = cache_line_size();
/*
初始化cache_cache空闲对象的本地高速缓存所对应的描述符
*/
cache_cache.array[smp_processor_id()] = &initarray_cache.cache;
//
cache_cache.nodelists[node] = &initkmem_list3[CACHE_CACHE];
/*
* struct kmem_cache size depends on nr_node_ids(1), which
* can be less than MAX_NUMNODES.
*/
/*
计算kmem_cache结构体的缓存大小,cache_cache.buffer_size = 80;
*/
cache_cache.buffer_size = offsetof(struct kmem_cache, nodelists) +
nr_node_ids * sizeof(struct kmem_list3 *);
#if DEBUG
cache_cache.obj_size = cache_cache.buffer_size;
#endif
/*
设置对齐数值,减少刷新次数,cache_cache.buffer_size = 96.
*/
cache_cache.buffer_size = ALIGN(cache_cache.buffer_size,
cache_line_size());
/*
#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a) - 1);
*/
cache_cache.reciprocal_buffer_size =
reciprocal_value(cache_cache.buffer_size);
/*
设置缓存大小以及slab内未使用的字节,实际上,这里是创建第一个slab描述符,并
设计了分配第一个页框
*/
for (order = 0; order < MAX_ORDER; order++) {
/*
这里详细解释cache_estimate(unsigned long gfporder,size_t buffer_size,
size_t align,int flags,size_t *left_over,unsigned int *num)
这个函数是用来计算slab所包含的对象的数量以及left-over(即空闲区域),作为初始化
函数,这里的sizeof(struct kmem_cache),所以值order = 0.
*/
cache_estimate(order, cache_cache.buffer_size,
cache_line_size(), 0, &left_over, &cache_cache.num);
/*
cache_cache.num = 40,left_over = 64;
*/
if (cache_cache.num)
break;
}
BUG_ON(!cache_cache.num);
/*
设置cache_cache中第一个单独slab中包含的连续页框数目的对数,这里的值为0
*/
cache_cache.gfporder = order;
/*
确定cache_cache中可用颜色的个数,根据以上的计算,得到的值为2
这里注意的一点是:“着色”其实是用来再细分slab,本质上是将slab中的一些空闲区
域从末尾移动到开始处.这样可能会使内核从微处理器的硬件高速缓存中获得最好性能.
为什么?
*/
cache_cache.colour = left_over / cache_cache.colour_off;
/*
设置slab描述符以及对象描述符的大小,这里的值为192,
cache_cache.num(对象的数量),kmem_bufctl_t(对象描述符),slab(slab描述符)
cache_cache.num = 40,sizeof(struct kmem_bufctl_t) = 4
sizeof(strict slab) = 28,三者之和为188,以32对齐,得到192
*/
cache_cache.slab_size = ALIGN(cache_cache.num * sizeof(kmem_bufctl_t) +
sizeof(struct slab), cache_line_size());
/* 2+3) create the kmalloc caches */
/*
下面调用kmem_cache_create来创建cache
*/
sizes = malloc_sizes;
/*
$36 = {{name = 0xc031c9e0 "size-32", name_dma = 0xc031c9e8 "size-32(DMA)"}, {
name = 0xc031c9f5 "size-64", name_dma = 0xc031c9fd "size-64(DMA)"}, {
name = 0xc031ca0a "size-128", name_dma = 0xc031ca13 "size-128(DMA)"}, {
name = 0xc031ca21 "size-192", name_dma = 0xc031ca2a "size-192(DMA)"}, {
name = 0xc031ca38 "size-256", name_dma = 0xc031ca41 "size-256(DMA)"}, {
name = 0xc031ca4f "size-512", name_dma = 0xc031ca58 "size-512(DMA)"}, {
name = 0xc031ca66 "size-1024", name_dma = 0xc031ca70 "size-1024(DMA)"}, {
name = 0xc031ca7f "size-2048", name_dma = 0xc031ca89 "size-2048(DMA)"}, {
name = 0xc031ca98 "size-4096", name_dma = 0xc031caa2 "size-4096(DMA)"}, {
name = 0xc031cab1 "size-8192", name_dma = 0xc031cabb "size-8192(DMA)"}, {
name = 0xc031caca "size-16384", name_dma = 0xc031cad5 "size-16384(DMA)"}, {
name = 0xc031cae5 "size-32768", name_dma = 0xc031caf0 "size-32768(DMA)"}, {
name = 0xc031cb00 "size-65536", name_dma = 0xc031cb0b "size-65536(DMA)"}, {
name = 0xc031cb1b "size-131072",
name_dma = 0xc031cb27 "size-131072(DMA)"}, {name = 0x0, name_dma = 0x0}}
*/
names = cache_names;
/*
首先为cache数组以及kmem_list3结构体提供内存,这是通过初始化caches,如果没
有这个初始数据,那么后面的分配工作将会出现bug
*/
/*
kmem_cache_create创建一个高速缓存cache;
struct kmem_cache *kmem_cache_create(const char *name,size_t size,
size_t align, unsigned long flags,void (*ctor)(void *,struct kmem_cache
*,unsigned long))
name:用于/proc/slabinfo文件中来识别这个cache
size:在对应的cache中所创建的对象的长度
align:对象对齐尺寸
flags:SLAB标志
ctor:构造函数
kmem_cache_create()创建成功返回一个指针ptr,失败返回NULL,当新的页框被
cache分配时执行ctor构造函数
name在cache销毁之前必须是合法的,
flags:这个变量取值有SLAB_POISON,SLAB_RED_ZONE,SLAB_HWCACHE_ALIGN
*/
/*
kmem_cache_create()的核心代码:
kmem_cache_create() {
size_t left_over,slab_size,ralign;
struct kmem_cache *cachep =NULL,*pc;
...
cachep = kmem_cache_zalloc(&cache_cache,GFP_KERNEL);
...
left_over = calculate_slab_order(cachep,size,align,flags);
...
cachep->colour_off = cache_line_size();
cachep->colour = left_over/cachep->colour_off;
cachep->slab_size = flags;
cachep->gfpflags = 0;
cachep->buffer_size = size;
cachep->reciprocal_buffer_size = reciprocal_value(size);
...
cachep->ctor = ctor;
cachep->name = name;
...
return cachep;
}
*/
/*
根据arraycache_int的大小使用kmem_cache_create来创建cache,即
kmem_cache_create创建的第一个高速缓存是用来处理arraycache_init的
INDEX_AC = sizeof(struct arraycache_t)
此处的names[INDEX_AC].name = "size-32".
*/
sizes[INDEX_AC].cs_cachep = kmem_cache_create(names[INDEX_AC].name,
sizes[INDEX_AC].cs_size,
ARCH_KMALLOC_MINALIGN,
ARCH_KMALLOC_FLAGS|SLAB_PANIC,
NULL);
/*
kmem_cache_create()最终函数的实现是cache_alloc_refill();
cache_alloc_refill()的最终实现看后面.+
*
/
/*
如果arraycache_init和kmem_list3所使用的高速缓存大小不同就给kmem_list3
创建一个新的高速缓存描述符
*/
if (INDEX_AC != INDEX_L3) {
sizes[INDEX_L3].cs_cachep =
kmem_cache_create(names[INDEX_L3].name,
sizes[INDEX_L3].cs_size,
ARCH_KMALLOC_MINALIGN,
ARCH_KMALLOC_FLAGS|SLAB_PANIC,
NULL);
}
slab_early_init = 0;
/*
此循环初始创建所有类型的高速缓存,相当于为所有类型的高速缓存开辟了一个起点
*/
while (sizes->cs_size != ULONG_MAX) {
/*
* For performance, all the general caches are L1 aligned.
* This should be particularly beneficial on SMP boxes, as it
* eliminates "false sharing".
* Note for systems short on memory removing the alignment will
* allow tighter packing of the smaller caches.
*/
if (!sizes->cs_cachep) {
sizes->cs_cachep = kmem_cache_create(names->name,
sizes->cs_size,
ARCH_KMALLOC_MINALIGN,
ARCH_KMALLOC_FLAGS|SLAB_PANIC,
NULL);
}
#ifdef CONFIG_ZONE_DMA
/*
给DMA创建一个高速缓存
*/
sizes->cs_dmacachep = kmem_cache_create(
names->name_dma,
sizes->cs_size,
ARCH_KMALLOC_MINALIGN,
ARCH_KMALLOC_FLAGS|SLAB_CACHE_DMA|
SLAB_PANIC,
NULL);
#endif
sizes++;
names++;
}
/* 4) Replace the bootstrap head arrays */
{
struct array_cache *ptr;
/*
创建array_cache类型对象,代替前面已初始化的cache_cache.array[0],
如此一来,这就受到cache_cache的管理了.
*/
ptr = kmalloc(sizeof(struct arraycache_init), GFP_KERNEL);
local_irq_disable();
BUG_ON(cpu_cache_get(&cache_cache) != &initarray_cache.cache);
//复制cache_cache中array_cache的值到ptr.
memcpy(ptr, cpu_cache_get(&cache_cache),
sizeof(struct arraycache_init));
/*
* Do not assume that spinlocks can be initialized via memcpy:
*/
spin_lock_init(&ptr->lock);
/*
改变cache_cache原有的array_cache
*/
cache_cache.array[smp_processor_id()] = ptr;
local_irq_enable();
ptr = kmalloc(sizeof(struct arraycache_init), GFP_KERNEL);
local_irq_disable();
BUG_ON(cpu_cache_get(malloc_sizes[INDEX_AC].cs_cachep)
!= &initarray_generic.cache);
memcpy(ptr, cpu_cache_get(malloc_sizes[INDEX_AC].cs_cachep),
sizeof(struct arraycache_init));
/*
* Do not assume that spinlocks can be initialized via memcpy:
*/
spin_lock_init(&ptr->lock);
malloc_sizes[INDEX_AC].cs_cachep->array[smp_processor_id()] =
ptr;
local_irq_enable();
}
/* 5) Replace the bootstrap kmem_list3's */
//取代引导程序所使用的kmem_list3
{
int nid;
/*
调用kmalloc_node()函数创建kmem_list3对象,取代初始的静态数据kmem_list3
*/
init_list(&cache_cache, &initkmem_list3[CACHE_CACHE], node);
/*
下面是init_list的具体实现
struct kmem_list3 *ptr;
ptr = kmalloc_node(sizeof(struct kmem_list3),GFP_KERNEL,nodeid);
local_irq_disable();
memcpy(ptr,list,sizeof(struct kmem_list3));
spin_lock_init(&ptr->list_lock);
MAKE_ALL_LISTS(cachep,ptr,nodeid);
cachep->nodelists[nodeid] = ptr;
local_irq_enable();
*/
for_each_online_node(nid) {
init_list(malloc_sizes[INDEX_AC].cs_cachep,
&initkmem_list3[SIZE_AC + nid], nid);
if (INDEX_AC != INDEX_L3) {
init_list(malloc_sizes[INDEX_L3].cs_cachep,
&initkmem_list3[SIZE_L3 + nid], nid);
}
}
}
/* 6) resize the head arrays to their final sizes */
{
struct kmem_cache *cachep;
mutex_lock(&cache_chain_mutex);
list_for_each_entry(cachep, &cache_chain, next)
if (enable_cpucache(cachep))
BUG();
mutex_unlock(&cache_chain_mutex);
}
/* Annotate slab for lockdep -- annotate the malloc caches */
init_lock_keys();
/* Done! */
g_cpucache_up = FULL;
/*
* Register a cpu startup notifier callback that initializes
* cpu_cache_get for all new cpus
*/
register_cpu_notifier(&cpucache_notifier);
/*
* The reap timers are started later, with a module init call: That part
* of the kernel is not yet operational.
*/
}
阅读(2170) | 评论(0) | 转发(0) |