プロセス毎の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解読室
Linuxカーネル2.6解読室
ソフトバンククリエイティブ 2006-11-18
売り上げランキング : 63555

おすすめ平均 star
starLinuxカーネル全般についてじっくり学べる
starこれを理解できなくてもがっかりするな
star細かい割りに、肝心な疑問点がわからない

Amazonで詳しく見る
by G-Tools