linux内核工程师 3.03节 Linux伙伴系统(二)--伙伴系统的初始化

伙伴系统的初始化主要是初始化之前介绍的伙伴系统涉及到的数据结构,并且把系统初始化时由bootmem allocator管理的低端内存以及系统的高端内存释放到伙伴系统中去。其中有些和zone相关的域在前面<<Linux节点和内存管理区的初始化>>中已经有所介绍。

        在start_kernel()-->paging_init()-->zone_sizes_init()-->free_area_init_nodes()-->free_area_init_node()-->free_area_init_core()-->init_currently_empty_zone()-->zone_init_free_lists()中,free_area的相关域都被初始化

[cpp]  view plain  copy
  1. static void __meminit zone_init_free_lists(struct zone *zone)  
  2. {  
  3.     int order, t;  
  4.     for_each_migratetype_order(order, t) {  
  5.         /*链表初始化为空链表*/  
  6.         INIT_LIST_HEAD(&zone->free_area[order].free_list[t]);  
  7.         /*内存块数量初始化为0*/  
  8.         zone->free_area[order].nr_free = 0;  
  9.     }  
  10. }  


for_each_migratetype_order(order, t)就是两个嵌套的for循环

[cpp]  view plain  copy
  1. #define for_each_migratetype_order(order, type) \  
  2.     for (order = 0; order < MAX_ORDER; order++) \  
  3.         for (type = 0; type < MIGRATE_TYPES; type++)  


start_kernel()-->mm_init()-->mem_init(),负责统计所有可用的低端内存和高端内存,并释放到伙伴系统中

<Init_32.c>

[cpp]  view plain  copy
  1. void __init mem_init(void)  
  2. {  
  3.     int codesize, reservedpages, datasize, initsize;  
  4.     int tmp;  
  5.   
  6.     pci_iommu_alloc();  
  7.   
  8. #ifdef CONFIG_FLATMEM  
  9.     BUG_ON(!mem_map);  
  10. #endif  
  11.     /* this will put all low memory onto the freelists */  
  12.      /*销毁bootmem分配器,释放bootmem分配器管理的空闲页框和bootmem的位图所占用的页框, 
  13.          并计入totalram_pages*/  
  14.     totalram_pages += free_all_bootmem();  
  15.   
  16.     reservedpages = 0;  
  17.     for (tmp = 0; tmp < max_low_pfn; tmp++)  
  18.         /* 
  19.          * Only count reserved RAM pages: 
  20.          */  
  21.         if (page_is_ram(tmp) && PageReserved(pfn_to_page(tmp)))  
  22.             reservedpages++;  
  23.   
  24.     /*处理高端内存页框*/  
  25.     set_highmem_pages_init();  
  26.   
  27.     codesize =  (unsigned long) &_etext - (unsigned long) &_text;  
  28.     datasize =  (unsigned long) &_edata - (unsigned long) &_etext;  
  29.     initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;  
  30.   
  31.     printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, "  
  32.             "%dk reserved, %dk data, %dk init, %ldk highmem)\n",  
  33.         nr_free_pages() << (PAGE_SHIFT-10),  
  34.         num_physpages << (PAGE_SHIFT-10),  
  35.         codesize >> 10,  
  36.         reservedpages << (PAGE_SHIFT-10),  
  37.         datasize >> 10,  
  38.         initsize >> 10,  
  39.         (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10))  
  40.            );  
  41.   
  42.     printk(KERN_INFO "virtual kernel memory layout:\n"  
  43.         "    fixmap  : 0x%08lx - 0x%08lx   (%4ld kB)\n"  
  44. #ifdef CONFIG_HIGHMEM  
  45.         "    pkmap   : 0x%08lx - 0x%08lx   (%4ld kB)\n"  
  46. #endif  
  47.         "    vmalloc : 0x%08lx - 0x%08lx   (%4ld MB)\n"  
  48.         "    lowmem  : 0x%08lx - 0x%08lx   (%4ld MB)\n"  
  49.         "      .init : 0x%08lx - 0x%08lx   (%4ld kB)\n"  
  50.         "      .data : 0x%08lx - 0x%08lx   (%4ld kB)\n"  
  51.         "      .text : 0x%08lx - 0x%08lx   (%4ld kB)\n",  
  52.         FIXADDR_START, FIXADDR_TOP,  
  53.         (FIXADDR_TOP - FIXADDR_START) >> 10,  
  54.   
  55. #ifdef CONFIG_HIGHMEM  
  56.         PKMAP_BASE, PKMAP_BASE+LAST_PKMAP*PAGE_SIZE,  
  57.         (LAST_PKMAP*PAGE_SIZE) >> 10,  
  58. #endif  
  59.   
  60.         VMALLOC_START, VMALLOC_END,  
  61.         (VMALLOC_END - VMALLOC_START) >> 20,  
  62.   
  63.         (unsigned long)__va(0), (unsigned long)high_memory,  
  64.         ((unsigned long)high_memory - (unsigned long)__va(0)) >> 20,  
  65.   
  66.         (unsigned long)&__init_begin, (unsigned long)&__init_end,  
  67.         ((unsigned long)&__init_end -  
  68.          (unsigned long)&__init_begin) >> 10,  
  69.   
  70.         (unsigned long)&_etext, (unsigned long)&_edata,  
  71.         ((unsigned long)&_edata - (unsigned long)&_etext) >> 10,  
  72.   
  73.         (unsigned long)&_text, (unsigned long)&_etext,  
  74.         ((unsigned long)&_etext - (unsigned long)&_text) >> 10);  
  75.   
  76.     /* 
  77.      * Check boundaries twice: Some fundamental inconsistencies can 
  78.      * be detected at build time already. 
  79.      */  
  80. #define __FIXADDR_TOP (-PAGE_SIZE)  
  81. #ifdef CONFIG_HIGHMEM  
  82.     BUILD_BUG_ON(PKMAP_BASE + LAST_PKMAP*PAGE_SIZE  > FIXADDR_START);  
  83.     BUILD_BUG_ON(VMALLOC_END            > PKMAP_BASE);  
  84. #endif  
  85. #define high_memory (-128UL << 20)  
  86.     BUILD_BUG_ON(VMALLOC_START          >= VMALLOC_END);  
  87. #undef high_memory  
  88. #undef __FIXADDR_TOP  
  89.   
  90. #ifdef CONFIG_HIGHMEM  
  91.     BUG_ON(PKMAP_BASE + LAST_PKMAP*PAGE_SIZE    > FIXADDR_START);  
  92.     BUG_ON(VMALLOC_END              > PKMAP_BASE);  
  93. #endif  
  94.     BUG_ON(VMALLOC_START                >= VMALLOC_END);  
  95.     BUG_ON((unsigned long)high_memory       > VMALLOC_START);  
  96.   
  97.     if (boot_cpu_data.wp_works_ok < 0)  
  98.         test_wp_bit();  
  99.   
  100.     save_pg_dir();  
  101.     /*将前3GB线性地址(即用户地址空间)对应的pgd全局目录项清空*/  
  102.     zap_low_mappings(true);  
  103. }  


 

free_all_bootmem()的核心函数在<<bootmem allocator>>中已有介绍,这里不再列出

 

<Highmem_32.c>

[cpp]  view plain  copy
  1. void __init set_highmem_pages_init(void)  
  2. {  
  3.     struct zone *zone;  
  4.     int nid;  
  5.   
  6.     for_each_zone(zone) {/*遍历每个管理区*/  
  7.         unsigned long zone_start_pfn, zone_end_pfn;  
  8.   
  9.         if (!is_highmem(zone))/*判断是否是高端内存管理区*/  
  10.             continue;  
  11.   
  12.         /*记录高端内存管理区的起始页框号和结束页框号*/  
  13.         zone_start_pfn = zone->zone_start_pfn;  
  14.         zone_end_pfn = zone_start_pfn + zone->spanned_pages;  
  15.   
  16.         nid = zone_to_nid(zone);  
  17.         printk(KERN_INFO "Initializing %s for node %d (%08lx:%08lx)\n",  
  18.                 zone->name, nid, zone_start_pfn, zone_end_pfn);  
  19.   
  20.         /*将高端内存的页框添加到伙伴系统*/  
  21.         add_highpages_with_active_regions(nid, zone_start_pfn,  
  22.                  zone_end_pfn);  
  23.     }  
  24.     /*将释放到伙伴系统的高端内存页框数计入totalram_pages*/  
  25.     totalram_pages += totalhigh_pages;  
  26. }  


 

[cpp]  view plain  copy
  1. void __init add_highpages_with_active_regions(int nid, unsigned long start_pfn,  
  2.                           unsigned long end_pfn)  
  3. {  
  4.     struct add_highpages_data data;  
  5.   
  6.     data.start_pfn = start_pfn;  
  7.     data.end_pfn = end_pfn;  
  8.   
  9.     /*遍历所有的活动区,调用add_highpages_word_fn()来处理每个活动区*/  
  10.     work_with_active_regions(nid, add_highpages_work_fn, &data);  
  11. }  


 

扫描二维码关注公众号,回复: 1597131 查看本文章
[cpp]  view plain  copy
  1. <span style="font-size:12px;">void __init work_with_active_regions(int nid, work_fn_t work_fn, void *data)  
  2. {  
  3.     int i;  
  4.     int ret;  
  5.   
  6.     for_each_active_range_index_in_nid(i, nid) {  
  7.         ret = work_fn(early_node_map[i].start_pfn,  
  8.                   early_node_map[i].end_pfn, data);  
  9.         if (ret)  
  10.             break;  
  11.     }  
  12. }</span>  

 

[cpp]  view plain  copy
  1. <span style="font-size:12px;">static int __init add_highpages_work_fn(unsigned long start_pfn,  
  2.                      unsigned long end_pfn, void *datax)  
  3. {  
  4.     int node_pfn;  
  5.     struct page *page;  
  6.     unsigned long final_start_pfn, final_end_pfn;  
  7.     struct add_highpages_data *data;  
  8.   
  9.     data = (struct add_highpages_data *)datax;  
  10.   
  11.     /*得到合理的起始结束页框号*/  
  12.     final_start_pfn = max(start_pfn, data->start_pfn);  
  13.     final_end_pfn = min(end_pfn, data->end_pfn);  
  14.     if (final_start_pfn >= final_end_pfn)  
  15.         return 0;  
  16.   
  17.     /*遍历活动区的页框*/  
  18.     for (node_pfn = final_start_pfn; node_pfn < final_end_pfn;  
  19.          node_pfn++) {  
  20.         if (!pfn_valid(node_pfn))  
  21.             continue;  
  22.         page = pfn_to_page(node_pfn);  
  23.         add_one_highpage_init(page, node_pfn);/*将该页框添加到伙伴系统*/  
  24.     }  
  25.   
  26.     return 0;  
  27.   
  28. }  
  29. </span>  


 

[cpp]  view plain  copy
  1. <span style="font-size:12px;">static void __init add_one_highpage_init(struct page *page, int pfn)  
  2. {  
  3.     ClearPageReserved(page);  
  4.     init_page_count(page);/*count初始化为1*/  
  5.     __free_page(page);     /*释放page到伙伴系统*/  
  6.     totalhigh_pages++;      /*高端内存的页数加1*/  
  7. }</span>  


__free_page()中涉及到的具体操作在后面介绍伙伴系统释放页面时再做分析

 

 

在free_area_init_core()-->memmap_init()(-->memmap_init_zone() )-->set_pageblock_migratetype(),将每个pageblock的起始页框对应的struct zone当中的pageblock_flags代表的位图相关区域标记为可移动的,表示该pageblock为可移动的,也就是说内核初始化伙伴系统时,所有的页都被标记为可移动的

[cpp]  view plain  copy
  1. <span style="font-size:12px;">void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone,  
  2.         unsigned long start_pfn, enum memmap_context context)  
  3. {  
  4.     struct page *page;  
  5.     unsigned long end_pfn = start_pfn + size;  
  6.     unsigned long pfn;  
  7.     struct zone *z;  
  8.   
  9.     if (highest_memmap_pfn < end_pfn - 1)  
  10.         highest_memmap_pfn = end_pfn - 1;  
  11.   
  12.     z = &NODE_DATA(nid)->node_zones[zone];  
  13.     for (pfn = start_pfn; pfn < end_pfn; pfn++) {  
  14.         /* 
  15.          * There can be holes in boot-time mem_map[]s 
  16.          * handed to this function.  They do not 
  17.          * exist on hotplugged memory. 
  18.          */  
  19.         if (context == MEMMAP_EARLY) {  
  20.             if (!early_pfn_valid(pfn))  
  21.                 continue;  
  22.             if (!early_pfn_in_nid(pfn, nid))  
  23.                 continue;  
  24.         }  
  25.         page = pfn_to_page(pfn);  
  26.         set_page_links(page, zone, nid, pfn);  
  27.         mminit_verify_page_links(page, zone, nid, pfn);  
  28.         init_page_count(page);  
  29.         reset_page_mapcount(page);  
  30.         SetPageReserved(page);  
  31.         /* 
  32.          * Mark the block movable so that blocks are reserved for 
  33.          * movable at startup. This will force kernel allocations 
  34.          * to reserve their blocks rather than leaking throughout 
  35.          * the address space during boot when many long-lived 
  36.          * kernel allocations are made. Later some blocks near 
  37.          * the start are marked MIGRATE_RESERVE by 
  38.          * setup_zone_migrate_reserve() 
  39.          * 
  40.          * bitmap is created for zone's valid pfn range. but memmap 
  41.          * can be created for invalid pages (for alignment) 
  42.          * check here not to call set_pageblock_migratetype() against 
  43.          * pfn out of zone. 
  44.          */  
  45.          /*如果pfn处在合理的范围,并且该pfn是一个pageblock的起始页框号*/  
  46.         if ((z->zone_start_pfn <= pfn)  
  47.             && (pfn < z->zone_start_pfn + z->spanned_pages)  
  48.             && !(pfn & (pageblock_nr_pages - 1)))  
  49.             set_pageblock_migratetype(page, MIGRATE_MOVABLE);/*将页框对应的位图域标记为可移动的*/  
  50.   
  51.         INIT_LIST_HEAD(&page->lru);  
  52. #ifdef WANT_PAGE_VIRTUAL  
  53.         /* The shift won't overflow because ZONE_NORMAL is below 4G. */  
  54.         if (!is_highmem_idx(zone))  
  55.             set_page_address(page, __va(pfn << PAGE_SHIFT));  
  56. #endif  
  57.     }  
  58. }  
  59. </span>  


    

 

[cpp]  view plain  copy
  1. <span style="font-size:12px;">static void set_pageblock_migratetype(struct page *page, int migratetype)  
  2. {  
  3.   
  4.     /*如果没有开启移动性分类,则所有页都要标记为不可移动的*/  
  5.     if (unlikely(page_group_by_mobility_disabled))  
  6.         migratetype = MIGRATE_UNMOVABLE;  
  7.       
  8.     set_pageblock_flags_group(page, (unsigned long)migratetype,  
  9.                     PB_migrate, PB_migrate_end);  
  10. }  
  11. </span>  


 

[cpp]  view plain  copy
  1. void set_pageblock_flags_group(struct page *page, unsigned long flags,  
  2.                     int start_bitidx, int end_bitidx)  
  3. {  
  4.     struct zone *zone;  
  5.     unsigned long *bitmap;  
  6.     unsigned long pfn, bitidx;  
  7.     unsigned long value = 1;  
  8.   
  9.     zone = page_zone(page);  
  10.     pfn = page_to_pfn(page);  
  11.     /*得到位图的起始地址,即zone->pageblock_flags*/  
  12.     bitmap = get_pageblock_bitmap(zone, pfn);  
  13.     /*得到pfn对应的位图区域的偏移量*/  
  14.     bitidx = pfn_to_bitidx(zone, pfn);  
  15.     VM_BUG_ON(pfn < zone->zone_start_pfn);  
  16.     VM_BUG_ON(pfn >= zone->zone_start_pfn + zone->spanned_pages);  
  17.   
  18.     /*每个页都需要3个bit来表征其移动性,也就是从start_bitidx到end_bitidx共3位*/  
  19.     for (; start_bitidx <= end_bitidx; start_bitidx++, value <<= 1)  
  20.         if (flags & value)/*通过flags和value相与确定相关的位是否为1*/  
  21.             __set_bit(bitidx + start_bitidx, bitmap);  
  22.         else  
  23.             __clear_bit(bitidx + start_bitidx, bitmap);  
  24. }  

猜你喜欢

转载自blog.csdn.net/zjy900507/article/details/80682531