我一直试图理解它是如何fork()
工作的,并最终到达了copy_pte_range()
.大多数功能都是可以理解的,但很少有值得怀疑的。
核心: 84年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);
函数开头的行的影响。