Linux核心初始化高端記憶體的過程(程式碼分析)

來源:互聯網
上載者:User

Linux核心初始化高端記憶體的過程

 

         核心在start_kernel()函數中調用了mem_init()來做所有與記憶體初始化相關的工作。與初始化高端記憶體相關的工作在函數set_highmem_pages_init()中完成。下面我們來詳細分析一下這個過程。

109 void __init set_highmem_pages_init(void)

110 {

111         struct zone *zone;

112         int nid;        

113

114         for_each_zone(zone) {

115                 unsigned long zone_start_pfn, zone_end_pfn;

116

117                 if (!is_highmem(zone))

118                         continue;

119

120                 zone_start_pfn = zone->zone_start_pfn;

121                 zone_end_pfn = zone_start_pfn + zone->spanned_pages;

122

123                 nid = zone_to_nid(zone);

124                 printk(KERN_INFO "Initializing %s for node %d(%08lx:%08lx)\n",

125                                 zone->name, nid, zone_start_pfn, zone_end_pfn);

126

127                 add_highpages_with_active_regions(nid, zone_start_pfn,

128                                  zone_end_pfn);

129         }      

130         totalram_pages += totalhigh_pages;

131 } 

         這個函數首先通過for_each_zone(zone)遍曆所有的zone,以找到高端記憶體管理器。117行的is_highmem(zone)判定zone是否是高端記憶體。如果是則繼續執行120行之後的代碼,否則繼續判斷下一個zone。變數zone_start_pfn與zone_end_pfn表示高端管理區的首位pfn。123行的zone_to_nid(zone)返回zone所在的節點號,即nid。124行輸出高端記憶體相關的資訊。在130行,將初始化後的高端記憶體頁面計入到全域變數totalram_pages中。totalram_pages表示系統中所有的物理頁面數。函數add_highpages_with_active_regions()將完成進一步的工作。

455 void __init add_highpages_with_active_regions(int nid, unsigned long start_pfn,

 456                                               unsigned long end_pfn)

 457 {

 458         struct add_highpages_data data;

 459       

 460         data.start_pfn = start_pfn;

 461         data.end_pfn = end_pfn;

 462       

 463         work_with_active_regions(nid, add_highpages_work_fn, &data);

 464 }

         這個函數將高端管理區的始末pfn封裝在結構add_highpages_data中,然後調用函數work_with_active_regions完成進一步的工作。這裡提出了一個active range的概念,可以將其譯為活動記憶體區。active range是為了描述地址空間中的可用性區域域,排除了地址空間中的空洞。active range儲存在數組early_node_map[MAX_ACTIVE_REGIONS]中。該數組中的每個元素儲存了該active range的始末pfn,以及所屬節點的節點號。函數work_with_active_regions(nid,
add_highpages_work_fn, &data)節點nid中的每個active range均調用一次函數add_highpages_work_fn(),目的是排除高端管理區中的空洞(hole),即那些不可使用的頁面。work_with_active_regions的實現如下:

3427 void __init work_with_active_regions(int nid, work_fn_t work_fn, void *data)

3428 {

3429         int i;

3430         int ret;

3431

3432         for_each_active_range_index_in_nid(i, nid) {

3433                 ret = work_fn(early_node_map[i].start_pfn,

3434                               early_node_map[i].end_pfn, data);

3435                 if (ret)

3436                         break;

3437         }

3438 }

         宏for_each_active_range_index_in_nid即用來遍曆節點nid中的所有active range。early_node_map[i].start_pfn與early_node_map[i].end_pfn表示了當前active range的始末pfn。

         函數add_highpages_work_fn()則對高端記憶體落在當前active range中的頁面進行初始化,其實現如下:

428 static int __init add_highpages_work_fn(unsigned long start_pfn,

 429                                          unsigned long end_pfn, void *datax)

 430 {

 431         int node_pfn;

 432         struct page *page;

 433         unsigned long final_start_pfn, final_end_pfn;

 434         struct add_highpages_data *data;

 435

 436         data = (struct add_highpages_data *)datax;

 437

 438         final_start_pfn = max(start_pfn, data->start_pfn);

 439         final_end_pfn = min(end_pfn, data->end_pfn);

 440         if (final_start_pfn >= final_end_pfn)

 441                return 0;

 442                

 443         for (node_pfn = final_start_pfn; node_pfn < final_end_pfn;

 444             node_pfn++) {

 445                if (!pfn_valid(node_pfn))

 446                         continue;

 447                page = pfn_to_page(node_pfn);

 448                add_one_highpage_init(page, node_pfn);

 449         }

 450                

 451         return 0;

 452                                

 453 }

         438與439行求出了當前active range與高端管理區(由data表示)的交集。443行開始的for迴圈,遍曆了這個交集中的每個頁面。在驗證該頁面的有效性之後,調用add_one_highpage_init()函數將該頁面釋放到夥伴系統中。add_one_highpage_init()函數的實現很簡單:

415 static void __init add_one_highpage_init(struct page *page, int pfn)

 416 {

 417         ClearPageReserved(page);

 418         init_page_count(page);

 419         __free_page(page);

 420         totalhigh_pages++;

 421 }

         ClearPageReserved清除了該頁面flag中的reserved標誌,表示該頁面屬於動態記憶體。init_page_count(page)將該頁面的引用計數初始化為1。__free_page(page)將該頁面真正釋放到夥伴系統中。該函數的第二個參數node_pfn實際上並沒有被用到,這算是該版本核心(2.6.32.2)的一個Bug吧。最新的核心版本中已經沒有這個參數了。

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.