プロセス毎のswap使用量を計測するパッチを読む その3

「プロセス毎のswap使用量を計測するパッチを読む その2」の続き。

ページテーブル

Linuxのページ変換テーブルは以下の要素で構成されています。

今回は一番末端のページテーブルのコピーを行うcopy_one_pte関数を見てみます。

copy_one_pte

copy_one_pte関数は、proc/(PID)/statusに書き込むswapサイズを計測する処理が追加されています。copy_to_pte関数そのものの機能は、あるタスクのvm_areaの1つを別のタスクにコピーする関数です。
copy_to_pte関数の呼び出し元を追いかけていくと、fork処理(do_fork)まで遡ります。fork時にページテーブルをコピーするのでしょう。
fork_idle, do_fork → copy_process → copy_mm → dup_mm → dup_mmap → copy_page_range → copy_pud_range → copy_pmd_range → copy_pte_range → copy_to_pte
最初の部分だけ見てみます。
mm/memory.c

copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
                pte_t *dst_pte, pte_t *src_pte, struct vm_area_struct *vma,
                unsigned long addr, int *rss)
{
        unsigned long vm_flags = vma->vm_flags;
        pte_t pte = *src_pte;
        struct page *page;

        /* pte contains position in swap or file, so copy. */
        if (unlikely(!pte_present(pte))) {
                if (!pte_file(pte)) {
                        swp_entry_t entry = pte_to_swp_entry(pte);

                        swap_duplicate(entry);
                        /* make sure dst_mm is on swapoff's mmlist. */
                        if (unlikely(list_empty(&dst_mm->mmlist))) {
                                spin_lock(&mmlist_lock);
                                if (list_empty(&dst_mm->mmlist))
                                        list_add(&dst_mm->mmlist,
                                                 &src_mm->mmlist);
                                spin_unlock(&mmlist_lock);
                        }

pte_t

pte_tの定義は以下のようになっています。このあたりはCPUのアーキテクチャによって異なるので、asm-generic下の定義を貼り付けました。
/usr/src/linux-2.6.32.12/include/asm-generic/page.h

/*
 * These are used to make use of C type-checking..
 */
typedef struct {        unsigned long pte;
} pte_t;
typedef struct {        unsigned long pmd[16];
} pmd_t;
typedef struct {        unsigned long pgd;
} pgd_t;
typedef struct {        unsigned long pgprot;
} pgprot_t;
typedef struct page *pgtable_t;

swp_entry_t

swp_entry_tは、スワップ領域上のページを表しているとのこと。
include/linux/swap.h

typedef struct {
        unsigned long val;
=>swp_entry_t;

pte_to_swp_entry

pte_to_swp_entry関数は、アーキテクチャ依存のpteからアーキテクチャ非依存のswp_entry_tに変換するようです。
include/linux/swapops.h

/*                                                                          
 * Convert the arch-dependent pte representation of a swp_entry_t into an   
 * arch-independent swp_entry_t.                                            
 */
static inline swp_entry_t pte_to_swp_entry(pte_t pte)
{
        swp_entry_t arch_entry;

        BUG_ON(pte_file(pte));
        arch_entry = __pte_to_swp_entry(pte);
        return swp_entry(__swp_type(arch_entry), __swp_offset(arch_entry));
}

swap_info_struct

スワップ領域を管理する構造体。swap_mapメンバがスワップ領域のページの参照カウントを管理しています。
include/linux/swap.h

/*                                                                          
 * The in-memory structure used to track swap areas.                        
 */
=>ruct swap_info_struct {
        unsigned long flags;
        int prio;                       /* swap priority */
        int next;                       /* next entry on swap list */
        struct file *swap_file;
        struct block_device *bdev;
        struct list_head extent_list;
        struct swap_extent *curr_swap_extent;
        unsigned short *swap_map;
        unsigned int lowest_bit;
        unsigned int highest_bit;
        unsigned int lowest_alloc;      /* while preparing discard cluster */
        unsigned int highest_alloc;     /* while preparing discard cluster */
        unsigned int cluster_next;
        unsigned int cluster_nr;
        unsigned int pages;
        unsigned int max;
        unsigned int inuse_pages;
        unsigned int old_block_size;
};

swap_info_structは、次の箇所で使用されています。
/usr/src/linux-2.6.32.12/mm/swapfile.c

=>atic struct swap_info_struct swap_info[MAX_SWAPFILES];

swap_duplicate

swap_duplicate関数は以下のようにして__swap_duplicate関数を呼び出します。

/*                                                                          
 * increase reference count of swap entry by 1.                             
 */
void swap_duplicate(swp_entry_t entry)
{
        __swap_duplicate(entry, SWAP_MAP);
}

SWAP_MAPは、以下のように定義されていました。
mm/swapfile.c

/* For reference count accounting in swap_map */
/* enum for swap_map[] handling. internal use only */
enum {
=>      SWAP_MAP = 0,   /* ops for reference from swap users */
        SWAP_CACHE,     /* ops for reference from swap cache */
};

ops for reference from swap users」は何だろう。「from swap cache」ではない、という意味で、一般的なスワップ領域を示すのでしょうか。
__swap_duplicate関数の中でこの値を見て処理が分かれるのですが、SWAP_MAPの場合は指定したswap_entry_tからスワップ領域を管理する構造体swap_infoに変換してスワップ領域のページを特定し、その参照カウントを1増やしていました。

mm_struct.mmlist

コピー先のmm_structのmmlistが空であれば、コピー元のmm_structのmmlistをコピー先のmmlistに追加しています。が、このmmlistメンバの位置づけが良くわかりません。
include/linux/mm_types.h

        struct list_head mmlist;                /* List of maybe swapped mm's.  These are globally strung                                 
                                                 * together off init_mm.mmlist, and are protected                                         
                                                 * by mmlist_lock
                                                 */

Linuxカーネル解読室』(p218)を見ると、「スワップページありのmm_structリンクリスト用」とあるのですが、意味が良く分からない…。プロセスのページの一部がスワップアウトしたら、そのプロセスのmm_structがmmlistに追加されるのでしょうか。

参考文献:

Linuxカーネル2.6解読室
Linuxカーネル2.6解読室
ソフトバンククリエイティブ 2006-11-18
売り上げランキング : 63555

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

Amazonで詳しく見る
by G-Tools