slab源码分析--从slab初始化说起

上次说了 slab 的主要数据结构,这次从初始化开始进行源码剖析。

slab 的初始化,当然是从内核启动就开始了。内核启动的 start_kernel() 函数:

//内核的启动程序啊:)
asmlinkage void __init start_kernel(void)
{
    ...
    mem_init();    //内存相关初始化
    kmem_cache_init();    //slab 初始化
    ...
}

其中调用 kmem_cache_init() 函数,这就是要进行 slab 的初始化。

/*
 * Initialisation.  Called after the page allocator have been initialised and
 * before smp_init().
 */
 //这个函数用来建立通用缓存器,否则我们无法使用kmalloc
void __init kmem_cache_init(void)
{
    size_t left_over;
    struct cache_sizes *sizes;
    struct cache_names *names;
    int i;
    int order;
    int node;

    //如果节点数目只有1个,那么就不能使用其他节点的shared cache
    if (num_possible_nodes() == 1)  //貌似当前这个版本还不支持这个,参见#define num_possible_nodes() 1
        use_alien_caches = 0;             //后续linux版本会支持

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

    //如前所述,先借用 initkem_list3 代替要用到的三链,每个节点对应一组三链
    //initkmem_list3 是个三链数组,这里循环初始化每个节点的三链 
    for (i = 0; i < NUM_INIT_LISTS; i++) {       //FIXME: NUM_INIT_LIST 是怎么求的,为什么等于2 * MAX_NODES+1 ? 有的版本是 3 * MAX_NODES
        kmem_list3_init(&initkmem_list3[i]);
        if (i < MAX_NUMNODES)
        //全局变量cache_cache指向的slab cache包含所有的kmem_cache对象,不包含cache_cache本身
        //这里初始化所有内存节点kmem_cache的slab三链为空
            cache_cache.nodelists[i] = NULL;
    }

    /*
     * Fragmentation resistance on low memory - only use bigger
     * page orders on machines with more than 32MB of memory.
     */
     //全部变量slab_break_gfp_order为每个slab最多占用几个页面,用来减少碎片。
     //总结起来意思就是是: (1)如果物理可用内存大于32MB,也就是可用内存充裕的时候,BREAK_GFP_ORDER_HI这个宏的值是1,
     //这个时候每个slab最多占用两个页面,不过此时不能横跨3个页面,除非对象大小大于8192K时才可以(一个页面大小是4K,也就是4096);
     //(2)如果可用内存不大于32MB,那么BREAK_GFP_ORDER_HI值为0,最多也就是允许一个页面,除非对象超了,否则不能横跨
    if (num_physpages > (32 << 20) >> PAGE_SHIFT)
        slab_break_gfp_order = BREAK_GFP_ORDER_HI;   //用来确定slab的最大大小

    /* 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();   //获取节点id,取得的值为0,因为初始化程序单CPU执行,且是0号

    /* 1) create the cache_cache */
    //初始化cache_chain 为 kmem_cache 链表头部
    INIT_LIST_HEAD(&cache_chain);
    list_add(&cache_cache.next, &cache_chain);
    //设置cache着色的偏移量基本值,也就是L1缓存行的大小
    cache_cache.colour_off = cache_line_size(); //宏定义L1缓存行的大小 #define cache_line_size() L1_CACHE_BYTES
    //初始化cache_cache的per-CPU cache,同样这里也不能使用kmalloc,需要使用静态分配的全局变量initarray_cache
    cache_cache.array[smp_processor_id()] = &initarray_cache.cache;
    //初始化slab链表,用全局变量,这里CACHE_CACHE值为0,是因为cache_cache就是系统第一个的缓存器
    cache_cache.nodelists[node] = &initkmem_list3[CACHE_CACHE];

    /*
     * struct kmem_cache size depends on nr_node_ids, which
     * can be less than MAX_NUMNODES.
     */
     //buffer_size原指用来分配的对象大小,由于cache_cache是用来做 kmem_cache 的分配器的,所以 buffer_size 的大小就是 kmem_cache 的大小
     //注意柔性数组的计算方法,nodelists不占据 kmem_cache的大小,所以要分开计算,并且注意nodelists数组在UMA架构只有一个节点,所以只有1个kmem_list3的指针
    cache_cache.buffer_size = offsetof(struct kmem_cache, nodelists) +
                 nr_node_ids * sizeof(struct kmem_list3 *);
#if 0 
#if DEBUG
    cache_cache.obj_size = cache_cache.buffer_size;
#endif
#endif

    //注意这里又一次计算了 buffer_size 的大小,通过这次计算将buffer_size以 缓存行 为单位进行上边界对齐
    //计算分配的对象与cache line的大小对齐后的大小
    c
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值