ARC: mm: do_page_fault refactor #7: fold the various error handling

- single up_read() call vs. 4
 - so much easier on eyes

Technically it seems like @bad_area label moved up, but even in old
regime, it was a special case of delivering SIGSEGV unconditionally
which we now do as well, although with checks.

Also note that @fault needs to be initialized since we can land in
@bad_area (which reads it) without setting it up with return value of
handle_mm_fault() - failing to do so did bite us although as a side
effect of different patch: see [1]

[1]: http://lists.infradead.org/pipermail/linux-snps-arc/2019-May/005803.html

Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
This commit is contained in:
Vineet Gupta 2019-05-14 15:55:31 -07:00
parent 98cb57ad70
commit 5e91bf5ce9

View File

@ -63,9 +63,9 @@ void do_page_fault(unsigned long address, struct pt_regs *regs)
struct vm_area_struct *vma = NULL;
struct task_struct *tsk = current;
struct mm_struct *mm = tsk->mm;
int si_code = SEGV_MAPERR;
int sig, si_code = SEGV_MAPERR;
unsigned int write = 0, exec = 0, mask;
vm_fault_t fault; /* handle_mm_fault() output */
vm_fault_t fault = VM_FAULT_SIGSEGV; /* handle_mm_fault() output */
unsigned int flags; /* handle_mm_fault() input */
/*
@ -174,47 +174,27 @@ retry:
return;
}
if (fault & VM_FAULT_OOM)
goto out_of_memory;
else if (fault & VM_FAULT_SIGSEGV)
goto bad_area;
else if (fault & VM_FAULT_SIGBUS)
goto do_sigbus;
/* no man's land */
BUG();
/*
* Something tried to access memory that isn't in our memory map..
* Fix it, but check if it's kernel or user first..
*/
bad_area:
up_read(&mm->mmap_sem);
if (!user_mode(regs))
goto no_context;
tsk->thread.fault_address = address;
force_sig_fault(SIGSEGV, si_code, (void __user *)address, tsk);
return;
if (fault & VM_FAULT_OOM) {
pagefault_out_of_memory();
return;
}
out_of_memory:
up_read(&mm->mmap_sem);
if (!user_mode(regs))
goto no_context;
pagefault_out_of_memory();
return;
do_sigbus:
up_read(&mm->mmap_sem);
if (!user_mode(regs))
goto no_context;
if (fault & VM_FAULT_SIGBUS) {
sig = SIGBUS;
si_code = BUS_ADRERR;
}
else {
sig = SIGSEGV;
}
tsk->thread.fault_address = address;
force_sig_fault(SIGBUS, BUS_ADRERR, (void __user *)address, tsk);
force_sig_fault(sig, si_code, (void __user *)address, tsk);
return;
no_context: