slab allocator (2)—— kmem_cache_create

          这个函数是slab系统的核心函数之一,他是kmalloc的后盾,也可以直接作为分配内存的接口,供驱动调用。具体可以参看ldd3的chp 8的后备高速缓存一节(P217)。他其实和我们CPU的L1,L2缓存并没有什么关系。他有点类似于内存池,可以从中分配若干个size相同的内存块使用。

          其调用流程主线如下:
          
          主线还是很清楚的,就是通过kmem_cache_zalloc分配kmem_cache,然后各种初始化,最后加入cache_chain中。之前不清楚的一个问题——cache_chain是做什么用的,现在看起来应该是有答案了。他的作用就是保存已分配的kmem_cache记录,防止重名的cache产生,方便proc系统显示调试信息。
          整个流程中有几个值得关注的地方

1. kmem_cache的初始化
     1)当size >= (PAGE_SIZE >> 3 = 512KB时,flags |= CFLGS_OFF_SLAB
     2)calculate_slab_order(cachep, size, align, flags)
          
          所谓的num与offslab_limit就是下面off-slab这种情况下,由整块2^order个页面决定的object数(num),和右边kmem_bufctl_t数组决定的object数(offslab_limit)。可见有一个约束就是,num要小于offslab_limit,也就是左边小于右边。很好理解,因为右边是左边的管控。
          3)如果left_over太多,足够放得下slab_size,会将off-slab转变为on-slab
2. off-slab时,slab mngmt放在哪
          调用cachep->slabp_cache = kmem_find_general_cachep(slab_size, 0u),去寻找这个size cache来存放slab mngmt。
               kmem_find_general_cachep -> __find_general_cachep -> (return malloc_sizes[n]->cs_cachep)

3. CPU cache的初始化
          setup_cpu_cache(cachep, gfp)
          这是一个很复杂的函数,先看调用流程

          
          整个过程根据g_cpucache_up分成三个部分
          1)FULL状态,此时,所有的cache初始化都完成了,setup_cpu_cache要做的就是enable_cpucache。这也是一个很复杂的函数,再另开新篇介绍
          2)PARTIAL_AC/L3状态,此时调用此函数的kmem_cache_create仍在kmem_cache_init中,初始化才刚开始,需要先对struct arracy_cache和kmem_list3s用到的内存进行初始化,否则其他cache在初始化时,无法动态地为这两个结构体分配内存
          3)剩下的就是,AC和L3都分配好了,其他的cache再create就可以正常的调用kmalloc了

          INDEX_AC的array_cache初始化是initarray_generic.cache
          INDEX_AC / L3的kmem_list3初始化是initkmem_list3[SIZE_AC / L3]
          cache_cache的array_cache初始化是initarray_cache,kmem_list3初始化是initkmem_list3[CACHE_CACHE]
          这些在kmem_cache_init的step 4,5都会被重新用kmalloc进行动态分配,并且array_cache会用memcpy将原先值赋入,list会用splice进行合并。