Linuxのpage単位のallocatorを理解したいなーというところで、mm/page_alloc.cの __alloc_pages_nodemask()を起点にコードを読み始める。 __alloc_pages_nodemask()はalloc_pages()なんかから呼ばれるところですね。
__alloc_pages_nodemask()の細かいところを覗いて基本的な流れはこのような形
__alloc_pages_nodemask()のパラメーターをstruct alloc_contextのインスタンスに保存
このalloc_context構造体はallocationに関する設定(gfpフラグとか)をひとまとめにしておくもの。gfpフラグとは別にalloc_flagsというローカル変数でallocationのフラグを設定する
このフラグはmm/internal.hにあるALLOC_
で始まる定数を使用するカーネルの.configでCONFIG_CMAが有効になっていて、gfpフラグの設定で
__GFP_MOVABLE
と__GFP_RECLAIMABLE
が立っている場合はでALLOC_CMAというフラグをalloc_flagsに立てる
CMA(Continuous Memory Allocator )はこのContinuous Memory Allocator - The Linux Foundation(pdf)を参照ここからは各zoneを調べて空きページを探す(コード上だとretry_cpusetラベルというgoto用のラベルが使われる)
最初に read_mems_allowed_begin()を呼んでpageを確保する処理を始めたという状態を設定しておく
first_zones_zonelist()でメモリを確保するのに適切なzoneを探す
適切なzoneが見つからなければどうにもならないので__alloc_page_nodemask()はNULLを返すget_page_from_freelist()でpageを取得する
ここではgfpフラグを直接使うのではなく、gfpフラグに__GFP_HARDWALL というフラグをセットしたものを使う。このフラグはプロセスが属するcpusetからのみ確保を行うという設定。get_page_from_freelist()でpageを確保できなかったら__alloc_pages_slowpath()で再度pageの確保にトライ
最後に、pageの取得ができていた場合にread_mems_allowed_retry()を呼んでread_mems_allowed_begin()の時と状態が違っていたらpageの確保失敗としてretry_cpusetラベルに戻る
この__alloc_pages_nodemask()で重要なところは read_mems_allowed_begin()とread_mems_allowed_retry()によるチェックと、実際にpageを確保しに行くget_page_from_freelist()かな。
前者の2個はcpusets機能のmems_allowedが絡んでいます。Documentation/cgroups/cpusets.txtについて書かれています。 このドキュメントの57〜60行目を見るとこんなことが書かれています。
57 CPUs or Memory Nodes not in that cpuset. The scheduler will not 58 schedule a task on a CPU that is not allowed in its cpus_allowed 59 vector, and the kernel page allocator will not allocate a page on a 60 node that is not allowed in the requesting task's mems_allowed vector.
カーネルのpage allocatorはtaskのmems_allowedを見てpageの確保が許可されていないnodeからはメモリを確保しないと言ってますね。 実際に、struct task_structを見てみるとnodemask_tの変数でmems_allowedがありますね。
1562 #ifdef CONFIG_CPUSETS 1563 nodemask_t mems_allowed; /* Protected by alloc_lock */ 1564 seqcount_t mems_allowed_seq; /* Seqence no to catch updates */ 1565 int cpuset_mem_spread_rotor; 1566 int cpuset_slab_spread_rotor; 1567 #endif
mems_allowedの設定値は /proc/
Cpus_allowed: ff Cpus_allowed_list: 0-7 Mems_allowed: 00000000,00000001 Mems_allowed_list: 0
そして、mems_allowedについては__alloc_pages_nodemask()の実行中に他のスレッドが更新しているかも知れないので再度チェックが必要みたいです。
さて、次はget_page_from_freelist()を読んでいきましょう。
プロセッサを支える技術 ??果てしなくスピードを追求する世界 (WEB+DB PRESS plus)
- 作者: Hisa Ando
- 出版社/メーカー: 技術評論社
- 発売日: 2011/01/06
- メディア: 単行本(ソフトカバー)
- 購入: 22人 クリック: 250回
- この商品を含むブログ (52件) を見る