paging_init()の続きで残りの2行を。。
node_clear_state()は特に見るほどではないのでzone_sizes_init()を見る。
650 void __init paging_init(void) 651 { 652 sparse_memory_present_with_active_regions(MAX_NUMNODES); 653 sparse_init(); 654 655 /* 656 * clear the default setting with node 0 657 * note: don't use nodes_clear here, that is really clearing when 658 * numa support is not compiled in, and later node_set_state 659 * will not set it back. 660 */ 661 node_clear_state(0, N_MEMORY); 662 if (N_MEMORY != N_NORMAL_MEMORY) 663 node_clear_state(0, N_NORMAL_MEMORY); 664 665 zone_sizes_init(); 666 }
zone_sizes_init()はarch/x86/mm/init.cにある関数でZONE_NORMALとかZONE_DMA32といったゾーンに関する初期化をする。
663 void __init zone_sizes_init(void) 664 { 665 unsigned long max_zone_pfns[MAX_NR_ZONES]; 666 667 memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); 668 669 #ifdef CONFIG_ZONE_DMA 670 max_zone_pfns[ZONE_DMA] = MAX_DMA_PFN; 671 #endif 672 #ifdef CONFIG_ZONE_DMA32 673 max_zone_pfns[ZONE_DMA32] = MAX_DMA32_PFN; 674 #endif 675 max_zone_pfns[ZONE_NORMAL] = max_low_pfn; 676 #ifdef CONFIG_HIGHMEM 677 max_zone_pfns[ZONE_HIGHMEM] = max_pfn; 678 #endif 679 680 free_area_init_nodes(max_zone_pfns); 681 }
配列のサイズに使っているMAX_NR_ZONESはinclude/generated/bounds.hにあって、このファイルはビルド時に作られているらしいのでlxrでも見つからない。 このファイルを見るとゾーンは最大4個というのがわかる。あとはCONFIG_HIGHMEMはx86_64(32bit環境と違って)では使わないので使われるゾーンはZONE_DMA、ZONE_DMA32、ZONE_NORMALの3種類。
#ifndef __LINUX_BOUNDS_H__ #define __LINUX_BOUNDS_H__ /* * DO NOT MODIFY. * * This file was generated by Kbuild * */ #define NR_PAGEFLAGS 25 /* __NR_PAGEFLAGS # */ #define MAX_NR_ZONES 4 /* __MAX_NR_ZONES # */ #define NR_PCG_FLAGS 3 /* __NR_PCG_FLAGS # */ #define NR_CPUS_BITS 7 /* ilog2(CONFIG_NR_CPUS) # */ #define SPINLOCK_SIZE 2 /* sizeof(spinlock_t) # */ #endif
最初に変数の初期化処理がいくつか。
5177 void __init free_area_init_nodes(unsigned long *max_zone_pfn) 5178 { 5179 unsigned long start_pfn, end_pfn; 5180 int i, nid; 5181 5182 /* Record where the zone boundaries are */ 5183 memset(arch_zone_lowest_possible_pfn, 0, 5184 sizeof(arch_zone_lowest_possible_pfn)); 5185 memset(arch_zone_highest_possible_pfn, 0, 5186 sizeof(arch_zone_highest_possible_pfn));
arch_zone_lowest_possible_pfn、arch_zone_highest_possible_pfnはstaticな変数でfree_area_init_nodes()と同じくmm/page_alloc.cにある。
215 static unsigned long __meminitdata arch_zone_lowest_possible_pfn[MAX_NR_ZONES]; 216 static unsigned long __meminitdata arch_zone_highest_possible_pfn[MAX_NR_ZONES];
find_min_pfn_with_active_regions()は全NUMAノードから最小のページフレーム番号を探す処理。 arch_zone_highest_possible_pfnは通常はZONE_DMAですね。ちなみにZONE_XXXはマクロじゃなくてenum。include/linux/mmzone.hに定義があります。
5187 arch_zone_lowest_possible_pfn[0] = find_min_pfn_with_active_regions(); 5188 arch_zone_highest_possible_pfn[0] = max_zone_pfn[0];
次は各ゾーンごとに最小・最大のページフレーム番号をセットする。
for (i = 1; i < MAX_NR_ZONES; i++) { 5190 if (i == ZONE_MOVABLE) 5191 continue; 5192 arch_zone_lowest_possible_pfn[i] = 5193 arch_zone_highest_possible_pfn[i-1]; 5194 arch_zone_highest_possible_pfn[i] = 5195 max(max_zone_pfn[i], arch_zone_lowest_possible_pfn[i]); 5196 }
ZONE_MOVABLEも意味合い的にはゾーンなのでZONE_DMA等と同じなんだけどZONE_DMA、ZONE_NORMALとちょっと意味合いが違ってページの移動ができるというもので、Linux 2.6.23の[2.10. Movable Memory Zone] (http://kernelnewbies.org/Linux_2_6_23)の説明にあるやつっぽい。メモリのフラグメンテーション回避に使用されるのかな(メモリ フラグメンテーション回避)
5197 arch_zone_lowest_possible_pfn[ZONE_MOVABLE] = 0; 5198 arch_zone_highest_possible_pfn[ZONE_MOVABLE] = 0; 5199
find_zone_movable_pfns_for_nodes()で各NUMAのノードごとに移動可能なゾーンのページフレームの最初の番号を探す。
5200 /* Find the PFNs that ZONE_MOVABLE begins at in each node */ 5201 memset(zone_movable_pfn, 0, sizeof(zone_movable_pfn)); 5202 find_zone_movable_pfns_for_nodes(); 5203
どんなことをしたい「かというのはコメントに書かれている。
5000 /* 5001 * Find the PFN the Movable zone begins in each node. Kernel memory 5002 * is spread evenly between nodes as long as the nodes have enough 5003 * memory. When they don't, some nodes will have more kernelcore than 5004 * others 5005 */ 5006 static void __init find_zone_movable_pfns_for_nodes(void)
ここはprintk
5204 /* Print out the zone ranges */ 5205 printk("Zone ranges:\n"); 5206 for (i = 0; i < MAX_NR_ZONES; i++) { 5207 if (i == ZONE_MOVABLE) 5208 continue; 5209 printk(KERN_CONT " %-8s ", zone_names[i]); 5210 if (arch_zone_lowest_possible_pfn[i] == 5211 arch_zone_highest_possible_pfn[i]) 5212 printk(KERN_CONT "empty\n"); 5213 else 5214 printk(KERN_CONT "[mem %0#10lx-%0#10lx]\n", 5215 arch_zone_lowest_possible_pfn[i] << PAGE_SHIFT, 5216 (arch_zone_highest_possible_pfn[i] 5217 << PAGE_SHIFT) - 1); 5218 } 5219 5220 /* Print out the PFNs ZONE_MOVABLE begins at in each node */ 5221 printk("Movable zone start for each node\n"); 5222 for (i = 0; i < MAX_NUMNODES; i++) { 5223 if (zone_movable_pfn[i]) 5224 printk(" Node %d: %#010lx\n", i, 5225 zone_movable_pfn[i] << PAGE_SHIFT); 5226 } 5227 5228 /* Print out the early node map */ 5229 printk("Early memory node ranges\n"); 5230 for_each_mem_pfn_range(i, MAX_NUMNODES, &start_pfn, &end_pfn, &nid) 5231 printk(" node %3d: [mem %#010lx-%#010lx]\n", nid, 5232 start_pfn << PAGE_SHIFT, (end_pfn << PAGE_SHIFT) - 1); 5233
この辺りはdmesgのこの辺で出ているもの。
[ 0.000000] Zone ranges: [ 0.000000] DMA [mem 0x00001000-0x00ffffff] [ 0.000000] DMA32 [mem 0x01000000-0xffffffff] [ 0.000000] Normal [mem 0x100000000-0x87f5fffff] [ 0.000000] Movable zone start for each node [ 0.000000] Early memory node ranges [ 0.000000] node 0: [mem 0x00001000-0x0009cfff] [ 0.000000] node 0: [mem 0x00100000-0x1fffffff] [ 0.000000] node 0: [mem 0x20200000-0x40003fff] [ 0.000000] node 0: [mem 0x40005000-0x78a47fff] [ 0.000000] node 0: [mem 0x7a30e000-0x7a30efff] [ 0.000000] node 0: [mem 0x7a352000-0x7aca1fff] [ 0.000000] node 0: [mem 0x7afd7000-0x7affffff] [ 0.000000] node 0: [mem 0x100000000-0x87f5fffff]
printk()で使っているKERN_CONTはログレベルという位置づけではなくて、その前のprintk()の出力の続きという感じの意味合い。
mminit_verify_pageflags_layout()はその名の通りの処理で何をやっているかというところには興味ないので飛ばす。
5234 /* Initialise every node */ 5235 mminit_verify_pageflags_layout();
setup_nr_node_ids()はノードを見て回って一番大きいノード番号を探すという処理みたい。
5236 setup_nr_node_ids();
使えるノード分のループで、
5237 for_each_online_node(nid) { 5238 pg_data_t *pgdat = NODE_DATA(nid);
nodeごとにフリー領域のセットアップ。free_area_init_node()とfree_area_init_core()が処理の本番。特にfree_area_init_core()ではstruct zoneにデータが設定される。
5239 free_area_init_node(nid, NULL, 5240 find_min_pfn_for_node(nid), NULL); 5241
N_MEMORYはinclude/linux/nodemask.hで定義されている。paging_init()ではnode_clear_state(0, N_MEMORY);として0がセットされたけど、ここではノード番号が入る。
5242 /* Any memory on that node */ 5243 if (pgdat->node_present_pages) 5244 node_set_state(nid, N_MEMORY);
check_for_memory()もやっていることとしては各ゾーンにページがあるか調べてあればnode_set_state()でステータスをセットするという感じの処理。
5245 check_for_memory(pgdat, nid); 5246 } 5247 }
(´-`).。oO(さて、これでx86_64の場合のpaging_init()が読み終わった。
- 作者: Andrew S. Tanenbaum,吉澤康文,木村信二,永見明久,峯博史
- 出版社/メーカー: ピアソンエデュケーション
- 発売日: 2007/12/20
- メディア: 単行本(ソフトカバー)
- 購入: 6人 クリック: 104回
- この商品を含むブログ (16件) を見る