• 内存管理 初始化(三)before mm_init()


    看到了mm_init(),期间将从bootmem迁移到伙伴系统,slab分配器也会建立。

    在分析mm_init()之前,把setup_arch(&command_line)之后的函数分析了以下,详见注释。

    start_kernel()                                                                                                     
        |---->page_address_init()
        |     考虑支持高端内存
        |     业务:初始化page_address_pool链表;
        |          将page_address_maps数组元素按索引降序插入
        |          page_address_pool链表; 
        |          初始化page_address_htable数组.
        | 
        |---->setup_arch(&command_line);
        |
        |---->setup_per_cpu_areas();
        |     为per-CPU变量分配空间
        |
        |---->build_all_zonelist()
        |     为系统中的zone建立后备zone的列表.
        |     2.6.34中的建立过程与《深入Linux内核架构》中p_134~p_135的图不符
        |     (即使是UMA也不同),书中讲述是每个zone都有自己的zonelist,
        |     2.6.34中对于UMA,所有zone的后备列表都在
        |     pglist_data->node_zonelists[0]中;
        |
        |     期间也对per-CPU变量boot_pageset做了初始化. 
        |
        |---->page_alloc_init()
             |---->hotcpu_notifier(page_alloc_cpu_notifier, 0);
             |     不考虑热插拔CPU 
             |       
        |---->pidhash_init()
        |     详见下文. 
        |     根据低端内存页数和散列度,分配hash空间,并赋予pid_hash
        |
        |---->vfs_caches_init_early()
              |---->dcache_init_early()
              |     dentry_hashtable空间,d_hash_shift, h_hash_mask赋值;
              |     同pidhash_init();
              |     区别:   
              |         散列度变化了(13 - PAGE_SHIFT);
              |         传入alloc_large_system_hash的最后参数值为0;
              |       
              |---->inode_init_early()
              |     inode_hashtable空间,i_hash_shift, i_hash_mask赋值;
              |     同pidhash_init();
              |     区别:
              |         散列度变化了(14 - PAGE_SHIFT);
              |         传入alloc_large_system_hash的最后参数值为0;
              |
    void pidhash_init(void)                                                                                            
        |---->pid_hash = alloc_large_system_hash("PID", sizeof(*pid_hash), 
        |         0, 18, HASH_EARLY|HASH_SMALL, &pidhash_shift, NULL, 4096);
        |     根据nr_kernel_pages(低端内存的页数),分配哈希数组,以及各个哈希
        |     数组元素下的哈希链表的空间,原理如下:
        |     number = nr_kernel_pages; 
        |     number >= (18 - PAGE_SHIFT) 根据散列度获得数组元素个数
        |     number = roundup_pow_of_two(number);
        |     pidhash_shift = max{x | 2**x <= number}
        |     size = number * sizeof(*pid_hash);
        |     使用位图分配器分配size空间,将返回值付给pid_hash;
        |
        |---->pidhash_size = 1 << pidhash_shift;
        |
        |---->for(i = 0; i < pidhash_size; i++)
        |         INIT_HLIST_HEAD(&pid_hash[i]);
    void build_all_zonelists(void)
        |---->set_zonelist_order()
             |---->current_zonelist_order = ZONELIST_ORDER_ZONE;
        |
        |---->__build_all_zonelists(NULL);
        |    Memory不支持热插拔, 为每个zone建立后备的zone,
        |    每个zone及自己后备的zone,形成zonelist
        |
        |---->vm_total_pages = nr_free_pagecache_pages();
        |    业务:获得所有zone中的present_pages总和.
       |
        |---->page_group_by_mobility_disabled = 0; | 对于代码中的判断条件一般不会成立,因为页数会最够多(内存较大)
    static int __build_all_zonelists(void *dummy)
        |---->pg_data_t *pgdat = NULL;
        |     pgdat = &contig_page_data;(单node)
        |
        |---->build_zonelists(pgdat);
        |     为每个zone建立后备zone的列表
        |
        |---->build_zonelist_cache(pgdat);
              |---->pdat->node_zonelists[0].zlcache_ptr = NULL;
              |     UMA体系结构
              |
        |---->for_each_possible_cpu(cpu)
        |     setup_pageset(&per_cpu(boot_pageset, cpu), 0);
              |详见下文
    void build_zonelists(pg_data *pgdat)
        |---->struct zonelist *zonelist = NULL;
        |     enum zone_type j;
        |     zonelist = &pgdat->node_zonelists[0];
        |
        |---->j = build_zonelists_node(pddat, zonelist, 0, MAX_NR_ZONES - 1);
        |     为pgdat->node_zones[0]建立后备的zone,node_zones[0]后备的zone
        |     存储在node_zonelist[0]内,对于node_zone[0]的后备zone,其后备的zone
        |     链表如下(只考虑UMA体系,而且不考虑ZONE_DMA):
        |     node_zonelist[0]._zonerefs[0].zone = &node_zones[2];
        |     node_zonelist[0]._zonerefs[0].zone_idx = 2;
        |     node_zonelist[0]._zonerefs[1].zone = &node_zones[1];
        |     node_zonelist[0]._zonerefs[1].zone_idx = 1;
        |     node_zonelist[0]._zonerefs[2].zone = &node_zones[0];
        |     node_zonelist[0]._zonerefs[2].zone_idx = 0;
        |     
        |     zonelist->_zonerefs[3].zone = NULL;
        |     zonelist->_zonerefs[3].zone_idx = 0;    
    void setup_pageset(struct per_cpu_pageset *p, unsigned long batch)
        |---->memset(p, 0, sizeof(*p));
        |
        |---->struct per_cpu_pages *pcp = NULL;
        |     pcp = &p->pcp;
        |     pcp->count = 0;
        |     pcp->high = 6 * batch;
        |     pcp->batch = max(1UL, 1 * batch);
        |
        |---->for(migratetype = 0; 
        |         migratetype < MIGRATE_PCPTYPES;
        |         migratetype++) |---->INIT_LIST_HEAD(&pcp->lists[migratetype]);
    unsigned int nr_free_pagecache_pages(void)
      |-->return nr_free_zone_pages(gfp_zone(GFP_HIGHUSER_MOVABLE));
                 对于UMA,且不考虑ZONE_DMA,参数为2
                 |-->参数offset = 2;
                 |   struct zoneref *z =NULL;
                 |   struct zone *zone = NULL;
                 |   unsigned int sum = 0;
                 |   struct zonelist *zonelist = 
                 |         node_zonelist(numa_node_id(), GFP_KERNEL)
                 |   对于UMA,zonelist = 
                 |           (&contig_page_data)->node_zonelists; | |-->for_each_zone_zonelist(zone, z, zonelist, offset) | offset的作用在于遍历zonelist下的_zonerefs数组元数中, | zone_idx <= offset的zone; | 因此当offset为0时,遍历的结果相当于 | zone = &pglist_data->node_zones[0] | | unsigned long size = zone->present_pages; | 获得该zone跨越的页数. | | unsigned long high = high_wmark_pages(zone); | if(size > high) sum += size - high; | (high暂时为0,因为zone->watermark[WMARK_HIGH] = 0) | |-->return sum;
  • 相关阅读:
    [LeetCode] 90. 子集 II
    [LeetCode] 91. 解码方法
    [LeetCode] 89. 格雷编码
    [LeetCode] 88. 合并两个有序数组
    转:Google论文之三----MapReduce
    转:Google论文之二----Google文件系统(GFS)翻译学习
    转:Zend Framework 2.0 分析
    转:PHP include()和require()方法的区别
    转:cookie和session(二)——php应用
    转:cookie和session(一)——原理
  • 原文地址:https://www.cnblogs.com/openix/p/3341174.html
Copyright © 2020-2023  润新知