int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long address, unsigned int flags) { pgd_t *pgd; pud_t *pud; pmd_t *pmd; pte_t *pte; if (unlikely(is_vm_hugetlb_page(vma))) return hugetlb_fault(mm, vma, address, flags); pgd = pgd_offset(mm, address); pud = pud_alloc(mm, pgd, address); pmd = pmd_alloc(mm, pud, address); pte = pte_alloc_map(mm, pmd, address); return handle_pte_fault(mm, vma, address, pte, pmd, flags); }
address对应的pte_t指针,其值is hoped to filled by page frame number, pfn,
但很多时候,新分配出来的pte表是全0的一个page,因此他的成员pte entry也就是0了,即*(pte_t) = 0
可以看出,在走到handle_pte_fault时,页表已建好对应vaddr的从pgd->pmd->pud->pte的路径,并搜索出对static inline int handle_pte_fault(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long address, pte_t *pte, pmd_t *pmd, unsigned int flags) { pte_t entry; entry = *pte; if (!pte_present(entry)) { if (pte_none(entry)) { if (vma->vm_ops) { if (likely(vma->vm_ops->fault)) return do_linear_fault(mm, vma, address, pte, pmd, flags, entry); } return do_anonymous_page(mm, vma, address, pte, pmd, flags); } if (pte_file(entry)) return do_nonlinear_fault(mm, vma, address, pte, pmd, flags, entry); return do_swap_page(mm, vma, address, pte, pmd, flags, entry); } if (flags & FAULT_FLAG_WRITE) { if (!pte_write(entry)) return do_wp_page(mm, vma, address, pte, pmd, ptl, entry); entry = pte_mkdirty(entry); } flush_tlb_page(vma, address); }
The MAP_SHARED and MAP_PRIVATE options describe the disposition of write references to the underlying object. If MAP_SHARED is specified, write references will change the memory object. If MAP_PRIVATE is specified, the initial write reference will create a private copy of the memory object page and redirect the mapping to the copy. The private copy is not created until the first write; until then, other users who have the object mapped MAP_SHARED can change the object. Either MAP_SHARED or MAP_PRIVATE must be specified, but not both. The mapping type is retained across fork(2).
static int do_linear_fault(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long address, pmd_t *pmd, pgoff_t pgoff, unsigned int flags, pte_t orig_pte) { ret = vma->vm_ops->fault(vma, &vmf); //分配一个新页面 /* * 根据注释,满足下面1,2条件时,会进行cow */ if (flags & FAULT_FLAG_WRITE) { //1.如果是写操作引起的异常 if (!(vma->vm_flags & VM_SHARED)) { //2. 此空间是MAP_PRIVATE标志 page = alloc_page_vma(vma, address); //分配新页 copy_user_highpage(page, vmf.page, address, vma);//将原页数据拷贝到新页 } entry = mk_pte(page, vma->vm_page_prot); //按新页生成pte entry //将此页置可写,以避免其他路径也触发COW if (flags & FAULT_FLAG_WRITE) entry = maybe_mkwrite(pte_mkdirty(entry), vma); set_pte_at(mm, address, page_table, entry); //设置到页表 }
if (is_cow_mapping(vm_flags)) { ptep_set_wrprotect(src_mm, addr, src_pte); pte = pte_wrprotect(pte); }
if (flags & FAULT_FLAG_WRITE) { if (!pte_write(entry))