このページを編集する際は、編集に関する方針に従ってください。

概要

  • linux2.6/mm/rmap.cにて定義
  • 引数で渡されたクラスタ(一定のページの塊(例えば32ページ))の範囲のページを物理ページとのマッピングを解除する
    • アンマップしたページは解放する

引数

  • cursor--クラスタアドレス(メモリリージョン内のオフセットアドレス)
  • mapcount--物理ページとマッピングされているページ数
  • vma--メモリリージョン

実装

static void try_to_unmap_cluster(unsigned long cursor,

	unsigned int *mapcount, struct vm_area_struct *vma)

{

	struct mm_struct *mm = vma->vm_mm;
  • vmaが属しているメモリディスクリプタをmmに設定する
	pgd_t *pgd;
  • ページグローバルディレクトリ
	pmd_t *pmd;
  • ページミドルディレクトリ
	pte_t *pte;
	pte_t pteval;
  • ページテーブルエントリ
	struct page *page;
	unsigned long address;
  • クラスタの開始アドレスを設定
	unsigned long end;
  • クラスタの終了アドレスを設定
	unsigned long pfn;
	/*
	 * We need the page_table_lock to protect us from page faults,
	 * munmap, fork, etc...
	 */
	spin_lock(&mm->page_table_lock);
  • スピンロックmm->page_table_lockの取得を試みる
    • ロックの取得に失敗した場合は待ち状態に入る
    • 詳細はspin_lock()/linux2.6を参照
	address = (vma->vm_start + cursor) & CLUSTER_MASK;
  • クラスタの開始アドレスをadressに設定
	end = address + CLUSTER_SIZE;
  • クラスタの終了アドレスをendへ設定
    • CLUSTER_SIZEは3レベルページングの場合は32ページである
	if (address < vma->vm_start)
		address = vma->vm_start;
	if (end > vma->vm_end)
		end = vma->vm_end;
  • クラスタの領域がvmaから溢れている場合はvma内に収める
	pgd = pgd_offset(mm, address);
  • addressに対応するページグローバルディレクトリを返す
	if (!pgd_present(*pgd))
		goto out_unlock;
	pmd = pmd_offset(pgd, address);
  • 引数で渡された情報に基づきページミドルディレクトリの特定エントリのアドレスを返す
	if (!pmd_present(*pmd))
		goto out_unlock;
  • 引数で渡されたページミドルディレクトリがメモリ上に存在する場合は1を返す。そうでない場合は0を返す
	for (pte = pte_offset_map(pmd, address);
			address < end; pte++, address += PAGE_SIZE) {
  • adress〜endまでページテーブルエントリを走査する:
		if (!pte_present(*pte))
			continue;
  • ページテーブルエントリpteに対応する物理ページが存在するか判定する
		pfn = pte_pfn(*pte);
  • ページテーブルエントリpteに対応するページフレーム番号を返す
		if (!pfn_valid(pfn))
			continue;
  • ページフレームpfnが適切な値であるかチェックする
		page = pfn_to_page(pfn);
  • ページフレーム番号pfnからページ(page構造体)を見つける
		BUG_ON(PageAnon(page));
  • ページpageがユーザ仮想メモリにマッピングされている場合、1を返して終了
		if (PageReserved(page))
			continue;
  • ページpageが予約されているか調べる
    • 予約されている場合1を返し、予約されていない場合は0を返す
    • 詳細はPageReserved()/linux2.6を参照
		if (ptep_clear_flush_young(vma, address, pte))
			continue;
  • ページテーブルエントリpteのアクセスフラグをクリアし、参照している(自分を含まない)CPUに対して仮想アドレスaddressに対応するTLBの無効要求を送信する
		/* Nuke the page table entry. */
		flush_cache_page(vma, address);
		pteval = ptep_clear_flush(vma, address, pte);
  • ページテーブルエントリpteをクリアし、クリアされる前のページテーブルエントリを返す
		/* If nonlinear, store the file page offset in the pte. */
		if (page->index != linear_page_index(vma, address))
			set_pte(pte, pgoff_to_pte(page->index));
  • 仮想アドレスaddressに対応する(メモリリージョン内の)ページオフセットを返す
  • オフセットpage->indexを用いてページテーブルエントリを作り、返す
  • 設定元のページテーブルエントリpgoff_to_pte(page->index)の情報を設定先のページテーブルエントリpteへコピーする
		/* Move the dirty bit to the physical page now the pte is gone. */
		if (pte_dirty(pteval))
			set_page_dirty(page);
  • ページテーブルエントリptevalが更新されているか調べる
    • 更新されている場合は1を、そうでない場合は0を返す
    • 詳細はpte_dirty()/linux2.6を参照
  • ページpageの更新フラグを設定する
		page_remove_rmap(page);
		page_cache_release(page);
		mm->rss--;
		(*mapcount)--;
	}
	pte_unmap(pte);

out_unlock:

	spin_unlock(&mm->page_table_lock);
  • スピンロックmm->page_table_lockの開放を行う。プリエンプション機能を有効にし、可能であれば自ら積極的にプリエンプション(実行権の移譲を行うこと)する

}

呼出元


履歴

  • 作者:ひら
  • 日付:2005/11/29
  • 対象:2.6.10
    更新日更新者更新内容

コメント



トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2009-11-24 (火) 07:19:57 (2921d)