Chinaunix首页 | 论坛 | 博客
  • 博客访问: 148740
  • 博文数量: 38
  • 博客积分: 1315
  • 博客等级: 准尉
  • 技术积分: 850
  • 用 户 组: 普通用户
  • 注册时间: 2011-01-06 16:19
文章分类

全部博文(38)

文章存档

2011年(38)

分类: LINUX

2011-03-04 11:09:10

前面已经将slab系统的工作原理介绍完毕,接下来看一下slab系统的初始化代码。之所以把初始化放在最后,是因为初始化过程中往往需要做一些特殊的处理,刚开始学习slab时如果太关注这些反而会陷入混乱。对slab原理有了认知之后,再来看初始化要容易理解的多。
 
kmem_cache_init

slab系统的初始化。主要是创建general cache

void __init kmem_cache_init(void)

{

       size_t left_over;

       struct cache_sizes *sizes;

       struct cache_names *names;

       int i;

       int order;

       int node;

       /* UMA内存节点数为0 */

       if (num_possible_nodes() == 1)

                      use_alien_caches = 0;

/* slab初始化好之前,无法通过kmalloc分配初始化过程中必要的一些对象,只能使用静态的全局变量,待slab初始化后期,再使用kmalloc动态分配的对象替换全局变量 */

/* 如前所述,先借用全局变量initkmem_list3表示的slab三链,每个内存节点对应一组slab三链。initkmem_list3是个slab三链数组,对于每个内存节点,包含三组:struct kmem_cacheslab三链、struct arraycache_initslab 三链、struct kmem_list3slab三链。这里循环初始化所有内存节点的所有slab三链 */

       for (i = 0; i < NUM_INIT_LISTS; i++) {

                      kmem_list3_init(&initkmem_list3[i]);

/* 全局变量cache_cache指向的slab cache包含所有struct kmem_cache对象,不包含cache_cache本身。这里初始化所有内存节点的struct kmem_cacheslab三链为空。*/

                      if (i < MAX_NUMNODES)

                                    cache_cache.nodelists[i] = NULL;

       }

/* 设置struct kmem_cacheslab三链指向initkmem_list3中的一组slab三链,CACHE_CACHEcache在内核cache链表中的索引,struct kmem_cache对应的cache是内核中创建的第一个cache,故CACHE_CACHE0 */

       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.

        */

/* 全局变量slab_break_gfp_order为每个slab最多占用几个页面,用来抑制碎片,比如大小为3360的对象,如果其slab只占一个页面,碎片为736slab占用两个页面,则碎片大小也翻倍。只有当对象很大,以至于slab中连一个对象都放不下时,才可以超过这个值。有两个可能的取值:当可用内存大于32MB时,BREAK_GFP_ORDER_HI1,即每个slab最多占用2个页面,只有当对象大小大于8192时,才可以突破slab_break_gfp_order的限制。小于等于32MBBREAK_GFP_ORDER_LO0*/

       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.

        */

       /* 获得本内存节点的idUMA0 */

       node = numa_mem_id();

 

       /* 1) create the cache_cache */

/* 第一步,创建struct kmem_cache所在的cache,由全局变量cache_cache指向,这里只是初始化数据结构,并未真正创建这些对象,要待分配时才创建。*/

/* 全局变量cache_chain是内核slab cache链表的表头 */

       INIT_LIST_HEAD(&cache_chain);

/* cache_cache加入到slab cache链表 */

       list_add(&cache_cache.next, &cache_chain);

/* 设置cache着色基本单位为cache line的大小:32字节 */

       cache_cache.colour_off = cache_line_size();

/*  初始化cache_cachelocal cache,同样这里也不能使用kmalloc,需要使用静态分配的全局变量initarray_cache */

       cache_cache.array[smp_processor_id()] = &initarray_cache.cache;

       /* 初始化slab链表 */

       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.

        */

/* buffer_size保存slab中对象的大小,这里是计算struct kmem_cache的大小, nodelists是最后一个成员,nr_node_ids保存内存节点个数,UMA1,所以nodelists偏移加上1struct kmem_list3 的大小即为struct kmem_cache的大小 */

       cache_cache.buffer_size = offsetof(struct kmem_cache, nodelists) +

                                                   nr_node_ids * sizeof(struct kmem_list3 *);

#if DEBUG

/* obj_size为对象大小,设置其等于buffer_size */

       cache_cache.obj_size = cache_cache.buffer_size;

#endif

       /* 将对象大小与cache line大小对齐 */

       cache_cache.buffer_size = ALIGN(cache_cache.buffer_size,

                                                                cache_line_size());

       /* 计算对象大小的倒数,用于计算对象在slab中的索引 */

       cache_cache.reciprocal_buffer_size =

                      reciprocal_value(cache_cache.buffer_size);

 

       for (order = 0; order < MAX_ORDER; order++) {

                      /* 计算cache_cache中的对象数目 */

                      cache_estimate(order, cache_cache.buffer_size,

                                    cache_line_size(), 0, &left_over, &cache_cache.num);

                      /* num不为0意味着创建struct kmem_cache对象成功,退出 */

                      if (cache_cache.num)

                                    break;

       }

       BUG_ON(!cache_cache.num);

       /* gfporder表示本slab包含2gfporder个页面 */

       cache_cache.gfporder = order;

       /* 着色区的大小,以colour_off为单位 */

       cache_cache.colour = left_over / cache_cache.colour_off;

       /* slab管理对象的大小 */

       cache_cache.slab_size = ALIGN(cache_cache.num * sizeof(kmem_bufctl_t) +

                                                        sizeof(struct slab), cache_line_size());

 

       /* 2+3) create the kmalloc caches */

/* 第二步,创建kmalloc所用的general cachekmalloc所用的对象按大小分级,malloc_sizes保存大小,cache_names保存cache */

       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.

        */

/* 首先创建struct array_cachestruct kmem_list3所用的general cache,它们是后续初始化动作的基础 */

/* INDEX_AC是计算local cache所用的struct arraycache_init对象在kmalloc size中的索引,即属于哪一级别大小的general cache,创建此大小级别的cachelocal 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);

/* 如果struct kmem_list3struct arraycache_init对应的kmalloc size索引不同,即大小属于不同的级别,则创建struct kmem_list3所用的cache,否则共用一个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);

       }

/* 创建完上述两个general cache后,slab early init阶段结束,在此之前,不允许创建外置式slab */

       slab_early_init = 0;

       /* 循环创建kmalloc各级别的general 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.

                       */

/* 某级别的kmalloc cache还未创建,创建之,struct kmem_list3struct arraycache_init对应的cache已经创建过了 */

                      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++;

       }

       /* 至此,kmalloc general cache已经创建完毕,可以拿来使用了 */

       /* 4) Replace the bootstrap head arrays */

/* 第四步,用kmalloc对象替换静态分配的全局变量。到目前为止一共使用了两个全局local cache,一个是cache_cachelocal cache指向initarray_cache.cache,另一个是malloc_sizes[INDEX_AC].cs_cacheplocal cache指向initarray_generic.cache,参见setup_cpu_cache函数。这里替换它们。*/

       {

                      struct array_cache *ptr;

                      /* 申请cache_cache所用local cache的空间 */

                      ptr = kmalloc(sizeof(struct arraycache_init), GFP_NOWAIT);

 

                      BUG_ON(cpu_cache_get(&cache_cache) != &initarray_cache.cache);

                      /* 复制原cache_cachelocal cache,即initarray_cache,到新的位置 */

                      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_cachelocal cache指向新的位置 */

                      cache_cache.array[smp_processor_id()] = ptr;

/* 申请malloc_sizes[INDEX_AC].cs_cachep所用local cache的空间 */

                      ptr = kmalloc(sizeof(struct arraycache_init), GFP_NOWAIT);

 

                      BUG_ON(cpu_cache_get(malloc_sizes[INDEX_AC].cs_cachep)

                             != &initarray_generic.cache);

/* 复制原local cache到新分配的位置,注意此时local 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_cachelocal cache指向新的位置 */

                      malloc_sizes[INDEX_AC].cs_cachep->array[smp_processor_id()] =

                          ptr;

       }

       /* 5) Replace the bootstrap kmem_list3's */

       /* 第五步,与第四步类似,用kmalloc的空间替换静态分配的slab三链 */

       {

                      int nid;

                      /* UMA只有一个节点 */

                      for_each_online_node(nid) {

                                    /* 复制struct kmem_cacheslab三链 */

                                    init_list(&cache_cache, &initkmem_list3[CACHE_CACHE + nid], nid);

/* 复制struct arraycache_initslab三链 */

                                    init_list(malloc_sizes[INDEX_AC].cs_cachep,

                                                    &initkmem_list3[SIZE_AC + nid], nid);

/* 复制struct kmem_list3slab三链 */

                                    if (INDEX_AC != INDEX_L3) {

                                                  init_list(malloc_sizes[INDEX_L3].cs_cachep,

                                                                  &initkmem_list3[SIZE_L3 + nid], nid);

                                    }

                      }

       }

       /* 更新slab系统初始化进度 */

       g_cpucache_up = EARLY;

}

 

kmem_cache_init_late

Slab系统初始化分两个部分,先初始化一些基本的,待系统初始化工作进行的差不多时,再配置一些特殊功能。

void __init kmem_cache_init_late(void)

{

       struct kmem_cache *cachep;

       /* 初始化阶段local cache的大小是固定的,要根据对象大小重新计算 */

       /* 6) resize the head arrays to their final sizes */

       mutex_lock(&cache_chain_mutex);

       list_for_each_entry(cachep, &cache_chain, next)

                      if (enable_cpucache(cachep, GFP_NOWAIT))

                                    BUG();

       mutex_unlock(&cache_chain_mutex);

 

       /* Done! */

       /* 大功告成,general cache终于全部建立起来了 */

       g_cpucache_up = FULL;

 

       /* Annotate slab for lockdep -- annotate the malloc caches */

       init_lock_keys();

 

       /*

        * Register a cpu startup notifier callback that initializes

        * cpu_cache_get for all new cpus

        */

       /* 注册cpu up回调函数,cpu up时配置local cache */

       register_cpu_notifier(&cpucache_notifier);

 

#ifdef CONFIG_NUMA

       /*

        * Register a memory hotplug callback that initializes and frees

        * nodelists.

        */

       hotplug_memory_notifier(slab_memory_callback, SLAB_CALLBACK_PRI);

#endif

 

       /*

        * The reap timers are started later, with a module init call: That part

        * of the kernel is not yet operational.

        */

}

 

 
阅读(2267) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~