デマンドロード

生成直後の仮想空間(ページ)にアクセスをすると, まだ実際には物理メモリが割り当てられていないため, CPU例外が発生する. そのときlinuxでは, do_no_page関数が呼び出される.

ファイルがマッピングされて無い領域の場合, do_anonymous_page関数を利用して, 適当な空き物理ページを割り当てる. (PTEに物理ページの物理アドレスとページ有効属性を設定する. 書き込みアクセスの場合, 書き込み可の属性も設定する)

ファイルがマッピングされている場合, filemap_nopage関数が呼び出される. このパスは, ファイルシステムの章で説明したファイル読み込み処理とほぼ同等である. ページキャッシュに目的のファイルデータが載っていない場合, そのファイルinodeのreadpageオペレーションを呼び出し, ページキャッシュに読み込む.

do_no_page(タスク、仮想空間管理構造体vm_area_struct、アドレス...)
{
        if (ファイルマップされていない領域?) {
                単純物理ページ確保とマップ(do_anonymous_page関数)
                return;
        }
        仮想空間管理構造体vm_area_structのnopageオペレーションを呼び出す。
          (ext2fsの場合は、 filemap_nopage関数)

        pteのデータを生成(mk_pte関数)
        if(書きこみアクセスか) {
                書きこみ可とする(pte_mkwrite関数)
                dirtyのビットも立てておく(pte_mkdirty関数)
        } else if (共有mmapでないが、複数のプロセスで共有している) {
                書きこみ禁止とする(pte_wrprotect関数)
                  (※これに関しては、コピーオンライトの説明を見よ)
        }
        実際のページテーブルに登録(set_pte関数)
}

ファイルマップされていないページでのフォルトの場合は、下記関数において適当な空き物理ページを確保し、pteに登録する。readアクセスの場合はシステム全体で一つだけ用意されている0クリアされたページ(ZERO_PAGE)を登録(共有)する。

do_anonymous_page(タスク、仮想空間管理構造体vm_area_struct、....)
{
        if (writeアクセスなら) {
                空き物理ページを確保(alloc_page関数)
                確保した物理ページを0クリア(clear_page関数)
                pteデータの作成、書きこみ可とし、(pte_mkwrite関数)
                  dirtyのビットも立てておく(pte_mkdirty関数)
        } else { /* readアクセスなら */
                pteデータの作成、システム内に一つだけ用意された0クリア
                 されたページ(ZERO_PAGE)を書きこみ禁止でマップする
                 (pte_wrprotect関数)
                  (※これに関しては、コピーオンライトの説明を見よ)
        }
        実際のページテーブルに登録(set_pte関数)
}

ext2ファイルシステム上のファイルの場合、ファイルマップされたページでフォルトが発生すると、filemap_nopage関数が呼び出される。この関数はフォルトを発生させたページに対応するファイルのブロックを物理メモリ上の読み込む処理を行う。

filemap_nopage(仮想空間管理構造体vm_area_struct, アドレス, 共有mmapか?)
{
        pageキャッシュ上に無いか検索(__find_get_page関数)
        if(pageキャッシュ上に無い) {
                pageキャッシュを確保し、ファイルから読み込む(page_cache_read関数)
                   (可能ならまとめ読みする。read_cluster_nonblocking関数)
        }
        if(pageキャッシュが有効でない) {
                フォルトが発生したページを再読み込み
                   (inodeのreadpageオペレーション呼び出し)
        }
        先行readを行っておく(nopage_sequential_readahead関数)
        if (共有mmap域なら) {
                return このページを返却
        }
        新しいページを確保(page_cache_alloc関数)し、
          pageキャッシュの内容をそこにコピーする(copy_user_highpage関数)
        return 新しいページ
}
img69.gif

書き込み処理でdo_no_page関数が呼び出されたときは、確保した物理ページのPTEを書き込み可にしてマップする。

readアクセスによりdo_no_pageでマップされたばかりの空間は、write禁止の状態で生成される。(ファイルからの読み込みであれば、pageキャッシュ上に登録される)この空間に対して書き込みアクセスがあると、例外が発生しdo_wp_page関数が呼び出される。

do_wp_page関数はページキャッシュ内のページであればページキャッシュから落しPTEのWビットを立て書き込み可能とする。システム共有のZERO_PAGEであれば、そのページの複製を作りPTEを書き込み可能(Wビットを立てた)にし、複製したページを登録する。

処理は、下記コピーオンライトのルーチンと共用しており、do_wp_page関数の詳細はそちらを参照のこと。

img70.gif

(NIS)HirokazuTakahashi
2000年12月09日 (土) 23時55分06秒 JST
1