page cacheの検索と作成・登録

詳解Linuxカーネル読書会 - 詳解Linuxカーネル読書会 | Doorkeeperのもくもく結果。今日はページキャッシュの処理を調べました。 参考資料はUnderstanding Linux Kernelですが、長いので赤本と呼びます。

kernelは4.6を参照

buffer_head構造体の初期化。

buffer_init()で実施。

  • buffer_headという名前のスラブキャッシュ作成
  • buffer_head用に確保できる最大のページ数を設定
  • cpu hotplugでcpuが外れた時のbuffer_headの後処理関数を設定

ページキャッシュの検索とキャッシュがなかった時に追加

赤本ではページキャッシュの追加はadd_to_page_cache()って書いているんだけど、検索した限りあまり使われていない感じです。

f:id:masami256:20160528133650p:plain

それよりも、add_to_page_cache_lru()や、find_or_create_page()が使われている。find_or_create_page()はページキャッシュを検索して、見つからなければページを確保してページキャッシュに登録してくれる関数。内部的にはadd_to_page_cache_lru()を使ってます。

赤本で説明されているfind_get_page()は内部の実装としてはpagecache_get_page()を呼びます。find_or_create_page()pagecache_get_page()を呼びます。違いはpagecache_get_page()の引数fgp_flagsにFGP_CREATを設定しているかどうかです。FGP_CREATのビットが立っている場合は、ページキャッシュがなかった時にキャッシュを登録します。ページキャッシュを検索する系の関数は基本的にpagecache_get_page()を使う感じですね。

ページキャッシュの検索は、最初に find_get_entry()でページを検索します。このfind_get_entry()は赤本でradix treeを探索してるって説明のところを行っている関数っぽいです。find_get_page()の場合は、find_get_entry()でページが見つかれば処理完了です。pageが見つかった場合は参照数を増やします。find_lock_page()の場合はpage->mappingが引数で渡されたmappingと同じかをチェックします。この時はpage構造体のロックを取る必要があって、ロックが取れなければキャッシュ見つからずという感じでNULLを返します。page->mapping != mappingの場合は確保したロックの解除と、pageの参照数を減らして、再度ページキャッシュの検索を行います。 つぎにfgp_flagsにFGP_ACCESSEDが設定されていた場合はmark_page_accessed()を呼びます。これはLRUキューの操作をしたりといったところです。

ページキャッシュが見つかった場合の処理はここまでです。次にページキャッシュが見つからなかった場合です。pageがNULLでfgp_flagsにFGP_CREATが設定されている場合にキャッシュの登録があります。最初にpageをallocします(これは通常はalloc_page()で)。pageを確保できなければそこで終了で、NULLを返します。次にfgp_flags関連の処理で、FGP_LOCKが設定されていなければ、FGP_LOCKを追加します。それと、FGP_ACCESSEDが設定されていれば、__SetPageReferenced()を実行します。

最後にadd_to_page_cache_lru()でLRUにページキャッシュを登録します。 LRUに登録するのはpage構造体だけど、まだpageとaddress_space構造体は関連付いていません。なので、その関連付けが最初に行うことになります。この処理を行うのは__add_to_page_cache_locked()です。ここでpage->mappingにpagecache_get_page()に渡されたmappingを設定したり、radix treeへの登録を行ってます。__add_to_page_cache_locked()の処理が終わったら、page構造体をLRUに登録します。

パーフェクトPython

パーフェクトPython