- 论坛徽章:
- 0
|
回复 12# chishanmingshen
1. ok
2. 貌似跟你理解的不一样...
/*
* These routines also need to handle stuff like marking pages dirty
* and/or accessed for architectures that don't do it in hardware (most
* RISC architectures). The early dirtying is also good on the i386.
*
* There is also a hook called "update_mmu_cache()" that architectures
* with external mmu caches can use to update those (ie the Sparc or
* PowerPC hashed page tables that act as extended TLBs).
*
* We enter with non-exclusive mmap_sem (to exclude vma changes,
* but allow concurrent faults), and pte mapped but not yet locked.
* We return with mmap_sem still held, but pte unmapped and unlocked.
*/
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;
spinlock_t *ptl;
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);
}
ptl = pte_lockptr(mm, pmd);
spin_lock(ptl);
if (unlikely(!pte_same(*pte, entry)))<--到这里应该一直same啊!没有不same的时候...?
/* 有可能在上面entry = *pte;取出entry到if這個statement中間有另外一個process or thread比較早發生page fault
* 並且已經改變了*pte的值。因此有可能造成不same的狀況。而改變*pte有可能包含上面四種faults,和下面這個do_wp_page。
*/
goto unlock;
if (flags & FAULT_FLAG_WRITE) {
/* 兩個threads or processes同時發生fault,有可能我這個thread/process跑在後面,在entry=*pte之前另一個prcoess/thread
* 就已經把do_wp_page() fault處理完了,這時候有可能發生pte_write=1的情況(可寫),這時候下面ptep_set_access_flags會是false代表相同。
* 因為另一個thread/process以經幫我們設pte_mkdirty & pte_mkyoung。
* 該做的是把tlb flush掉,也就是下面的else。但感覺也可以不用作,因為另一個process/thread應該會打ipi通知我們做flush tlb的動作。
* 像是arm A15有tlb coherency則完全不用作flush。
*/
if (!pte_write(entry))
return do_wp_page(mm, vma, address,
pte, pmd, ptl, entry);
entry = pte_mkdirty(entry);<------此处会改entry,所以下面的ptep_set_access_flags()会有不same的时候
}
entry = pte_mkyoung(entry);<----此处会改entry,所以下面的ptep_set_access_flags()会有不same的时候
if (ptep_set_access_flags(vma, address, pte, entry, flags & FAULT_FLAG_WRITE)) {
update_mmu_cache(vma, address, pte);
} else {
/*
* This is needed only for protection faults but the arch code
* is not yet telling us if this is a protection fault or not.
* This still avoids useless tlb flushes for .text page faults
* with threads.
*/
if (flags & FAULT_FLAG_WRITE)
flush_tlb_fix_spurious_fault(vma, address);
}
unlock:
pte_unmap_unlock(pte, ptl);
return 0;
}
|
|