感谢支持
我们一直在努力

Linux物理内存管理区初始化

Linux物理内存管理区在start_kernel函数中进行初始化,此时启动分配器已经建立,所以可以从bootmem中分配需要的内存。


一、全局变量初始化


max_pfn:最大物理页面帧号


start_kernel()->setup_arch()->e820_end_of_ram_pfn()找出最大可用内存页面帧号。


  1. void __init setup_arch(char **cmdline_p)  

  2. {  

  3.     ……  

  4. /* 

  5.      * partially used pages are not usable – thus 

  6.      * we are rounding upwards: 

  7.      */  

  8.     /*遍历e820.map,找到系统中得最大内存数, 

  9.     这个内存数需小于4G*/  

  10.     max_pfn = e820_end_of_ram_pfn();  

  11.     ……  

  12. }  

 


  1. unsigned long __init e820_end_of_ram_pfn(void)  

  2. {  

  3.     /*MAX_ARCH_PFN为4G空间*/  

  4.     return e820_end_pfn(MAX_ARCH_PFN, E820_RAM);  

  5. }  

 


  1. /* 

  2.  * Find the highest page frame number we have available 

  3.  */  

  4. static unsigned long __init e820_end_pfn(unsigned long limit_pfn, unsigned type)  

  5. {  

  6.     int i;  

  7.     unsigned long last_pfn = 0;  

  8.     unsigned long max_arch_pfn = MAX_ARCH_PFN;/*4G地址空间对应的页面数*/  

  9.   

  10.     /*对e820中所有的内存块,其中e820为从bios中探测到的页面数存放处*/  

  11.     for (i = 0; i < e820.nr_map; i++) {  

  12.         struct e820entry *ei = &e820.map[i];/*第i个物理页面块*/  

  13.         unsigned long start_pfn;  

  14.         unsigned long end_pfn;  

  15.   

  16.         if (ei->type != type)/*与找的类型不匹配*/  

  17.             continue;  

  18.         /*起始地址对应的页面帧号*/  

  19.         start_pfn = ei->addr >> PAGE_SHIFT;  

  20.         /*结束物理地址对应的页面帧号*/  

  21.         end_pfn = (ei->addr + ei->size) >> PAGE_SHIFT;  

  22.   

  23.         if (start_pfn >= limit_pfn)  

  24.             continue;  

  25.         if (end_pfn > limit_pfn) {  

  26.             last_pfn = limit_pfn;/*找到的结束页面帧号大于限制大小时*/  

  27.             break;  

  28.         }  

  29.         if (end_pfn > last_pfn)  

  30.             last_pfn = end_pfn;/*保存更新last_pfn*/  

  31.     }  

  32.   

  33.     if (last_pfn > max_arch_pfn)/*大于4G空间时*/  

  34.         last_pfn = max_arch_pfn;  

  35.     /*打印输出信息*/  

  36.     printk(KERN_INFO “last_pfn = %#lx max_arch_pfn = %#lx\n”,  

  37.              last_pfn, max_arch_pfn);  

  38.     /*返回最后一个页面帧号*/  

  39.     return last_pfn;  

  40. }  

max_low_pfn:低端内存最大页面数


start_kernel()->setup_arch()->find_low_pfn_range()


  1. /* 

  2.  * Determine low and high memory ranges: 

  3.  */  

  4. /*找到低端内存的做大内存页面数,初始化两个变量*/  

  5. void __init find_low_pfn_range(void)  

  6. {  

  7.     /* it could update max_pfn */  

  8.     /*当内存的大小本来就小于低端内存的做大页框数时; 

  9.     直接没有高端地址映射*/  

  10.     if (max_pfn <= MAXMEM_PFN)  

  11.         lowmem_pfn_init();  

  12.     else/*这是一般PC机的运行流程,存在高端映射*/  

  13.         highmem_pfn_init();  

  14. }  

我们直接看具有高端地址空间的部分。


  1. /* 

  2.  * We have more RAM than fits into lowmem – we try to put it into 

  3.  * highmem, also taking the highmem=x boot parameter into account: 

  4.  */  

  5.  /*高端地址空间的页面数可以在启动中进行配置; 

  6.  如果不配置,在这里进行设置大小*/  

  7. void __init highmem_pfn_init(void)  

  8. {  

  9.     /*MAXMEM_PFN为最大物理地址-(4M+4M+8K+128M); 

  10.     所以低端内存的大小其实比我们说的896M低一些*/  

  11.     max_low_pfn = MAXMEM_PFN;  

  12.   

  13.     if (highmem_pages == -1)/*高端内存页面数如果在开机没有设置*/  

  14.         highmem_pages = max_pfn – MAXMEM_PFN;/*总页面数减去低端页面数*/  

  15.     /*如果highmem_pages变量在启动项设置了,那么在这里就要进行这样的判断,因为可能出现不一致的情况*/  

  16.     if (highmem_pages + MAXMEM_PFN < max_pfn)  

  17.         max_pfn = MAXMEM_PFN + highmem_pages;  

  18.   

  19.     if (highmem_pages + MAXMEM_PFN > max_pfn) {  

  20.         printk(KERN_WARNING MSG_HIGHMEM_TOO_SMALL,  

  21.             pages_to_mb(max_pfn – MAXMEM_PFN),  

  22.             pages_to_mb(highmem_pages));  

  23.         highmem_pages = 0;  

  24.     }  

  25. #ifndef CONFIG_HIGHMEM   

  26.     /* Maximum memory usable is what is directly addressable */  

  27.     printk(KERN_WARNING “Warning only %ldMB will be used.\n”, MAXMEM>>20);  

  28.     if (max_pfn > MAX_NONPAE_PFN)  

  29.         printk(KERN_WARNING “Use a HIGHMEM64G enabled kernel.\n”);  

  30.     else  

  31.         printk(KERN_WARNING “Use a HIGHMEM enabled kernel.\n”);  

  32.     max_pfn = MAXMEM_PFN;  

  33. #else /* !CONFIG_HIGHMEM *//*存在高端地址情况*/   

  34. #ifndef CONFIG_HIGHMEM64G   

  35.     /*在没有配置64G的情况下,内存的大小不能超过4G*/  

  36.     if (max_pfn > MAX_NONPAE_PFN) {  

  37.         max_pfn = MAX_NONPAE_PFN;  

  38.         printk(KERN_WARNING MSG_HIGHMEM_TRIMMED);  

  39.     }  

  40. #endif /* !CONFIG_HIGHMEM64G */   

  41. #endif /* !CONFIG_HIGHMEM */   

  42. }  

二、管理区初始化


Start_kernl()->setup_arch()->paging_init()->zone_sizes_init()


  1. static void __init zone_sizes_init(void)  

  2. {  

  3.     /*初始化几个内存区中的最大页面数,在后面用于具体的初始化工作*/  

  4.     unsigned long max_zone_pfns[MAX_NR_ZONES];  

  5.     memset(max_zone_pfns, 0, sizeof(max_zone_pfns));  

  6.     max_zone_pfns[ZONE_DMA] =/*DMA区的最大页面帧号,后面的类似*/  

  7.         virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;  

  8.     max_zone_pfns[ZONE_NORMAL] = max_low_pfn;  

  9. #ifdef CONFIG_HIGHMEM   

  10.     max_zone_pfns[ZONE_HIGHMEM] = highend_pfn;  

  11. #endif   

  12.     /*内存体系的MMU建立,包括伙伴系统的初步建立*/  

  13.     free_area_init_nodes(max_zone_pfns);  

  14. }  

其中x86-32 非PAE下MAX_DMA_ADDRESS16M+3G大小

 


  1. /* The maximum address that we can perform a DMA transfer to on this platform */  

  2. #define MAX_DMA_ADDRESS      (PAGE_OFFSET + 0x1000000)  

 


  1. /** 

  2.  * free_area_init_nodes – Initialise all pg_data_t and zone data 

  3.  * @max_zone_pfn: an array of max PFNs for each zone 

  4.  * 

  5.  * This will call free_area_init_node() for each active node in the system. 

  6.  * Using the page ranges provided by add_active_range(), the size of each 

  7.  * zone in each node and their holes is calculated. If the maximum PFN 

  8.  * between two adjacent zones match, it is assumed that the zone is empty. 

  9.  * For example, if arch_max_dma_pfn == arch_max_dma32_pfn, it is assumed 

  10.  * that arch_max_dma32_pfn has no pages. It is also assumed that a zone 

  11.  * starts where the previous one ended. For example, ZONE_DMA32 starts 

  12.  * at arch_max_dma_pfn. 

  13.  */  

  14. void __init free_area_init_nodes(unsigned long *max_zone_pfn)  

  15. {  

  16.     unsigned long nid;  

  17.     int i;  

  18.   

  19.     /* Sort early_node_map as initialisation assumes it is sorted */  

  20.   

  21.     /*将活动区域进行排序,关于活动区域在后面会有介绍*/  

  22.     sort_node_map();  

  23.   

  24.     /* Record where the zone boundaries are */  

  25.     memset(arch_zone_lowest_possible_pfn, 0,  

  26.                 sizeof(arch_zone_lowest_possible_pfn));  

  27.     memset(arch_zone_highest_possible_pfn, 0,  

  28.                 sizeof(arch_zone_highest_possible_pfn));  

  29.       

  30.     /*找出活动内存中最小的页面,在代码中的作者的注释很详细*/  

  31.     arch_zone_lowest_possible_pfn[0] = find_min_pfn_with_active_regions();  

  32.     arch_zone_highest_possible_pfn[0] = max_zone_pfn[0];  

  33.     for (i = 1; i < MAX_NR_ZONES; i++) {  

  34.         if (i == ZONE_MOVABLE)  

  35.             continue;  

  36.         arch_zone_lowest_possible_pfn[i] =  

  37.             arch_zone_highest_possible_pfn[i-1];/*假定区域连续,下一个区域的最小页面为上一个区的最后页面*/  

  38.         arch_zone_highest_possible_pfn[i] =  

  39.             max(max_zone_pfn[i], arch_zone_lowest_possible_pfn[i]);  

  40.     }  

  41.     /*对ZONE_MOVABLE区域设置为0*/  

  42.     arch_zone_lowest_possible_pfn[ZONE_MOVABLE] = 0;  

  43.     arch_zone_highest_possible_pfn[ZONE_MOVABLE] = 0;  

  44.   

  45.     /* Find the PFNs that ZONE_MOVABLE begins at in each node */  

  46.     memset(zone_movable_pfn, 0, sizeof(zone_movable_pfn));  

  47.     find_zone_movable_pfns_for_nodes(zone_movable_pfn);/*找出每个区的movable的页面数,关于movable为新引入的机制,在后面的文章中会对其详细分析*/  

  48.   

  49.     /* Print out the zone ranges */  

  50.     printk(“Zone PFN ranges:\n”);  

  51.     for (i = 0; i < MAX_NR_ZONES; i++) {  

  52.         if (i == ZONE_MOVABLE)  

  53.             continue;  

  54.         printk(”  %-8s %0#10lx -> %0#10lx\n”,  

  55.                 zone_names[i],  

  56.                 arch_zone_lowest_possible_pfn[i],  

  57.                 arch_zone_highest_possible_pfn[i]);  

  58.     }  

  59.   

  60.     /* Print out the PFNs ZONE_MOVABLE begins at in each node */  

  61.     printk(“Movable zone start PFN for each node\n”);  

  62.     for (i = 0; i < MAX_NUMNODES; i++) {  

  63.         if (zone_movable_pfn[i])  

  64.             printk(”  Node %d: %lu\n”, i, zone_movable_pfn[i]);  

  65.     }  

  66.   

  67.     /* Print out the early_node_map[] */  

  68.     printk(“early_node_map[%d] active PFN ranges\n”, nr_nodemap_entries);  

  69.     for (i = 0; i < nr_nodemap_entries; i++)  

  70.         printk(”  %3d: %0#10lx -> %0#10lx\n”, early_node_map[i].nid,  

  71.                         early_node_map[i].start_pfn,  

  72.                         early_node_map[i].end_pfn);  

  73.   

  74.     /* Initialise every node */  

  75.     /*调试用*/  

  76.     mminit_verify_pageflags_layout();  

  77.     setup_nr_node_ids();  

  78.       

  79.     for_each_online_node(nid) {  

  80.         pg_data_t *pgdat = NODE_DATA(nid);  

  81.           

  82.     /*zone中数据的初始化,伙伴系统建立但是没有页面 

  83.         和数据,页面在后面的mem_init中得到*/  

  84.         free_area_init_node(nid, NULL,  

  85.                 find_min_pfn_for_node(nid), NULL);  

  86.   

  87.         /* Any memory on that node */  

  88.         if (pgdat->node_present_pages)  

  89.             node_set_state(nid, N_HIGH_MEMORY);  

  90.     /*内存的相关检查*/  

  91.         check_for_regular_memory(pgdat);  

  92.     }  

  93. }  

 


  1. void __paginginit free_area_init_node(int nid, unsigned long *zones_size,  

  2.         unsigned long node_start_pfn, unsigned long *zholes_size)  

  3. {  

  4.     pg_data_t *pgdat = NODE_DATA(nid);  

  5.   

  6.     pgdat->node_id = nid;  

  7.     pgdat->node_start_pfn = node_start_pfn;/*这个在前面调用一个函数得到*/  

  8.     /*计算系统中节点nid的所有物理页面保存在数据结构中*/  

  9.     calculate_node_totalpages(pgdat, zones_size, zholes_size);  

  10.     /*当节点只有一个时,将节点的map保存到全局变量中*/  

  11.     alloc_node_mem_map(pgdat);  

  12. #ifdef CONFIG_FLAT_NODE_MEM_MAP   

  13.     printk(KERN_DEBUG “free_area_init_node: node %d, pgdat %08lx, node_mem_map %08lx\n”,  

  14.         nid, (unsigned long)pgdat,  

  15.         (unsigned long)pgdat->node_mem_map);  

  16. #endif   

  17.     /*zone中相关数据的初始化,包括伙伴系统,等待队列,相关变量, 

  18.     数据结构、链表等;*/  

  19.     free_area_init_core(pgdat, zones_size, zholes_size);  

  20. }  

具体的区域的初始化在下面函数进行


  1. /* 

  2.  * Set up the zone data structures: 

  3.  *   – mark all pages reserved 

  4.  *   – mark all memory queues empty 

  5.  *   – clear the memory bitmaps 

  6.  */  

  7. static void __paginginit free_area_init_core(struct pglist_data *pgdat,  

  8.         unsigned long *zones_size, unsigned long *zholes_size)  

  9. {  

  10.     enum zone_type j;  

  11.     int nid = pgdat->node_id;  

  12.     unsigned long zone_start_pfn = pgdat->node_start_pfn;  

  13.     int ret;  

  14.   

  15.     pgdat_resize_init(pgdat);  

  16.     pgdat->nr_zones = 0;  

  17.     init_waitqueue_head(&pgdat->kswapd_wait);  

  18.     pgdat->kswapd_max_order = 0;  

  19.     pgdat_page_cgroup_init(pgdat);  

  20.       

  21.     for (j = 0; j < MAX_NR_ZONES; j++) {  

  22.         struct zone *zone = pgdat->node_zones + j;  

  23.         unsigned long size, realsize, memmap_pages;  

  24.         enum lru_list l;  

  25.     /*下面的两个函数会获得指定节点的真实内存大小*/  

  26.         size = zone_spanned_pages_in_node(nid, j, zones_size);  

  27.         realsize = size – zone_absent_pages_in_node(nid, j,  

  28.                                 zholes_size);  

  29.   

  30.         /* 

  31.          * Adjust realsize so that it accounts for how much memory 

  32.          * is used by this zone for memmap. This affects the watermark 

  33.          * and per-cpu initialisations 

  34.          */  

  35.         memmap_pages =/*存放页面所需要的内存大小*/  

  36.             PAGE_ALIGN(size * sizeof(struct page)) >> PAGE_SHIFT;  

  37.         if (realsize >= memmap_pages) {  

  38.             realsize -= memmap_pages;  

  39.             if (memmap_pages)  

  40.                 printk(KERN_DEBUG  

  41.                        ”  %s zone: %lu pages used for memmap\n”,  

  42.                        zone_names[j], memmap_pages);  

  43.         } else  

  44.             printk(KERN_WARNING  

  45.                 ”  %s zone: %lu pages exceeds realsize %lu\n”,  

  46.                 zone_names[j], memmap_pages, realsize);  

  47.   

  48.         /* Account for reserved pages */  

  49.         if (j == 0 && realsize > dma_reserve) {  

  50.             realsize -= dma_reserve;/*减去为DMA保留的页面*/  

  51.             printk(KERN_DEBUG ”  %s zone: %lu pages reserved\n”,  

  52.                     zone_names[0], dma_reserve);  

  53.         }  

  54.   

  55.         if (!is_highmem_idx(j))/*如果不是高端内存区*/                                    nr_kernel_pages += realsize;  

  56.         nr_all_pages += realsize;  

  57.     /*下面为初始化zone结构的相关变量*/  

  58.         zone->spanned_pages = size;  

  59.         zone->present_pages = realsize;  

  60. #ifdef CONFIG_NUMA   

  61.         zone->node = nid;  

  62.         zone->min_unmapped_pages = (realsize*sysctl_min_unmapped_ratio)  

  63.                         / 100;  

  64.         zone->min_slab_pages = (realsize * sysctl_min_slab_ratio) / 100;  

  65. #endif   

  66.         zone->name = zone_names[j];  

  67.         spin_lock_init(&zone->lock);  

  68.         spin_lock_init(&zone->lru_lock);  

  69.         zone_seqlock_init(zone);  

  70.         zone->zone_pgdat = pgdat;  

  71.   

  72.         zone->prev_priority = DEF_PRIORITY;  

  73.   

  74.         zone_pcp_init(zone);  

  75.         for_each_lru(l) {//初始化链表   

  76.             INIT_LIST_HEAD(&zone->lru[l].list);  

  77.             zone->reclaim_stat.nr_saved_scan[l] = 0;  

  78.         }  

  79.         zone->reclaim_stat.recent_rotated[0] = 0;  

  80.         zone->reclaim_stat.recent_rotated[1] = 0;  

  81.         zone->reclaim_stat.recent_scanned[0] = 0;  

  82.         zone->reclaim_stat.recent_scanned[1] = 0;  

  83.         zap_zone_vm_stats(zone);/*将变量zone->vm_stat变量置0*/  

  84.         zone->flags = 0;  

  85.         if (!size)  

  86.             continue;  

  87.     /*需要定义相关宏该版本没定义*/  

  88.         set_pageblock_order(pageblock_default_order());  

  89.     /zone中变量pageblock_flags内存申请,从启动分配器中*/  

  90.         setup_usemap(pgdat, zone, size);  

  91.     /*zone中的任务等待队列和zone的伙伴系统(MAX_ORDER个链表)的初始化,关于伙伴系统将单独在后面总结*/  

  92.         ret = init_currently_empty_zone(zone, zone_start_pfn,  

  93.                         size, MEMMAP_EARLY);  

  94.         BUG_ON(ret);  

  95.         /*zone中page相关属性的初始化工作*/  

  96.         memmap_init(size, nid, j, zone_start_pfn);  

  97.         zone_start_pfn += size;  

  98.     }  

  99. }  

三、分配内存的备用区域初始化(CONFIG_NUMA


数据结构表示


  1. x;      /* zone_idx(zoneref->zone) */  

  2. };  

  3.   

  4. /* 

  5.  * One allocation request operates on a zonelist. A zonelist 

  6.  * is a list of zones, the first one is the ‘goal’ of the 

  7.  * allocation, the other zones are fallback zones, in decreasing 

  8.  * priority. 

  9.  * 

  10.  * If zlcache_ptr is not NULL, then it is just the address of zlcache, 

  11.  * as explained above.  If zlcache_ptr is NULL, there is no zlcache. 

  12.  * * 

  13.  * To speed the reading of the zonelist, the zonerefs contain the zone index 

  14.  * of the entry being read. Helper functions to access information given 

  15.  * a struct zoneref are 

  16.  * 

  17.  * zonelist_zone()  – Return the struct zone * for an entry in _zonerefs 

  18.  * zonelist_zone_idx()  – Return the index of the zone for an entry 

  19.  * zonelist_node_idx()  – Return the index of the node for an entry 

  20.  *///zone分配方案  

  21. struct zonelist {  

  22.     struct zonelist_cache *zlcache_ptr;          // NULL or &zlcache   

  23.     struct zoneref _zonerefs[MAX_ZONES_PER_ZONELIST + 1];  

  24. #ifdef CONFIG_NUMA   

  25.     struct zonelist_cache zlcache;               // optional …   

  26. #endif   

  27. };  

代码中的英文注释很详细了


初始化


Start_kernel()->build_all_zonelists()

 


  1. void build_all_zonelists(void)  

  2. {  

  3.     /*设置全局变量current_zonelist_order*/  

  4.     set_zonelist_order();  

  5.   

  6.     if (system_state == SYSTEM_BOOTING) {  

  7.     /*对所有节点创建zonelists*/  

  8.         __build_all_zonelists(NULL);  

  9.     /*调试用*/  

  10.         mminit_verify_zonelist();  

  11.         cpuset_init_current_mems_allowed();  

  12.     } else {  

  13.         /* we have to stop all cpus to guarantee there is no user 

  14.            of zonelist */  

  15.         stop_machine(__build_all_zonelists, NULL, NULL);  

  16.         /* cpuset refresh routine should be here */  

  17.     }  

  18.     /*计算所有zone中可分配的页面数之和*/  

  19.     vm_total_pages = nr_free_pagecache_pages();  

  20.     /* 

  21.      * Disable grouping by mobility if the number of pages in the 

  22.      * system is too low to allow the mechanism to work. It would be 

  23.      * more accurate, but expensive to check per-zone. This check is 

  24.      * made on memory-hotadd so a system can start with mobility 

  25.      * disabled and enable it later 

  26.      */  

  27.     if (vm_total_pages < (pageblock_nr_pages * MIGRATE_TYPES))  

  28.         page_group_by_mobility_disabled = 1;  

  29.     else  

  30.         page_group_by_mobility_disabled = 0;  

  31.   

  32.     printk(“Built %i zonelists in %s order, mobility grouping %s.  “  

  33.         “Total pages: %ld\n”,  

  34.             nr_online_nodes,  

  35.             zonelist_order_name[current_zonelist_order],  

  36.             page_group_by_mobility_disabled ? “off” : “on”,  

  37.             vm_total_pages);  

  38. #ifdef CONFIG_NUMA   

  39.     printk(“Policy zone: %s\n”, zone_names[policy_zone]);  

  40. #endif   

  41. }  

 


  1. /* return values int ….just for stop_machine() */  

  2. static int __build_all_zonelists(void *dummy)  

  3. {  

  4.     int nid;  

  5.   

  6. #ifdef CONFIG_NUMA   

  7.     memset(node_load, 0, sizeof(node_load));  

  8. #endif   

  9.     for_each_online_node(nid) {  

  10.         pg_data_t *pgdat = NODE_DATA(nid);  

  11.     /*创建zonelists,这个数组用来在分配内存中坐回绕,循环访问*/  

  12.         build_zonelists(pgdat);  

  13.     /*在UMA中,这个仅仅是把相关的变量设置成了NULL*/  

  14.         build_zonelist_cache(pgdat);  

  15.     }  

  16.     return 0;  

  17. }  

 


  1. static void build_zonelists(pg_data_t *pgdat)  

  2. {  

  3.     int node, local_node;  

  4.     enum zone_type j;  

  5.     struct zonelist *zonelist;  

  6.   

  7.     local_node = pgdat->node_id;  

  8.   

  9.     zonelist = &pgdat->node_zonelists[0];  

  10.     /*将zone添加到zone链表中,这样,zone中page的 

  11.     分配等操作将依靠这个环形的链表;*/  

  12.     j = build_zonelists_node(pgdat, zonelist, 0, MAX_NR_ZONES – 1);  

  13.   

  14.     /* 

  15.      * Now we build the zonelist so that it contains the zones 

  16.      * of all the other nodes. 

  17.      * We don’t want to pressure a particular node, so when 

  18.      * building the zones for node N, we make sure that the 

  19.      * zones coming right after the local ones are those from 

  20.      * node N+1 (modulo N) 

  21.      *//*对其他在线的节点创建zonelist*/  

  22.     for (node = local_node + 1; node < MAX_NUMNODES; node++) {  

  23.         if (!node_online(node))  

  24.             continue;  

  25.         j = build_zonelists_node(NODE_DATA(node), zonelist, j,  

  26.                             MAX_NR_ZONES – 1);  

  27.     }  

  28.     for (node = 0; node < local_node; node++) {  

  29.         if (!node_online(node))  

  30.             continue;  

  31.         j = build_zonelists_node(NODE_DATA(node), zonelist, j,  

  32.                             MAX_NR_ZONES – 1);  

  33.     }  

  34.   

  35.     zonelist->_zonerefs[j].zone = NULL;  

  36.     zonelist->_zonerefs[j].zone_idx = 0;  

  37. }  

 


  1. /* 

  2.  * Builds allocation fallback zone lists. 

  3.  * 

  4.  * Add all populated zones of a node to the zonelist. 

  5.  */  

  6. static int build_zonelists_node(pg_data_t *pgdat, struct zonelist *zonelist,  

  7.                 int nr_zones, enum zone_type zone_type)  

  8. {  

  9.     struct zone *zone;  

  10.   

  11.     BUG_ON(zone_type >= MAX_NR_ZONES);  

  12.     zone_type++;  

  13.   

  14.     do {  

  15.         zone_type–;  

  16.         zone = pgdat->node_zones + zone_type;  

  17.         if (populated_zone(zone)) {/*如果以页面为单位的管理区的总大小不为0*/  

  18.             zoneref_set_zone(zone,/*设置管理区链表,将相关信息加入*/  

  19.                 &zonelist->_zonerefs[nr_zones++]);  

  20.             check_highest_zone(zone_type);  

  21.         }  

  22.   

  23.     } while (zone_type);  

  24.     return nr_zones;  

  25. }  

内存管理区初始化主要是借助于启动分配器和以初始化的e820全局变量。内存管理区初始化后相应的伙伴系统、slab机制等等就可以在此基础上建立了,在后面会一点一点总结。

赞(0) 打赏
转载请注明出处:服务器评测 » Linux物理内存管理区初始化
分享到: 更多 (0)

听说打赏我的人,都进福布斯排行榜啦!

支付宝扫一扫打赏

微信扫一扫打赏