Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

nios2: Port OOM changes to do_page_fault()

Commit d065bd810b6d ("mm: retry page fault when blocking on disk transfer") and
and commit 37b23e0525d3 ("x86,mm: make pagefault killable")

The above commits introduced changes into the nios2 pagefault handler
for making the page fault handler retryable as well as killable.

These changes reduce the mmap_sem hold time, which is crucial
during OOM killer invocation.

Signed-off-by: Ley Foon Tan <lftan@altera.com>

+32 -5
+32 -5
arch/nios2/mm/fault.c
··· 47 47 struct mm_struct *mm = tsk->mm; 48 48 int code = SEGV_MAPERR; 49 49 int fault; 50 - unsigned int flags = 0; 50 + unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; 51 51 52 52 cause >>= 2; 53 53 ··· 86 86 if (!down_read_trylock(&mm->mmap_sem)) { 87 87 if (!user_mode(regs) && !search_exception_tables(regs->ea)) 88 88 goto bad_area_nosemaphore; 89 + retry: 89 90 down_read(&mm->mmap_sem); 90 91 } 91 92 ··· 133 132 * the fault. 134 133 */ 135 134 fault = handle_mm_fault(mm, vma, address, flags); 135 + 136 + if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) 137 + return; 138 + 136 139 if (unlikely(fault & VM_FAULT_ERROR)) { 137 140 if (fault & VM_FAULT_OOM) 138 141 goto out_of_memory; ··· 146 141 goto do_sigbus; 147 142 BUG(); 148 143 } 149 - if (fault & VM_FAULT_MAJOR) 150 - tsk->maj_flt++; 151 - else 152 - tsk->min_flt++; 144 + 145 + /* 146 + * Major/minor page fault accounting is only done on the 147 + * initial attempt. If we go through a retry, it is extremely 148 + * likely that the page will be found in page cache at that point. 149 + */ 150 + if (flags & FAULT_FLAG_ALLOW_RETRY) { 151 + if (fault & VM_FAULT_MAJOR) 152 + current->maj_flt++; 153 + else 154 + current->min_flt++; 155 + if (fault & VM_FAULT_RETRY) { 156 + /* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk 157 + * of starvation. */ 158 + flags &= ~FAULT_FLAG_ALLOW_RETRY; 159 + flags |= FAULT_FLAG_TRIED; 160 + 161 + /* 162 + * No need to up_read(&mm->mmap_sem) as we would 163 + * have already released it in __lock_page_or_retry 164 + * in mm/filemap.c. 165 + */ 166 + 167 + goto retry; 168 + } 169 + } 153 170 154 171 up_read(&mm->mmap_sem); 155 172 return;