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

概要

  • linux2.6/mm/memory.cにて定義
  • 引数で渡された開始アドレスから終了アドレス(またはメモリディスクリプタに登録されているメモリリージョン群のアドレス範囲)までの物理ページ(ページフレーム)とのマッピングを解除する

引数

  • tlbp--TLBを管理する構造体
  • mm--メモリディスクリプタ
  • vma--メモリリージョン
  • start_addr--unmapする開始アドレス
  • end_addr--unmapする終了アドレス
  • nr_accounted--
  • details--
    • zap_details/linux2.6?を参照

実装

/**

* unmap_vmas - unmap a range of memory covered by a list of vma's
* @tlbp: address of the caller's struct mmu_gather
* @mm: the controlling mm_struct
* @vma: the starting vma
* @start_addr: virtual address at which to start unmapping
* @end_addr: virtual address at which to end unmapping
* @nr_accounted: Place number of unmapped pages in vm-accountable vma's here
* @details: details of nonlinear truncation or shared cache invalidation
*
* Returns the number of vma's which were covered by the unmapping.
*
* Unmap all pages in the vma list.  Called under page_table_lock.
*
* We aim to not hold page_table_lock for too long (for scheduling latency
* reasons).  So zap pages in ZAP_BLOCK_SIZE bytecounts.  This means we need to
* return the ending mmu_gather to the caller.
*
* Only addresses between `start' and `end' will be unmapped.
*
* The VMA list must be sorted in ascending virtual address order.
*
* unmap_vmas() assumes that the caller will flush the whole unmapped address
* range after unmap_vmas() returns.  So the only responsibility here is to
* ensure that any thus-far unmapped pages are flushed before unmap_vmas()
* drops the lock and schedules.
*/

int unmap_vmas(struct mmu_gather **tlbp, struct mm_struct *mm,

		struct vm_area_struct *vma, unsigned long start_addr,
		unsigned long end_addr, unsigned long *nr_accounted,
		struct zap_details *details)

{

	unsigned long zap_bytes = ZAP_BLOCK_SIZE;
	unsigned long tlb_start = 0;	/* For tlb_finish_mmu */
	int tlb_start_valid = 0;
	int ret = 0;
	int atomic = details && details->atomic;
	for ( ; vma && vma->vm_start < end_addr; vma = vma->vm_next) {
  • vma->start〜end_addrまでの間をunmapする
		unsigned long start;
		unsigned long end;
		start = max(vma->vm_start, start_addr);
  • vma->vm_startとstart_addrの2つの値のうち、大きいほうを返す
		if (start >= vma->vm_end)
			continue;
  • startがvmaの領域に含まれていない場合はcontinue
		end = min(vma->vm_end, end_addr);
  • vma->vm_endとend_addrの2つの値のうち、小さいほうを返す


  • これより下は、startとendは同一vma内の領域である
		if (end <= vma->vm_start)
			continue;
  • endがvmaの開始アドレスより小さい場合はcontinue
		if (vma->vm_flags & VM_ACCOUNT)
			*nr_accounted += (end - start) >> PAGE_SHIFT;
  • vmaが課金対象である場合、nr_accountedへstart〜endのページ数を加算する
		ret++;
		while (start != end) {
  • 同一vma内のstart〜endの領域を走査する:
			unsigned long block;
			if (!tlb_start_valid) {
				tlb_start = start;
				tlb_start_valid = 1;
			}
			if (is_vm_hugetlb_page(vma)) {
				block = end - start;
				unmap_hugepage_range(vma, start, end);
			} else {
				block = min(zap_bytes, end - start);
  • zap_bytesと(end - start)の2つの値のうち、小さいほうを返す
				unmap_page_range(*tlbp, vma, start,
						start + block, details);
  • 開始アドレスstartから終了アドレス(start + block)までの物理ページ(ページフレーム)とのマッピングを解除する
			}
			start += block;
			zap_bytes -= block;
			if ((long)zap_bytes > 0)
				continue;
			if (!atomic && need_resched()) {
  • 再スケジュール要求が出されているか調べる
				int fullmm = tlb_is_full_mm(*tlbp);
  • tlbpに対応するメモリディスクリプタをフラッシュするか返す
				tlb_finish_mmu(*tlbp, tlb_start, start);
				cond_resched_lock(&mm->page_table_lock);
  • このスレッドが再スケジュール要求を出している場合は、ロックmm->page_table_lockを解放しスケジューラを呼び出しCPUを手放す
    • CPUが再び戻ってきたときはロックmm->page_table_lockを取得してこの関数を終了する
    • 詳細はcond_resched_lock()/linux2.6を参照
				*tlbp = tlb_gather_mmu(mm, fullmm);
  • 引数で渡された情報(mmとfullmm)よりTLBを管理する構造体を作成し、返す
				tlb_start_valid = 0;
			}
			zap_bytes = ZAP_BLOCK_SIZE;
		}
	}
	return ret;

}

呼出元


履歴

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

コメント



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