Swap - ページイン
Rev.4を表示中。最新版はこちら。
1. ページイン処理の概要
ページアウトされたページはプロセスのアドレス空間からアンマップされているので、プロセスがページアウトされたアドレス空間にアクセスすると、ページフォルトが発生する。
ページフォルトのハンドラはユーザプロセスがページアウト済みのページにアクセスした場合に、do_swap_page()でページイン処理を開始する。
なお、ページフォルトの発生したアドレス空間のページがページアウトされているかどうかはPTEの内容で判断できる。ページアウトしてページをアンマップする際、ページアウト先の情報をPTEの空きフィールドに書き込むので、PTEにこの情報が格納されているかでページアウトされているかどうかを判断できる。
2. 処理の概要
2.1 do_swap_page()
do_swap_page()はまずページフォルトが発生する要因となった仮想アドレス空間に対応するPTEからページアウト先の位置情報を取得する。この情報には、ページアウト先のスワップ領域種別とスワップ領域内のページオフセットが含まれる(「Swap - ページアウト」参照)。この情報により、ページインすべきデータがディスクのどこに格納されているかがわかる。
ページインすべきページがわかったら、そのページがすでにSwapCacheに格納されていないかを確認する。SwapCacheにすでにある場合はページインは不要なのでページのマップ処理に進む。SwapCacheにない場合は、swapin_readahead()でページのReadを開始する。
Readが完了すると、PTEを設定してプロセスのアドレス空間にページをマップしプロセスからアクセスできるようにする。
そして、swap_free()でスワップ空間内のこのページの使用中カウンタをデクリメントする。
/* PTEがHighMemoryにある場合は、カーネル空間からUnmap * CONFIG_HIGHPTEが無効なら関係ない */ if (!pte_unmap_same(mm, pmd, page_table, orig_pte)) goto out; /* PTEからページアウト先の情報を取得 */ entry = pte_to_swp_entry(orig_pte); again: /* ページインするページがSwapCacheにあるかチェック */ page = lookup_swap_cache(entry); if (!page) { /* Read I/O開始 - 先読みも行う */ swapin_readahead(entry, address, vma); page = read_swap_cache_async(entry, vma, address); : } : /* Lockを取得 * 上でRead I/Oを開始した場合は、I/O完了までここでBlockする */ lock_page(page); /* マップ処理 * PTEを設定してプロセスからアクセスできるようにする */ pte = mk_pte(page, vma->vm_page_prot); if (write_access && can_share_swap_page(page)) { /* ページフォルト要因がWriteアクセスで * このページを他に誰も使用していない場合は * SwapCache内のページをWriteしてしまってよいので * Write可にPTEを設定する。 * この場合、Copy On Writeは不要なのでwrite_accsessを0にする。 */ pte = maybe_mkwrite(pte_mkdirty(pte), vma); write_access = 0; } set_pte_at(mm, address, page_table, pte); /* ページをRmapに登録 */ page_add_anon_rmap(page, vma, address); /* スワップ空間内のページの使用中カウンタをデクリメント */ swap_free(entry); : if (write_access) { /* ページフォルト要因がWriteアクセスで、 * ページインしたページに直接Writeできない場合は、 * 複製してそちらを使用する。- COW (Copy On Write) */ if (do_wp_page(mm, vma, address, page_table, pmd, ptl, pte) == VM_FAULT_OOM) ret = VM_FAULT_OOM; goto out; }