Commit 5e91bf5c authored by Vineet Gupta's avatar Vineet Gupta
Browse files

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: default avatarVineet Gupta <vgupta@synopsys.com>
parent 98cb57ad
Loading
Loading
Loading
Loading
+14 −34
Original line number Diff line number Diff line
@@ -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;

out_of_memory:
	up_read(&mm->mmap_sem);

	if (!user_mode(regs))
		goto no_context;

	if (fault & VM_FAULT_OOM) {
		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: