私はそれがどのように機能するかを理解しようとし、fork()
ついに到着しましたcopy_pte_range()
。ほとんどの機能は理解できますが、疑わしいことはほとんどありません。
コア:1984年4月14日
static int copy_pte_range(struct mm_struct *dst_mm, struct mm_struct *src_mm,
pmd_t *dst_pmd, pmd_t *src_pmd, struct vm_area_struct *vma,
unsigned long addr, unsigned long end)
{
pte_t *orig_src_pte, *orig_dst_pte;
pte_t *src_pte, *dst_pte;
spinlock_t *src_ptl, *dst_ptl;
int progress = 0;
int rss[NR_MM_COUNTERS];
swp_entry_t entry = (swp_entry_t){0};
again:
init_rss_vec(rss);
dst_pte = pte_alloc_map_lock(dst_mm, dst_pmd, addr, &dst_ptl);
if (!dst_pte)
return -ENOMEM;
src_pte = pte_offset_map(src_pmd, addr);
src_ptl = pte_lockptr(src_mm, src_pmd);
spin_lock_nested(src_ptl, SINGLE_DEPTH_NESTING);
orig_src_pte = src_pte;
orig_dst_pte = dst_pte;
arch_enter_lazy_mmu_mode();
do {
/*
* We are holding two locks at this point - either of them
* could generate latencies in another task on another CPU.
*/
if (progress >= 32) {
progress = 0;
if (need_resched() ||
spin_needbreak(src_ptl) || spin_needbreak(dst_ptl))
break;
}
if (pte_none(*src_pte)) {
progress++;
continue;
}
entry.val = copy_one_pte(dst_mm, src_mm, dst_pte, src_pte,
vma, addr, rss);
if (entry.val)
break;
progress += 8;
} while (dst_pte++, src_pte++, addr += PAGE_SIZE, addr != end);
arch_leave_lazy_mmu_mode();
spin_unlock(src_ptl);
pte_unmap(orig_src_pte);
add_mm_rss_vec(dst_mm, rss);
pte_unmap_unlock(orig_dst_pte, dst_ptl);
cond_resched();
if (entry.val) {
if (add_swap_count_continuation(entry, GFP_KERNEL) < 0)
return -ENOMEM;
progress = 0;
}
if (addr != end)
goto again;
return 0;
}
質問
1.do {} while()
変数の目的は何ですか? 2. その後はなぜ必要なのでしょうか。これがプロセスです。私が知っているのは、プロセスが書き込み中のコピーに基づいているため、親はまだマッピングする必要があるため、マッピングを解除する必要はないようです。progress
do {} while()
pte_unmap(orig_src_pte);
fork()
pte(orig_src_pte)
答え1
この
progress
変数は、ロック状態で実行される作業コストと、これらのロックを長期間維持するのを防ぐコストを測定します。最大32回の呼び出しpte_none
、4回の呼び出しcopy_one_pte
(高価)、またはその組み合わせごとに、関数はスケジューリングが必要かどうかを確認し、必要に応じてロックを解除してスケジュールの変更を許可します。にジャンプするため、関数は中断された位置から続きますagain
。unmap 呼び出しは、ソース・プロセスから元の PTE のマッピングを解放せず、
src_pte = pte_offset_map(src_pmd, addr);
関数の先頭の行効果を取り消します。