buddy allocatorの__zone_watermark_ok()めも

Linuxのbuddy allocatorでpage数のwatermarkをチェックしているのは__zone_watermark_ok()。そんなわけで、今日はその辺りの動作を見てみる。

__zone_watermark_ok()は他のファイルから直接呼べないので、zone_watermark_ok()を使う。例えば、mm/compaction.cにあるtry_to_compact_pages()はwatermarkを下回らないzoneを対象に処理するので、zone_watermark_ok()を使う。

zone_watermark_ok()はこのように__zone_watermark_ok()を呼ぶ。最後の引数は対象のzone、zの空きページ数。

1834 bool zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark,
1835                       int classzone_idx, int alloc_flags)
1836 {
1837         return __zone_watermark_ok(z, order, mark, classzone_idx, alloc_flags,
1838                                         zone_page_state(z, NR_FREE_PAGES));
1839 }

zone_page_state()はこのような関数でzone構造体のメンバ変数vm_statを参照する。

130 static inline unsigned long zone_page_state(struct zone *zone,
131                                         enum zone_stat_item item)
132 {
133         long x = atomic_long_read(&zone->vm_stat[item]);
134 #ifdef CONFIG_SMP
135         if (x < 0)
136                 x = 0;
137 #endif
138         return x;
139 }

vm_statはstruct zoneの定義の一番最後にある。

528         /* Zone statistics */
529         atomic_long_t           vm_stat[NR_VM_ZONE_STAT_ITEMS];

NR_FREE_PAGESはenum型で、include/linux/mmzone.hで定義されている。

114 enum zone_stat_item {
115         /* First 128 byte cacheline (assuming 64 bit words) */
116         NR_FREE_PAGES,
117         NR_ALLOC_BATCH,
~略~

そして、本日のメインになる__zone_watermark_ok()はこちら。

1799 static bool __zone_watermark_ok(struct zone *z, unsigned int order,
1800                         unsigned long mark, int classzone_idx, int alloc_flags,
1801                         long free_pages)
1802 {
1803         /* free_pages may go negative - that's OK */
1804         long min = mark;
1805         int o;
1806         long free_cma = 0;
1807

最初に空きページ数からorder分のpage数-1した数を引く。

1808         free_pages -= (1 << order) - 1;

次に、alloc_flagsの設定によって、watermarkの位置を変更する。 ここの計算は2.6.12-rc1の時点ですでにこうなってたらしい。

1809         if (alloc_flags & ALLOC_HIGH)
1810                 min -= min / 2;
1811         if (alloc_flags & ALLOC_HARDER)
1812                 min -= min / 4;

Contiguous Memory Allocator機能が有効な場合はCMAの領域についても空きページ数を調べる。

1813 #ifdef CONFIG_CMA
1814         /* If allocation can't use CMA areas don't use free CMA pages */
1815         if (!(alloc_flags & ALLOC_CMA))
1816                 free_cma = zone_page_state(z, NR_FREE_CMA_PAGES);
1817 #endif

空きページ数(CMA以外 + CMA)を足してもまだwatermarkまで回復しない場合はfalse。try_to_compact_pages()から呼ばれた場合だと、このzoneはcompactionしないということになる。

1818 
1819         if (free_pages - free_cma <= min + z->lowmem_reserve[classzone_idx])
1820                 return false;

次に、対象のzone「z」のorder「o」のfree_areaの空きページ数をo分左シフトした値と、minを2で割った値を比較して、空きページ数の方が下回るならfalseを返す。これをorder 0から確保しようとしたoder - 1まで実行する。

1821         for (o = 0; o < order; o++) {
1822                 /* At the next order, this order's pages become unavailable */
1823                 free_pages -= z->free_area[o].nr_free << o;
1824 
1825                 /* Require fewer higher order pages to be free */
1826                 min >>= 1;
1827 
1828                 if (free_pages <= min)
1829                         return false;
1830         }
1831         return true;
1832 }
1833 

途中でreturnせずにforループを抜けたら問題なしということでtrueを返す。

The Art of Computer Programming Volume 1 Fundamental Algorithms Third Edition 日本語版

The Art of Computer Programming Volume 1 Fundamental Algorithms Third Edition 日本語版