cache_cache的初始化和普通高速缓存的建立由start_kernel()-->mm_init()-->kmem_cache_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)
- use_alien_caches = 0;
- /*初始化静态L3变量initkmem_list3*/
- for (i = 0; i < NUM_INIT_LISTS; i++) {
- kmem_list3_init(&initkmem_list3[i]);
- if (i < MAX_NUMNODES)
- cache_cache.nodelists[i] = NULL;
- }
- /*将cache_cache和initkmem_list3相关联*/
- set_up_list3s(&cache_cache, CACHE_CACHE);
- /*
- * Fragmentation resistance on low memory - only use bigger
- * page orders on machines with more than 32MB of memory.
- */
- if (totalram_pages > (32 << 20) >> PAGE_SHIFT)
- slab_break_gfp_order = BREAK_GFP_ORDER_HI;
- /* 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();
- /*初始化cache_cache的其余部分*/
- /* 1) create the cache_cache */
- INIT_LIST_HEAD(&cache_chain);
- list_add(&cache_cache.next, &cache_chain);
- cache_cache.colour_off = cache_line_size();
- cache_cache.array[smp_processor_id()] = &initarray_cache.cache;
- cache_cache.nodelists[node] = &initkmem_list3[CACHE_CACHE + node];
- /*
- * struct kmem_cache size depends on nr_node_ids, which
- * can be less than MAX_NUMNODES.
- */
- 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 = ALIGN(cache_cache.buffer_size,
- cache_line_size());
- cache_cache.reciprocal_buffer_size =
- reciprocal_value(cache_cache.buffer_size);
- /*计算cache_cache的剩余空间以及slab中对象的数目,order决定了slab的大小(PAGE_SIZE<<order)*/
- for (order = 0; order < MAX_ORDER; order++) {
- cache_estimate(order, cache_cache.buffer_size,
- cache_line_size(), 0, &left_over, &cache_cache.num);
- /*当该order计算出来的num,即slab中对象的数目不为0时,则跳出循环*/
- if (cache_cache.num)
- break;
- }
- BUG_ON(!cache_cache.num);
- cache_cache.gfporder = order;/*确定分配给每个slab的页数的对数*/
- cache_cache.colour = left_over / cache_cache.colour_off;/*确定可用颜色的数目*/
- /*确定slab管理区的大小,即slab描述符以及kmem_bufctl_t数组*/
- cache_cache.slab_size = ALIGN(cache_cache.num * sizeof(kmem_bufctl_t) +
- sizeof(struct slab), cache_line_size());
- /* 2+3) create the kmalloc caches */
- sizes = malloc_sizes;
- names = cache_names;
- /*
- * Initialize the caches that provide memory for the array cache and the
- * kmem_list3 structures first. Without this, further allocations will
- * bug.
- */
- /*为了后面能够调用kmalloc()创建per-CPU高速缓存和kmem_list3高速缓存,
- 这里必须先创建大小相应的general cache*/
- 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);
- /*如果AC和L3在malloc_sizes中的偏移不一样,也就是说它们的大小不属于同一级别,
- 则创建AC的gerneral cache,否则两者共用一个gerneral cache*/
- 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;
- /*创建各级的gerneral cache*/
- 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
- 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;
- /*这里调用kmalloc()为cache_cache创建per-CPU高速缓存*/
- ptr = kmalloc(sizeof(struct arraycache_init), GFP_NOWAIT);
- BUG_ON(cpu_cache_get(&cache_cache) != &initarray_cache.cache);
- /*将静态定义的initarray_cache中的array_cache拷贝到malloc申请到的空间中*/
- 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与保存per-CPU高速缓存的空间关联*/
- cache_cache.array[smp_processor_id()] = ptr;
- /*为之前创建的AC gerneral cache创建per-CPU高速缓存,替换静态定义的initarray_generic.cache*/
- ptr = kmalloc(sizeof(struct arraycache_init), GFP_NOWAIT);
- 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;
- }
- /* 5) Replace the bootstrap kmem_list3's */
- {
- int nid;
- for_each_online_node(nid) {
- /*为cache_cache的kmem_list3申请高速缓存空间,并替换静态定义的initkmem_list3*/
- init_list(&cache_cache, &initkmem_list3[CACHE_CACHE + nid], nid);
- /*为AC的kmem_list3申请高速缓存空间,并替换静态定义的initkmem_list3*/
- init_list(malloc_sizes[INDEX_AC].cs_cachep,
- &initkmem_list3[SIZE_AC + nid], nid);
- if (INDEX_AC != INDEX_L3) {
- /*为L3的kmem_list3申请高速缓存空间,并替换静态定义的initkmem_list3*/
- init_list(malloc_sizes[INDEX_L3].cs_cachep,
- &initkmem_list3[SIZE_L3 + nid], nid);
- }
- }
- }
- g_cpucache_up = EARLY;
- }