Linux
關於核心中copy_pte_range()的兩個問題
我一直在試圖了解它是如何
fork()
工作的,最終到達了copy_pte_range()
. 大多數功能是可以理解的,但很少有非常值得懷疑的。核心:4.14.84
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; }
問題
- 在 中,變數
do {} while()
的用途是什麼?- 之後,為什麼需要它?這是 的過程。根據我的知識,仍應映射父級,因為該過程基於寫時複製,所以我想不必取消映射。
progress
do {} while()``pte_unmap(orig_src_pte);``fork()``pte(orig_src_pte)
- 該
progress
變數衡量在鎖下執行的操作的成本,並避免持有這些鎖太久。最多每 32 次呼叫pte_none
,或 4 次呼叫copy_one_pte
(代價高昂),或兩者的組合,該函式檢查是否需要重新調度,或者是否在其他地方請求了鎖;如果是這樣,它會釋放鎖並允許重新安排。由於跳轉到again
.- unmap 呼叫不會取消映射源程序中的原始 PTE,它會撤消
src_pte = pte_offset_map(src_pmd, addr);
函式開頭的行的影響。