前回は__alloc_pages_nodemask()
を見たので、今回はそこから呼ばれ、実際にallocationを行う部分の
get_page_from_freelist()を見ていきます。
基本的な流れは、
boolの変数consider_zone_dirtyにalloc_flagsとgfpフラグの値から真偽値を決める ここでgfpフラグに__GFP_WRITEがセットされているかというチェックがあり、これは「mm: try to distribute dirty pages fairly across zones」というpatchで追加されたもので、pageがallocation後、すぐにdirtyになることが分かっている場合にせっとするようです。
ローカル変数の定義が終わると本編で、zonelist_scanというgotoラベルが設定され、ループの先頭がここになる
for_each_zone_zonelist_nodemask()でzoneのリストからzoneをひとつずつ見て、pageの確保を行うzoneを探す
このzoneからpageの確保ができるかをzlc_zone_worth_trying()で軽くチェックし、無理なら次のzoneを調べるためにループ先頭に戻る
cpuset_zone_allowed()でzoneがあるNUMA nodeからpage確保がcpusetによって禁止されていたらcontinue
__alloc_pages_nodemask()で最初のリクエストの時に__GFP_HARDWALL
を付けてましたが、それはここで使われます。alloc_flagsにALLOC_FAIRが立っている場合の処理 preferred_zoneと調べているzoneが同じならここからpage確保するのでループ終了。
もし、zoneに設定されているフラグにZONE_FAIR_DEPLETEDが立っていたらこのzoneのチェックは終了して、次のzoneを調べる。 ALLOC_FAIRは「mm: page_alloc: spill to remote nodes before waking kswapd」のpatchで追加。 ZONE_FAIR_DEPLETEDは「mm: page_alloc: reduce cost of the fair zone allocation policy」で追加。 ALLOC_FAIR・ZONE_FAIR_DEPLETEDどちらもfair zone allocation policyに関連している。 これのベーシックなところは「[patch 3/3] mm: page_alloc: fair zone allocator policy」に。見ているzoneがdirtyになることを許可しているかチェックして、ダメならこのzoneは諦める チエックとしてはconsider_zone_dirtyが1の場合にzone_dirty_ok()を呼ぶ。
要求されたpage数(order)がzoneのwatermark(最低限残しておく空きページ数)が下回らないかzone_watermark_ok()でチェックして、falseが返ってきた場合は以下の処理に入る
alloc_flagsにALLOC_NO_WATERMARKS がセットされていたら(watermarkを無視してpage確保するフラグ)このzoneからpageを確保するということで決定する
zone listのキャッシュが作成されていなければ作成する
このキャッシュはstruct zonelist_cacheで管理されていて、get_page_from_freelist()で空きpageを素早く見つけるのに使われる。最初の方に会ったzlc_zone_worth_trying()ではこのキャッシュを参照している。zoneがpageの回収が可能かチェックして、できないようならthis_zone_fullラベルにジャンプ
再度、最初と同じようにzlc_zone_worth_trying()でこのzoneからpage確保できるかチェックして、ダメなら次のzoneを調べる ここで再度チェックするのはちょっと前の処理でzonelist cacheを作っている場合があるため。
zone_reclaim()でpageの回収処理をする 結果がZONE_RECLAIM_NOSCAN、ZONE_RECLAIM_FULLの場合はこのzoneでのpage確保が無理なので次のzoneを調べる このzone_reclaim()はまた別の機会に詳しく見ましょう
pageのreclaimによってpageの確保ができるようになったならこのzoneからpage確保すると決定する
alloc_flagsにALLOC_WMARK_MINが立っていて、reclaim処理の戻り値がZONE_RECLAIM_SOMEの場合は、十分に空きpage数が確保できていないのでthis_zone_fullラベルにジャンプ
上記のチェックに引っかからない場合は次のzoneを見に行く
ここまでが 最初のzone_watermark_ok()でfalseが返った場合の処理で、ここからはzoneが確定した場合でtry_this_zoneラベルの場所
buffered_rmqueue()でzoneからpageを確保する なので、この buffered_rmqueue()がpage確保処理の本体っぽい。
pageが確保できた場合はprep_new_page()でpageを実際に使う前の前処理を行い、pageをreturnして関数を終了する prep_new_page()の処理は__GFP_ZEROが設定されていたら0クリアするとか、pageのリファレンスカウンタを初期化するとかの処理。
もしbuffered_rmqueue()でpageの取得ができなかった場合は、this_zone_fullラベルの処理に進む
this_zone_fullラベルからの処理はzonelist cacheに対して、空きpageが無いと設定する for_each_zone_zonelist_nodemask()によるforループの範囲はここまで({}の範囲)。
ここからはfor_each_zone_zonelist_nodemask()のループ中にpageを確保できなかった場合
alloc_flagsにALLOC_FAIRが立っていた場合、このbitを落とす
ALLOC_FAIRが立っていたためチェックをスキップしたzoneを再度チェックできるようにするreset_alloc_batches()で行う
onlineなNUMAノードが1以上あれば再度チェックするようにする
zonelist cacheを作成していた場合も再度チェックできるようにする
上記3個の処理で再チェックするとした場合は、関数冒頭にあるzonelist_scanラベルに飛んで、for_each_zone_zonelist_nodemask()のループ処理を再度行う
再チェックしない場合はNULLを返す
次回見ていくのはbuffered_rmqueue()ですね。
まんがでわかるLinux シス管系女子(日経BP Next ICT選書)
- 作者: 日経Linux
- 出版社/メーカー: 日経BP社
- 発売日: 2015/02/19
- メディア: Kindle版
- この商品を含むブログを見る