プロセス毎のswap使用量を計測するパッチを読む その6
「プロセス毎のswap使用量を計測するパッチを読む その5」の続き。
copy_one_pte
copy_one_pte関数の最後の数行です。
mm/memory.c
page = vm_normal_page(vma, addr, pte); if (page) { get_page(page); page_dup_rmap(page); rss[PageAnon(page)]++; } out_set_pte: set_pte_at(dst_mm, addr, dst_pte, pte); }
vm_normal_page関数
vm_normal_page関数は、指定されたページテーブルエントリに関連するpage構造体を返します、とコメントに記載されていました。実装はvm_areaがspecialマッピングかVM_PFNMAP|VM_MIXEDMAPの時にアドレス範囲のチェック等が行われます。通常のページであれば、ページテーブルエントリからページフレームに変換し(pte_pfn関数)、さらにページフレームからpage構造体を取得します(pfn_to_page関数)。指定されたページテーブルエントリがpage構造体に関連しない場合はNULLとなります。
get_page関数
include/linux/mm.h
static inline void get_page(struct page *page) { page = compound_head(page); VM_BUG_ON(atomic_read(&page->_count) == 0); atomic_inc(&page->_count); }
指定されたpage構造体の参照カウントをインクリメントしているようです。参照カウントを増やすという処理は、swapエントリが増えた時と同じような処理になります。
compound_head関数
static inline struct page *compound_head(struct page *page) { if (unlikely(PageTail(page))) return page->first_page; return page; }
ページの最後(Tail)であれば最初のページを返す、と読めますが、詳細はよくわかりません。pglist_data構造体→(zone構造体)→page構造体配列で管理されるpage構造体配列の先頭と末尾のpage構造体を意味しているのかな。
PageTail関数
include/linux/page-flags.h
/* * PG_reclaim is used in combination with PG_compound to mark the * head and tail of a compound page. This saves one page flag * but makes it impossible to use compound pages for the page cache. * The PG_reclaim bit would have to be used for reclaim or readahead * if compound pages enter the page cache. * * PG_compound & PG_reclaim => Tail page * PG_compound & ~PG_reclaim => Head page */ #define PG_head_tail_mask ((1L << PG_compound) | (1L << PG_reclaim)) =>atic inline int PageTail(struct page *page) { return ((page->flags & PG_head_tail_mask) == PG_head_tail_mask); }
PageTail関数ですが、page構造体のflagsメンバが「PG_compound & PG_reclaim」である場合、Tail Pageということになっています。「Linuxカーネル解析室」のp.193を見ると、PG_compoundは「このページがラージページの一部であることを示す」、PG_reclaimは「swap処理で処理中(dirtyページの書き出し)となっていますが、pageのHead/Tailとどう関連があるのか分かりません。 コメントの内容も理解できてませんが、先に進みます。
page_dup_rmap関数
copy_one_pte関数に戻って、get_page関数の次に呼ばれているpage_dup_rmap関数。
/include/linux/rmap.h
=>atic inline void page_dup_rmap(struct page *page) { atomic_inc(&page->_mapcount); }
「Linuxカーネル解読室」のpage構造体の説明(p.192)を見ると、page構造体の_mapcountメンバは「アドレス空間にマップされている数」とのこと。
その後、rssの使用量を加算します。この部分については以前記述したので割愛します。最後のset_pte_at関数もアーキテクチャ依存で追えませんでしたが、今までcopy_one_pte関数を見てきて、関数名にあるようなページテーブルエントリのコピーが行われていないので、それはset_pte_atの内部で行われていると思われます。
参考文献:
Linuxカーネル2.6解読室 | |
ソフトバンククリエイティブ 2006-11-18 売り上げランキング : 63555 おすすめ平均 Linuxカーネル全般についてじっくり学べる これを理解できなくてもがっかりするな 細かい割りに、肝心な疑問点がわからない Amazonで詳しく見る by G-Tools |