linux:x86_64のpageing_init()での最後の処理、zone_sizes_init()を読む。

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

次にfree_area_init_nodes()を。

最初に変数の初期化処理がいくつか。

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はマクロじゃなくてenuminclude/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()が読み終わった。

オペレーティングシステム 第3版

オペレーティングシステム 第3版

  • 作者: Andrew S. Tanenbaum,吉澤康文,木村信二,永見明久,峯博史
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 2007/12/20
  • メディア: 単行本(ソフトカバー)
  • 購入: 6人 クリック: 104回
  • この商品を含むブログ (16件) を見る