彩色科技|linux内核写时复制机制源代码解读( 二 )

以上过程就完成了对于需要写时复制的页 , 将父子进程的页表项改写为只读(这时候vma的属性是可写的) , 并共享相同的物理页 , 这为下面的COW缺页异常做好了页表级别的准备工作 。
二 , COW缺页异常触发条件当然如果父子进程仅仅是对COW共享的页面做只读访问 , 则通过各自的页表就能直接访问到对应的数据 , 一切都正常 , 一旦有一方去写 , 就会发生处理器异常 , 处理器会判断出是COW缺页异常:
arm64处理器处理过程:
彩色科技|linux内核写时复制机制源代码解读我们从handle_pte_fault函数开始分析:
3800if (vmf->flags //处理cow3803entry = pte_mkdirty(entry);3804}程序走到上面的判断说明:页表项存在 , 物理页存在内存 , 但是vma是可写 , pte页表项是只读属性(这就是fork的时候所作的准备) , 这些条件也是COW缺页异常判断的条件 。
三,发生COW缺页异常当内核判断了这次异常时COW缺页异常 , 就会调用do_wp_page进行处理:
2480 static vm_fault_t do_wp_page(struct vm_fault *vmf)2481__releases(vmf->ptl)2482 {2483struct vm_area_struct *vma = vmf->vma;24842485vmf->page = vm_normal_page(vma, vmf->address, vmf->orig_pte);//获得异常地址对应的page实例2486if (!vmf->page) {2487/*2488|* VM_MIXEDMAP !pfn_valid() case, or VM_SOFTDIRTY clear on a2489|* VM_PFNMAP VMA.2490|*2491|* We should not cow pages in a shared writeable mapping.2492|* Just mark the pages writable and/or call ops->pfn_mkwrite.2493|*/2494if ((vma->vm_flags //处理共享可写映射24972498pte_unmap_unlock(vmf->pte, vmf->ptl);2499return wp_page_copy(vmf);//处理私有可写映射2500}2485行 , 获得发生异常时地址所在的page结构 , 如果没有page结构是使用页帧号的特殊映射 , 则通过wp_pfn_shared处理共享可写映射 , wp_page_copy处理私有可写映射 , 当然这不是我们分析重点 。
我们继续往下分析:
我们主要关注2522行 , 判断是否可以重新使用这个页 , 这个稍后在分析 。
2544|* Ok, we need to copy. Oh, well..2545|*/2546get_page(vmf->page);25472548pte_unmap_unlock(vmf->pte, vmf->ptl);2549return wp_page_copy(vmf);2546行 增加原来的页的引用计数 , 防止被释放 。
2548行 释放页表锁
2549行 这是COW处理的核心函数
我们下面将详细分析wp_page_copy函数:
* - Allocate a page, copy the content of the old page to the new one.2234* - Handle book keeping and accounting - cgroups, mmu-notifiers, etc.2235* - Take the PTL. If the pte changed, bail out and release the allocated page2236* - If the pte is still the way we remember it, update the page table and all2237*relevant references. This includes dropping the reference the page-table2238*held to the old page, as well as updating the rmap.2239* - In any case, unlock the PTL and drop the reference we took to the old page.2240*/2241 static vm_fault_t wp_page_copy(struct vm_fault *vmf)2242 {2243struct vm_area_struct *vma = vmf->vma;2244struct mm_struct *mm = vma->vm_mm;2245struct page *old_page = vmf->page;2246struct page *new_page = NULL;2247pte_t entry;2248int page_copied = 0;2249struct mem_cgroup *memcg;2250struct mmu_notifier_range range;22512252if (unlikely(anon_vma_prepare(vma)))2253goto oom;22542255if (is_zero_pfn(pte_pfn(vmf->orig_pte))) {2256new_page = alloc_zeroed_user_highpage_movable(vma,2257|vmf->address);2258if (!new_page)2259goto oom;2260} else {2261new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma,2262vmf->address);2263if (!new_page)2264goto oom;2265cow_user_page(new_page, old_page, vmf->address, vma);2266}


推荐阅读