RHD補足資料
                     (Pagecache/swap)




                               2008/7/11

                             Tatsuo Kawasaki
                                               1
                                 @kernel023


Rev RH236-20080711        Tatsuo Kawasaki
1. アドレスについての復習(1)

• メモリとページ
        • 物理メモリの位置を表現する物理アドレス
        • アーキテクチャ毎に異なるリニアアドレス
          (x86=32bit= 約 4G,x86_64=64bit=16EB※)
        • 上記アドレスの処理は H/W のメモリ管理ユニット (MMU) で行う
               • 変換テーブルはカーネルが用意しておく
        • アーキテクチャ毎にメモリを扱う単位が決まっている
          =ページサイズ
          (x86,x86_64=4KB, IA64= カーネル構築時に選択可 :8k,16k.. 等 )


                                                 2
        ※ 現在の CPU アーキテクチャでは 16EB の全てはユーザー / カーネルメモ
          リとして使えないようになっている
Rev RH236-20080711           Tatsuo Kawasaki
2. アドレスについての復習(2)

                              メモリを「フレーム」単位で区切って管理




                                                                       単位はページサイズ
                                                                       (PAGE_SIZE)


Page構造体:
 ページフレームを管理
                                                                          page構造体それぞれが
   mem_map *page
                       page
                              page
                                     page
                                            page
                                                   page



                                                                page



                                                                          対応するページフレームを
      page構造体を                                                            管理             3
      配列のように扱う

Rev RH236-20080711                                 Tatsuo Kawasaki
3. Page構造体とフレームの関係




     swap可                                                 対応しているページフレーム
                                                           はページキャッシュだ

                                                                        Page構造体でページの用途、状態
対応しているページフ                                                              などを管理している
レームは空いている
                                                                        struct page {
                                                                          unsigned long flags;

                                                                            atomic_t _count;
                        page
                               page
                                      page
                                             page
                                                    page



                                                                 page



                                                                            union {
                                                                              atomic_t _mapcount;
                                                                                                    4
                                                                            (略)
                                                                        }

Rev RH236-20080711                                  Tatsuo Kawasaki
4. Page構造体             struct page {
                                               unsigned long flags;

                                                 atomic_t _count;
                                                 union {
•     Page 構造体の主な要素                                atomic_t _mapcount;

         主要メンバー       意味、値                       (略)
         flag         フラグ(テキスト参照)            }
         _count       -1:未使用、0>:使用
         (union)
           m apping   a)対象ポインタはinode(ページキャッシュ)
                      b)対象ポインタは無名メモリ
           private    a)ページキャッシュのbuffer_head
                      b)スワップエントリ(swp_entry)
                      c)バディシステム(の指示)
           slab       Slab用
         index        a)ページキャッシュのオフセット
                      b)無名ページリージョンの開始リニアアドレス
                      c)不定
         freelist     Slab用
         lru          解放時に使用するLRU

                                                                         5


Rev RH236-20080711        Tatsuo Kawasaki
5. ページの種類(通常メモリの場合)
         (例)ページフレームに入っているのは
         カーネルが確保したメモリ



                            struct page {
    通常ページ
                              :
                              :
                              mapping <----- NULL
                              index   <----- 不定
                             :
                             :
                            }
                     page




                                                    6


Rev RH236-20080711                Tatsuo Kawasaki
6. ページの種類(無名ページの場合)
                                                                     ※話を簡単にしてあります


      ページフレームに入っているのは無名ページ



                                               struct vm_area_struct {   メモリリージョ
                     struct anon_vma {            vm_start               ン
                        list_head head            anon_vma_node; 共有時
                          :                    }
                     }
                                               struct vm_area_struct {
                                                  vm_start
                                                  :
                                               }

                             struct page {
                                mapping; ­­­> anon_vmaを指す
                               index; ­­­> メモリリージョンのインデックス
                                    :      
                      page




                             }
                                                                                    7


Rev RH236-20080711                  Tatsuo Kawasaki
7. ページの種類(ファイルデータの場合)
                                                                      ※話を簡単にしてあります
        ページフレームに入っているのは
        ファイルデータ(=ページキャッシュ)



                                                                        ファイ
             ファイル                                                       ル
                     struct address_space {          struct inode {
              データ       *host                           :
                         page_tree                      :
                                                                              ページ(正確には
                            :                        }                        ブロック)単位に
                     }
                                                                              管理


                            struct page {
                               mapping; ­­­> address_spaceを指す
                              index; ­­­> ファイルのインデックス
                                   :      (ファイルの何番目のインデックスに
                     page




                                     対応するデータが入っているページか)
                            }
                                                                                     8


Rev RH236-20080711                 Tatsuo Kawasaki
8. ページの種類(ファイルデータが
           複数のブロックから構成される場合)
         1ページフレームに複数のデータブロックが入るケース
              ページ




                                                                          ファイ
                                                   struct buffer_head {
                                                                          ル
                                                      b_data;
                                                      next;
                                                   }
                                                                                ブロック単位や
                                                                                superblockなど
                                                   struct buffer_head {
                                                                                ページサイズ以下
                                                      b_data;
   バッ        バッ      バッ   バッ                          next;
   ファ        ファ      ファ   ファ                       }



         struct page {
            private;  ­­> buffer_headへのポインタ
  page




         }
                                                                                        9


Rev RH236-20080711                       Tatsuo Kawasaki
9. 書き込み処理(1)
                     - システムコールからページキャッシュへ追加 -

• システムコールからの流れ( sys_write() )
        sys_write()
            + vfs_write()
             + do_sync_write()
                + ( ファイルシステム毎の )aio_write 。 EXT3 を例にする
                  + ext3_file_write()
                  + generic_file_aio_write()
                    + __generic_file_aio_write_nolock()
                     + generic_file_direct_write()    <--- DIRECT I/O の場合
                       + generic_file_buffered_write()             <--- 通常 I/O
                              対応する位置 (pos) から該当するページを特定

            + generic_file_buffered_write()        <--- 通常 I/O
             + __grub_cache_page()                 <--- ページキャッシュ検索、なければ割り当て
             + (apos->prepare_write) 。今回のケースでは __block_prepare_write() と仮定
                                        a. Page 構造体に必要なら buffer_head を割り当ててリンク
                                        b. ページ境界にあっていなければ解放、なければデバイスから読み込み
                                        c. ページに dirty という印をつけ繰り返す
                + filemap_copy_user() ページにデータをコピー( filemap_copy_user_iovec() の場合もある)
             + (apos->commit_write) 。今回のケースでは __block_commit_write() と仮定
                                        バッファとページに dirty という印を付ける
                                                                                       10


Rev RH236-20080711                               Tatsuo Kawasaki
9. 書き込み処理(2)
                     - ページキャッシュからデバイスへの書き込み -

•     ページキャッシュからの書き込みは複数の契機がある
      ( O_SYNC での write(),sync コマンド ,f_syncdata(), カーネルスレッドの
      pdflush など)
        例えば pdflush は、以下のいずれかのメソッドを呼び出す
          do_emergency_remount()
          do_sync()
          background_writeout()
          wb_kupdate()
          laptop_flush

        background_writeout() を例にしたフロー
           + writeback_inodes()
            + sync_sb_inode()
              + __writeback_single_inode()
               + __sync_single_inode()
                + do_writepage()       --> 上記のメソッドは最終的にこの関数を呼び出す

        do_writepage()
           + generic_writepages()
            + mpage_writepages()
                この関数にて address_space 構造体軽油で page 構造体を取得し、ページ
                                                                   11
               キャッシュのデータをディスクに書き出す



Rev RH236-20080711                    Tatsuo Kawasaki
10. 読み込み処理

• システムコールからの流れ( sys_read() )
        sys_read()
            + vfs_read()
             + do_sync_read()
               + ( ファイルシステム毎の )aio_read 。 EXT3 を例にする
                 + ext3_file_read()
                   + generic_file_aio_read()
                    + __generic_file_aio_read()
                     + do_generic_file_read()
                      + do_generic_mapping_read()

          do_generic_mapping_read()
            + page_cache_readahead()              <-- ページの先読み
            + find_get_page()                     <-- ページキャッシュの検索
              + radix_tree_lookup()                   radix_tree よりページキャッシュにあるかどうか検索
              + page_cache_get()                     ページキャッシュ取得
                 :
            + mapping->aops->readpages()          <-- デバイスから取得
              例えば ext3_readpages()
             + mpage_readpages()
              + do_mpage_readpage()
                                                                                       12
                + mpage_bio_submit()              <--- ドライバに I/O 要求発行
                   + block_read_full_page()       <-- buffer_head に格納

Rev RH236-20080711                            Tatsuo Kawasaki
11. スワップアウト処理の概要(1)

• メモリ不足発生時の挙動



                                                 3. スワップ領域に書き出し
  1. ページフレームは何らかのデータ
  (ページキャッシュは除く)
   page構造体の_mapcountが0に
  なるように解放していく


                            2. ページテーブル書き換え
                     page




                                                                  13


Rev RH236-20080711             Tatsuo Kawasaki
12. スワップアウト処理の概要(2)

• ページテーブル (pte) を書き換えることにより、ページテーブ
  ルでのページの対応が
                     リニアアドレス ===> 物理メモリ
                               ではなく
     リニアアドレス ===> スワップされているディスクの場所
  となる
                      page




                                               スワップ   14
                                       メモリ
Rev RH236-20080711           Tatsuo Kawasaki
13. スワップアウト処理の概要(3)

• メモリ回収処理が実行される箇所
        • メモリ確保要求時 (alloc_pages() など)
               • 但しカーネルメモリはスワップアウトされないので、 
                 out_of_memory() となるケースもある
        • サスペンド ( ハイバネーション)
        • 定期的な回収
               • kswapd カーネルスレッド
               • reap_work (events カーネルスレッドより実行)

• ページの回収アルゴリズム
                                         15
        • 基本的には LRU (最長不要使用順)を使用した、最近あまり使用
          されていない不要ページを優先とする回収アルゴリズム
Rev RH236-20080711            Tatsuo Kawasaki
14. スワップイン処理の概要

• 対応するページにアクセスしたら、そこにはページが存在
  していなかった --> ページフォルト発生
• ページフォルトに対応する処理で、スワップ領域からデー
  タを読み込みメモリにコピー(戻す)
                                                スワップ領域からページを
                                                読み込みメモリに戻す
                       page




ページフォルト!                                             スワップ   16
                                        メモリ
Rev RH236-20080711            Tatsuo Kawasaki
15. スワップに関する構造体の関連図
   swap_list
   _t                struct swap_info_struct {         struct swap_info_struct {
                       extent_list                       extent_list               スワップ領域毎に存在
                       swap_map                          swap_map
                     }                                 }



                                                                         どのスロットが使用されている
       struct swap_extent {                                              かを簡単に判別できる
         start_page                                                           ビットマッ
         nr_pages                                                             プ 0
         start_block                                                                 1
       }                                                                             1
                                                                                     2   ページスロットの
    ページとブロックの対応がわか                                                                   0   使用状況
    る                                                                                    0: 空き
                                                                                         1: 使用
                                                                                         2: 複数から使用
ページスロット
(単位はページサイ
ズ)


                                                                                                17


Rev RH236-20080711                           Tatsuo Kawasaki
16. スワップ識別子

• 通常は4段階の表引きにより対応する物理ページを特定する
• スワップの場合、ページテーブルを書き換え、スワップ領域の番号と
  スロットのインデックスを設定しておくことで取り出す

                     ページディレクトリ
                                            オフセット
                     ページテーブル等
                                             (12bit)   通常
                        (20bit)




                     スロットのインデックス           スワップ領域
                        (24ビット)             の番号等       スワップの場合
                                                       必ず0
                                                                 18
                        スワップ識別子
Rev RH236-20080711            Tatsuo Kawasaki
17. スワップアウト処理

• スワップアウト発生時のフロー( shrink_list() )
        shrink_list()
           + get_swappage()            <-- スロットの割り当て
           + add_to_page_cache()              <-- スワップキャッシュに追加
           + try_to_unmap()            <-- ページテーブルエントリにスワップアウト識別子書
           き込み
             + try_to_unmap_one()
             + set_pte_at()
             + swap_entry_to_pte()
           + pageout()
                + ジャンプテーブルに伴う該当する writepage 関数の実行、 swap 時は
           swap_write_page()
                   swap_write_page()
                      + get_swap_bio()        <-- ディスクに該当ブロックを書き込み
                       + submit_bio()

                                                               19


Rev RH236-20080711            Tatsuo Kawasaki
18. スワップイン処理

• スワップイン発生時のフロー( do_page_fault() 例外よ
  り)
        do_swap_page()
           + pte_unmap()                               <-- 一時領域解放
           + lookup_swap_cache()                       <-- スワップキャッシュにあるかどうかをチ
           ェック
           + swapin_readahead()                        <-- 数ページ分先読み (/proc/sys/vm/page-
           cluster 変数)
             + read_swap_cache_async()   <-- スワップキャッシュに読み込む
               + swap_readpage()
              + get_submit_bio()         <-- ディスクから読み込み( I/O の発生)
               + submit_bio()
            + swap_free()                              <-- エントリ更新 ( ページテーブル更新)
            + page_ad_anon_rmap()                      <-- リバースマップに追加
                                                                                    20


Rev RH236-20080711                   Tatsuo Kawasaki

pagecache-memo

  • 1.
    RHD補足資料 (Pagecache/swap) 2008/7/11 Tatsuo Kawasaki 1 @kernel023 Rev RH236-20080711 Tatsuo Kawasaki
  • 2.
    1. アドレスについての復習(1) • メモリとページ • 物理メモリの位置を表現する物理アドレス • アーキテクチャ毎に異なるリニアアドレス (x86=32bit= 約 4G,x86_64=64bit=16EB※) • 上記アドレスの処理は H/W のメモリ管理ユニット (MMU) で行う • 変換テーブルはカーネルが用意しておく • アーキテクチャ毎にメモリを扱う単位が決まっている =ページサイズ (x86,x86_64=4KB, IA64= カーネル構築時に選択可 :8k,16k.. 等 ) 2 ※ 現在の CPU アーキテクチャでは 16EB の全てはユーザー / カーネルメモ リとして使えないようになっている Rev RH236-20080711 Tatsuo Kawasaki
  • 3.
    2. アドレスについての復習(2) メモリを「フレーム」単位で区切って管理 単位はページサイズ (PAGE_SIZE) Page構造体:  ページフレームを管理 page構造体それぞれが mem_map *page page page page page page page 対応するページフレームを page構造体を 管理 3 配列のように扱う Rev RH236-20080711 Tatsuo Kawasaki
  • 4.
    3. Page構造体とフレームの関係 swap可 対応しているページフレーム はページキャッシュだ Page構造体でページの用途、状態 対応しているページフ などを管理している レームは空いている struct page { unsigned long flags; atomic_t _count; page page page page page page union { atomic_t _mapcount; 4 (略) } Rev RH236-20080711 Tatsuo Kawasaki
  • 5.
    4. Page構造体 struct page { unsigned long flags; atomic_t _count; union { • Page 構造体の主な要素 atomic_t _mapcount; 主要メンバー 意味、値 (略) flag フラグ(テキスト参照) } _count -1:未使用、0>:使用 (union) m apping a)対象ポインタはinode(ページキャッシュ) b)対象ポインタは無名メモリ private a)ページキャッシュのbuffer_head b)スワップエントリ(swp_entry) c)バディシステム(の指示) slab Slab用 index a)ページキャッシュのオフセット b)無名ページリージョンの開始リニアアドレス c)不定 freelist Slab用 lru 解放時に使用するLRU 5 Rev RH236-20080711 Tatsuo Kawasaki
  • 6.
    5. ページの種類(通常メモリの場合) (例)ページフレームに入っているのは カーネルが確保したメモリ struct page { 通常ページ : : mapping <----- NULL index <----- 不定  :  : } page 6 Rev RH236-20080711 Tatsuo Kawasaki
  • 7.
    6. ページの種類(無名ページの場合) ※話を簡単にしてあります ページフレームに入っているのは無名ページ struct vm_area_struct { メモリリージョ struct anon_vma {    vm_start ン    list_head head    anon_vma_node; 共有時      : } } struct vm_area_struct {    vm_start    : } struct page {    mapping; ­­­> anon_vmaを指す index; ­­­> メモリリージョンのインデックス        :       page } 7 Rev RH236-20080711 Tatsuo Kawasaki
  • 8.
    7. ページの種類(ファイルデータの場合) ※話を簡単にしてあります ページフレームに入っているのは ファイルデータ(=ページキャッシュ) ファイ ファイル ル struct address_space { struct inode { データ    *host    :     page_tree    : ページ(正確には        : } ブロック)単位に } 管理 struct page {    mapping; ­­­> address_spaceを指す index; ­­­> ファイルのインデックス        :      (ファイルの何番目のインデックスに page          対応するデータが入っているページか) } 8 Rev RH236-20080711 Tatsuo Kawasaki
  • 9.
    8. ページの種類(ファイルデータが 複数のブロックから構成される場合) 1ページフレームに複数のデータブロックが入るケース ページ ファイ struct buffer_head { ル    b_data;    next; } ブロック単位や superblockなど struct buffer_head { ページサイズ以下    b_data; バッ バッ バッ バッ    next; ファ ファ ファ ファ } struct page {    private;  ­­> buffer_headへのポインタ page } 9 Rev RH236-20080711 Tatsuo Kawasaki
  • 10.
    9. 書き込み処理(1) - システムコールからページキャッシュへ追加 - • システムコールからの流れ( sys_write() ) sys_write() + vfs_write() + do_sync_write() + ( ファイルシステム毎の )aio_write 。 EXT3 を例にする + ext3_file_write() + generic_file_aio_write() + __generic_file_aio_write_nolock() + generic_file_direct_write() <--- DIRECT I/O の場合 + generic_file_buffered_write() <--- 通常 I/O 対応する位置 (pos) から該当するページを特定 + generic_file_buffered_write() <--- 通常 I/O + __grub_cache_page() <--- ページキャッシュ検索、なければ割り当て + (apos->prepare_write) 。今回のケースでは __block_prepare_write() と仮定 a. Page 構造体に必要なら buffer_head を割り当ててリンク b. ページ境界にあっていなければ解放、なければデバイスから読み込み c. ページに dirty という印をつけ繰り返す + filemap_copy_user() ページにデータをコピー( filemap_copy_user_iovec() の場合もある) + (apos->commit_write) 。今回のケースでは __block_commit_write() と仮定 バッファとページに dirty という印を付ける 10 Rev RH236-20080711 Tatsuo Kawasaki
  • 11.
    9. 書き込み処理(2) - ページキャッシュからデバイスへの書き込み - • ページキャッシュからの書き込みは複数の契機がある ( O_SYNC での write(),sync コマンド ,f_syncdata(), カーネルスレッドの pdflush など) 例えば pdflush は、以下のいずれかのメソッドを呼び出す do_emergency_remount() do_sync() background_writeout() wb_kupdate() laptop_flush background_writeout() を例にしたフロー + writeback_inodes() + sync_sb_inode() + __writeback_single_inode() + __sync_single_inode() + do_writepage() --> 上記のメソッドは最終的にこの関数を呼び出す do_writepage() + generic_writepages() + mpage_writepages() この関数にて address_space 構造体軽油で page 構造体を取得し、ページ 11  キャッシュのデータをディスクに書き出す Rev RH236-20080711 Tatsuo Kawasaki
  • 12.
    10. 読み込み処理 • システムコールからの流れ(sys_read() ) sys_read() + vfs_read() + do_sync_read() + ( ファイルシステム毎の )aio_read 。 EXT3 を例にする + ext3_file_read() + generic_file_aio_read() + __generic_file_aio_read() + do_generic_file_read() + do_generic_mapping_read() do_generic_mapping_read() + page_cache_readahead() <-- ページの先読み + find_get_page() <-- ページキャッシュの検索 + radix_tree_lookup() radix_tree よりページキャッシュにあるかどうか検索 + page_cache_get()    ページキャッシュ取得 : + mapping->aops->readpages() <-- デバイスから取得   例えば ext3_readpages() + mpage_readpages() + do_mpage_readpage() 12 + mpage_bio_submit() <--- ドライバに I/O 要求発行 + block_read_full_page() <-- buffer_head に格納 Rev RH236-20080711 Tatsuo Kawasaki
  • 13.
    11. スワップアウト処理の概要(1) • メモリ不足発生時の挙動 3. スワップ領域に書き出し 1. ページフレームは何らかのデータ (ページキャッシュは除く) page構造体の_mapcountが0に なるように解放していく 2. ページテーブル書き換え page 13 Rev RH236-20080711 Tatsuo Kawasaki
  • 14.
    12. スワップアウト処理の概要(2) • ページテーブル(pte) を書き換えることにより、ページテーブ ルでのページの対応が リニアアドレス ===> 物理メモリ ではなく リニアアドレス ===> スワップされているディスクの場所   となる page スワップ 14 メモリ Rev RH236-20080711 Tatsuo Kawasaki
  • 15.
    13. スワップアウト処理の概要(3) • メモリ回収処理が実行される箇所 • メモリ確保要求時 (alloc_pages() など) • 但しカーネルメモリはスワップアウトされないので、  out_of_memory() となるケースもある • サスペンド ( ハイバネーション) • 定期的な回収 • kswapd カーネルスレッド • reap_work (events カーネルスレッドより実行) • ページの回収アルゴリズム 15 • 基本的には LRU (最長不要使用順)を使用した、最近あまり使用 されていない不要ページを優先とする回収アルゴリズム Rev RH236-20080711 Tatsuo Kawasaki
  • 16.
    14. スワップイン処理の概要 • 対応するページにアクセスしたら、そこにはページが存在 していなかった --> ページフォルト発生 • ページフォルトに対応する処理で、スワップ領域からデー タを読み込みメモリにコピー(戻す) スワップ領域からページを 読み込みメモリに戻す page ページフォルト! スワップ 16 メモリ Rev RH236-20080711 Tatsuo Kawasaki
  • 17.
    15. スワップに関する構造体の関連図 swap_list _t struct swap_info_struct { struct swap_info_struct {   extent_list   extent_list スワップ領域毎に存在   swap_map   swap_map } } どのスロットが使用されている struct swap_extent { かを簡単に判別できる   start_page ビットマッ   nr_pages プ 0   start_block 1 } 1 2 ページスロットの ページとブロックの対応がわか 0 使用状況 る 0: 空き 1: 使用 2: 複数から使用 ページスロット (単位はページサイ ズ) 17 Rev RH236-20080711 Tatsuo Kawasaki
  • 18.
    16. スワップ識別子 • 通常は4段階の表引きにより対応する物理ページを特定する •スワップの場合、ページテーブルを書き換え、スワップ領域の番号と スロットのインデックスを設定しておくことで取り出す ページディレクトリ オフセット ページテーブル等 (12bit) 通常 (20bit) スロットのインデックス スワップ領域 (24ビット) の番号等 スワップの場合 必ず0 18 スワップ識別子 Rev RH236-20080711 Tatsuo Kawasaki
  • 19.
    17. スワップアウト処理 • スワップアウト発生時のフロー(shrink_list() ) shrink_list() + get_swappage() <-- スロットの割り当て + add_to_page_cache() <-- スワップキャッシュに追加 + try_to_unmap() <-- ページテーブルエントリにスワップアウト識別子書 き込み + try_to_unmap_one() + set_pte_at() + swap_entry_to_pte() + pageout() + ジャンプテーブルに伴う該当する writepage 関数の実行、 swap 時は swap_write_page() swap_write_page() + get_swap_bio() <-- ディスクに該当ブロックを書き込み + submit_bio() 19 Rev RH236-20080711 Tatsuo Kawasaki
  • 20.
    18. スワップイン処理 • スワップイン発生時のフロー(do_page_fault() 例外よ り) do_swap_page() + pte_unmap() <-- 一時領域解放 + lookup_swap_cache() <-- スワップキャッシュにあるかどうかをチ ェック + swapin_readahead() <-- 数ページ分先読み (/proc/sys/vm/page- cluster 変数) + read_swap_cache_async() <-- スワップキャッシュに読み込む + swap_readpage() + get_submit_bio() <-- ディスクから読み込み( I/O の発生) + submit_bio() + swap_free() <-- エントリ更新 ( ページテーブル更新) + page_ad_anon_rmap() <-- リバースマップに追加 20 Rev RH236-20080711 Tatsuo Kawasaki