I think there is an inconsistency in this patch that can cause a deadlock:
Consider that the code first takes the &mm->mmap_sem lock during if (!down_read_trylock(&mm->mmap_sem)) {
@@ -305,6 +297,7 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) if (!down_read_trylock(&mm->mmap_sem)) { if (!user_mode(regs) && !search_exception_tables(regs->ARM_pc)) goto no_context; +retry: down_read(&mm->mmap_sem); } else { /* @@ -320,14 +313,41 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) #endif }
and then later manage to take the goto retry; this will will cause a deadlock when trying to take the &mm->mmap_sem twice.
+ if (flags & FAULT_FLAG_ALLOW_RETRY) { + if (fault & VM_FAULT_MAJOR) { + tsk->maj_flt++; + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, + regs, addr); + } else { + tsk->min_flt++; + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, + regs, addr); + } + if (fault & VM_FAULT_RETRY) { + /* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk + * of starvation. */ + flags &= ~FAULT_FLAG_ALLOW_RETRY; + goto retry; + } + } + + up_read(&mm->mmap_sem);
I think there is an inconsistency in this patch that can cause a deadlock:
Consider that the code first takes the &mm->mmap_sem lock during if (!down_ read_trylock( &mm->mmap_ sem)) {
@@ -305,6 +297,7 @@ do_page_ fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) read_trylock( &mm->mmap_ sem)) { exception_ tables( regs->ARM_ pc)) read(&mm- >mmap_sem) ; fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
if (!down_
if (!user_mode(regs) && !search_
goto no_context;
+retry:
down_
} else {
/*
@@ -320,14 +313,41 @@ do_page_
#endif
}
and then later manage to take the goto retry;
this will will cause a deadlock when trying to take the &mm->mmap_sem twice.
+ if (flags & FAULT_FLAG_ ALLOW_RETRY) { event(PERF_ COUNT_SW_ PAGE_FAULTS_ MAJ, 1, event(PERF_ COUNT_SW_ PAGE_FAULTS_ MIN, 1, ALLOW_RETRY to avoid any risk FLAG_ALLOW_ RETRY; &mm->mmap_ sem);
+ if (fault & VM_FAULT_MAJOR) {
+ tsk->maj_flt++;
+ perf_sw_
+ regs, addr);
+ } else {
+ tsk->min_flt++;
+ perf_sw_
+ regs, addr);
+ }
+ if (fault & VM_FAULT_RETRY) {
+ /* Clear FAULT_FLAG_
+ * of starvation. */
+ flags &= ~FAULT_
+ goto retry;
+ }
+ }
+
+ up_read(