mm/fault: convert remaining simple cases to lock_mm_and_find_vma()
commit a050ba1e74
upstream.
This does the simple pattern conversion of alpha, arc, csky, hexagon,
loongarch, nios2, sh, sparc32, and xtensa to the lock_mm_and_find_vma()
helper. They all have the regular fault handling pattern without odd
special cases.
The remaining architectures all have something that keeps us from a
straightforward conversion: ia64 and parisc have stacks that can grow
both up as well as down (and ia64 has special address region checks).
And m68k, microblaze, openrisc, sparc64, and um end up having extra
rules about only expanding the stack down a limited amount below the
user space stack pointer. That is something that x86 used to do too
(long long ago), and it probably could just be skipped, but it still
makes the conversion less than trivial.
Note that this conversion was done manually and with the exception of
alpha without any build testing, because I have a fairly limited cross-
building environment. The cases are all simple, and I went through the
changes several times, but...
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Samuel Mendoza-Jonas <samjonas@amazon.com>
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
1f4197f050
commit
21ee33d51b
|
@ -28,6 +28,7 @@ config ALPHA
|
|||
select GENERIC_SMP_IDLE_THREAD
|
||||
select HAVE_ARCH_AUDITSYSCALL
|
||||
select HAVE_MOD_ARCH_SPECIFIC
|
||||
select LOCK_MM_AND_FIND_VMA
|
||||
select MODULES_USE_ELF_RELA
|
||||
select ODD_RT_SIGACTION
|
||||
select OLD_SIGSUSPEND
|
||||
|
|
|
@ -119,20 +119,12 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
|
|||
flags |= FAULT_FLAG_USER;
|
||||
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
|
||||
retry:
|
||||
mmap_read_lock(mm);
|
||||
vma = find_vma(mm, address);
|
||||
vma = lock_mm_and_find_vma(mm, address, regs);
|
||||
if (!vma)
|
||||
goto bad_area;
|
||||
if (vma->vm_start <= address)
|
||||
goto good_area;
|
||||
if (!(vma->vm_flags & VM_GROWSDOWN))
|
||||
goto bad_area;
|
||||
if (expand_stack(vma, address))
|
||||
goto bad_area;
|
||||
goto bad_area_nosemaphore;
|
||||
|
||||
/* Ok, we have a good vm_area for this memory access, so
|
||||
we can handle it. */
|
||||
good_area:
|
||||
si_code = SEGV_ACCERR;
|
||||
if (cause < 0) {
|
||||
if (!(vma->vm_flags & VM_EXEC))
|
||||
|
@ -189,6 +181,7 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
|
|||
bad_area:
|
||||
mmap_read_unlock(mm);
|
||||
|
||||
bad_area_nosemaphore:
|
||||
if (user_mode(regs))
|
||||
goto do_sigsegv;
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ config ARC
|
|||
select HAVE_PERF_EVENTS
|
||||
select HAVE_SYSCALL_TRACEPOINTS
|
||||
select IRQ_DOMAIN
|
||||
select LOCK_MM_AND_FIND_VMA
|
||||
select MODULES_USE_ELF_RELA
|
||||
select OF
|
||||
select OF_EARLY_FLATTREE
|
||||
|
|
|
@ -113,15 +113,9 @@ void do_page_fault(unsigned long address, struct pt_regs *regs)
|
|||
|
||||
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
|
||||
retry:
|
||||
mmap_read_lock(mm);
|
||||
|
||||
vma = find_vma(mm, address);
|
||||
vma = lock_mm_and_find_vma(mm, address, regs);
|
||||
if (!vma)
|
||||
goto bad_area;
|
||||
if (unlikely(address < vma->vm_start)) {
|
||||
if (!(vma->vm_flags & VM_GROWSDOWN) || expand_stack(vma, address))
|
||||
goto bad_area;
|
||||
}
|
||||
goto bad_area_nosemaphore;
|
||||
|
||||
/*
|
||||
* vm_area is good, now check permissions for this memory access
|
||||
|
@ -161,6 +155,7 @@ void do_page_fault(unsigned long address, struct pt_regs *regs)
|
|||
bad_area:
|
||||
mmap_read_unlock(mm);
|
||||
|
||||
bad_area_nosemaphore:
|
||||
/*
|
||||
* Major/minor page fault accounting
|
||||
* (in case of retry we only land here once)
|
||||
|
|
|
@ -96,6 +96,7 @@ config CSKY
|
|||
select HAVE_RSEQ
|
||||
select HAVE_STACKPROTECTOR
|
||||
select HAVE_SYSCALL_TRACEPOINTS
|
||||
select LOCK_MM_AND_FIND_VMA
|
||||
select MAY_HAVE_SPARSE_IRQ
|
||||
select MODULES_USE_ELF_RELA if MODULES
|
||||
select OF
|
||||
|
|
|
@ -97,13 +97,12 @@ static inline void mm_fault_error(struct pt_regs *regs, unsigned long addr, vm_f
|
|||
BUG();
|
||||
}
|
||||
|
||||
static inline void bad_area(struct pt_regs *regs, struct mm_struct *mm, int code, unsigned long addr)
|
||||
static inline void bad_area_nosemaphore(struct pt_regs *regs, struct mm_struct *mm, int code, unsigned long addr)
|
||||
{
|
||||
/*
|
||||
* Something tried to access memory that isn't in our memory map.
|
||||
* Fix it, but check if it's kernel or user first.
|
||||
*/
|
||||
mmap_read_unlock(mm);
|
||||
/* User mode accesses just cause a SIGSEGV */
|
||||
if (user_mode(regs)) {
|
||||
do_trap(regs, SIGSEGV, code, addr);
|
||||
|
@ -238,20 +237,9 @@ asmlinkage void do_page_fault(struct pt_regs *regs)
|
|||
if (is_write(regs))
|
||||
flags |= FAULT_FLAG_WRITE;
|
||||
retry:
|
||||
mmap_read_lock(mm);
|
||||
vma = find_vma(mm, addr);
|
||||
vma = lock_mm_and_find_vma(mm, address, regs);
|
||||
if (unlikely(!vma)) {
|
||||
bad_area(regs, mm, code, addr);
|
||||
return;
|
||||
}
|
||||
if (likely(vma->vm_start <= addr))
|
||||
goto good_area;
|
||||
if (unlikely(!(vma->vm_flags & VM_GROWSDOWN))) {
|
||||
bad_area(regs, mm, code, addr);
|
||||
return;
|
||||
}
|
||||
if (unlikely(expand_stack(vma, addr))) {
|
||||
bad_area(regs, mm, code, addr);
|
||||
bad_area_nosemaphore(regs, mm, code, addr);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -259,11 +247,11 @@ asmlinkage void do_page_fault(struct pt_regs *regs)
|
|||
* Ok, we have a good vm_area for this memory access, so
|
||||
* we can handle it.
|
||||
*/
|
||||
good_area:
|
||||
code = SEGV_ACCERR;
|
||||
|
||||
if (unlikely(access_error(regs, vma))) {
|
||||
bad_area(regs, mm, code, addr);
|
||||
mmap_read_unlock(mm);
|
||||
bad_area_nosemaphore(regs, mm, code, addr);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ config HEXAGON
|
|||
select GENERIC_SMP_IDLE_THREAD
|
||||
select STACKTRACE_SUPPORT
|
||||
select GENERIC_CLOCKEVENTS_BROADCAST
|
||||
select LOCK_MM_AND_FIND_VMA
|
||||
select MODULES_USE_ELF_RELA
|
||||
select GENERIC_CPU_DEVICES
|
||||
select ARCH_WANT_LD_ORPHAN_WARN
|
||||
|
|
|
@ -57,21 +57,10 @@ void do_page_fault(unsigned long address, long cause, struct pt_regs *regs)
|
|||
|
||||
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
|
||||
retry:
|
||||
mmap_read_lock(mm);
|
||||
vma = find_vma(mm, address);
|
||||
if (!vma)
|
||||
goto bad_area;
|
||||
vma = lock_mm_and_find_vma(mm, address, regs);
|
||||
if (unlikely(!vma))
|
||||
goto bad_area_nosemaphore;
|
||||
|
||||
if (vma->vm_start <= address)
|
||||
goto good_area;
|
||||
|
||||
if (!(vma->vm_flags & VM_GROWSDOWN))
|
||||
goto bad_area;
|
||||
|
||||
if (expand_stack(vma, address))
|
||||
goto bad_area;
|
||||
|
||||
good_area:
|
||||
/* Address space is OK. Now check access rights. */
|
||||
si_code = SEGV_ACCERR;
|
||||
|
||||
|
@ -140,6 +129,7 @@ void do_page_fault(unsigned long address, long cause, struct pt_regs *regs)
|
|||
bad_area:
|
||||
mmap_read_unlock(mm);
|
||||
|
||||
bad_area_nosemaphore:
|
||||
if (user_mode(regs)) {
|
||||
force_sig_fault(SIGSEGV, si_code, (void __user *)address);
|
||||
return;
|
||||
|
|
|
@ -107,6 +107,7 @@ config LOONGARCH
|
|||
select HAVE_VIRT_CPU_ACCOUNTING_GEN if !SMP
|
||||
select IRQ_FORCED_THREADING
|
||||
select IRQ_LOONGARCH_CPU
|
||||
select LOCK_MM_AND_FIND_VMA
|
||||
select MMU_GATHER_MERGE_VMAS if MMU
|
||||
select MODULES_USE_ELF_RELA if MODULES
|
||||
select NEED_PER_CPU_EMBED_FIRST_CHUNK
|
||||
|
|
|
@ -166,22 +166,18 @@ static void __kprobes __do_page_fault(struct pt_regs *regs,
|
|||
|
||||
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
|
||||
retry:
|
||||
mmap_read_lock(mm);
|
||||
vma = find_vma(mm, address);
|
||||
if (!vma)
|
||||
goto bad_area;
|
||||
if (vma->vm_start <= address)
|
||||
goto good_area;
|
||||
if (!(vma->vm_flags & VM_GROWSDOWN))
|
||||
goto bad_area;
|
||||
if (!expand_stack(vma, address))
|
||||
goto good_area;
|
||||
vma = lock_mm_and_find_vma(mm, address, regs);
|
||||
if (unlikely(!vma))
|
||||
goto bad_area_nosemaphore;
|
||||
goto good_area;
|
||||
|
||||
/*
|
||||
* 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:
|
||||
mmap_read_unlock(mm);
|
||||
bad_area_nosemaphore:
|
||||
do_sigsegv(regs, write, address, si_code);
|
||||
return;
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ config NIOS2
|
|||
select HAVE_ARCH_TRACEHOOK
|
||||
select HAVE_ARCH_KGDB
|
||||
select IRQ_DOMAIN
|
||||
select LOCK_MM_AND_FIND_VMA
|
||||
select MODULES_USE_ELF_RELA
|
||||
select OF
|
||||
select OF_EARLY_FLATTREE
|
||||
|
|
|
@ -86,27 +86,14 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long cause,
|
|||
|
||||
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
|
||||
|
||||
if (!mmap_read_trylock(mm)) {
|
||||
if (!user_mode(regs) && !search_exception_tables(regs->ea))
|
||||
goto bad_area_nosemaphore;
|
||||
retry:
|
||||
mmap_read_lock(mm);
|
||||
}
|
||||
|
||||
vma = find_vma(mm, address);
|
||||
vma = lock_mm_and_find_vma(mm, address, regs);
|
||||
if (!vma)
|
||||
goto bad_area;
|
||||
if (vma->vm_start <= address)
|
||||
goto good_area;
|
||||
if (!(vma->vm_flags & VM_GROWSDOWN))
|
||||
goto bad_area;
|
||||
if (expand_stack(vma, address))
|
||||
goto bad_area;
|
||||
goto bad_area_nosemaphore;
|
||||
/*
|
||||
* Ok, we have a good vm_area for this memory access, so
|
||||
* we can handle it..
|
||||
*/
|
||||
good_area:
|
||||
code = SEGV_ACCERR;
|
||||
|
||||
switch (cause) {
|
||||
|
|
|
@ -56,6 +56,7 @@ config SUPERH
|
|||
select HAVE_STACKPROTECTOR
|
||||
select HAVE_SYSCALL_TRACEPOINTS
|
||||
select IRQ_FORCED_THREADING
|
||||
select LOCK_MM_AND_FIND_VMA
|
||||
select MODULES_USE_ELF_RELA
|
||||
select NEED_SG_DMA_LENGTH
|
||||
select NO_DMA if !MMU && !DMA_COHERENT
|
||||
|
|
|
@ -439,21 +439,9 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
|
|||
}
|
||||
|
||||
retry:
|
||||
mmap_read_lock(mm);
|
||||
|
||||
vma = find_vma(mm, address);
|
||||
vma = lock_mm_and_find_vma(mm, address, regs);
|
||||
if (unlikely(!vma)) {
|
||||
bad_area(regs, error_code, address);
|
||||
return;
|
||||
}
|
||||
if (likely(vma->vm_start <= address))
|
||||
goto good_area;
|
||||
if (unlikely(!(vma->vm_flags & VM_GROWSDOWN))) {
|
||||
bad_area(regs, error_code, address);
|
||||
return;
|
||||
}
|
||||
if (unlikely(expand_stack(vma, address))) {
|
||||
bad_area(regs, error_code, address);
|
||||
bad_area_nosemaphore(regs, error_code, address);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -461,7 +449,6 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
|
|||
* Ok, we have a good vm_area for this memory access, so
|
||||
* we can handle it..
|
||||
*/
|
||||
good_area:
|
||||
if (unlikely(access_error(error_code, vma))) {
|
||||
bad_area_access_error(regs, error_code, address);
|
||||
return;
|
||||
|
|
|
@ -56,6 +56,7 @@ config SPARC32
|
|||
select DMA_DIRECT_REMAP
|
||||
select GENERIC_ATOMIC64
|
||||
select HAVE_UID16
|
||||
select LOCK_MM_AND_FIND_VMA
|
||||
select OLD_SIGACTION
|
||||
select ZONE_DMA
|
||||
|
||||
|
|
|
@ -143,28 +143,19 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
|
|||
if (pagefault_disabled() || !mm)
|
||||
goto no_context;
|
||||
|
||||
if (!from_user && address >= PAGE_OFFSET)
|
||||
goto no_context;
|
||||
|
||||
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
|
||||
|
||||
retry:
|
||||
mmap_read_lock(mm);
|
||||
|
||||
if (!from_user && address >= PAGE_OFFSET)
|
||||
goto bad_area;
|
||||
|
||||
vma = find_vma(mm, address);
|
||||
vma = lock_mm_and_find_vma(mm, address, regs);
|
||||
if (!vma)
|
||||
goto bad_area;
|
||||
if (vma->vm_start <= address)
|
||||
goto good_area;
|
||||
if (!(vma->vm_flags & VM_GROWSDOWN))
|
||||
goto bad_area;
|
||||
if (expand_stack(vma, address))
|
||||
goto bad_area;
|
||||
goto bad_area_nosemaphore;
|
||||
/*
|
||||
* Ok, we have a good vm_area for this memory access, so
|
||||
* we can handle it..
|
||||
*/
|
||||
good_area:
|
||||
code = SEGV_ACCERR;
|
||||
if (write) {
|
||||
if (!(vma->vm_flags & VM_WRITE))
|
||||
|
@ -318,17 +309,9 @@ static void force_user_fault(unsigned long address, int write)
|
|||
|
||||
code = SEGV_MAPERR;
|
||||
|
||||
mmap_read_lock(mm);
|
||||
vma = find_vma(mm, address);
|
||||
vma = lock_mm_and_find_vma(mm, address, regs);
|
||||
if (!vma)
|
||||
goto bad_area;
|
||||
if (vma->vm_start <= address)
|
||||
goto good_area;
|
||||
if (!(vma->vm_flags & VM_GROWSDOWN))
|
||||
goto bad_area;
|
||||
if (expand_stack(vma, address))
|
||||
goto bad_area;
|
||||
good_area:
|
||||
goto bad_area_nosemaphore;
|
||||
code = SEGV_ACCERR;
|
||||
if (write) {
|
||||
if (!(vma->vm_flags & VM_WRITE))
|
||||
|
@ -347,6 +330,7 @@ static void force_user_fault(unsigned long address, int write)
|
|||
return;
|
||||
bad_area:
|
||||
mmap_read_unlock(mm);
|
||||
bad_area_nosemaphore:
|
||||
__do_fault_siginfo(code, SIGSEGV, tsk->thread.kregs, address);
|
||||
return;
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ config XTENSA
|
|||
select HAVE_SYSCALL_TRACEPOINTS
|
||||
select HAVE_VIRT_CPU_ACCOUNTING_GEN
|
||||
select IRQ_DOMAIN
|
||||
select LOCK_MM_AND_FIND_VMA
|
||||
select MODULES_USE_ELF_RELA
|
||||
select PERF_USE_VMALLOC
|
||||
select TRACE_IRQFLAGS_SUPPORT
|
||||
|
|
|
@ -130,23 +130,14 @@ void do_page_fault(struct pt_regs *regs)
|
|||
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
|
||||
|
||||
retry:
|
||||
mmap_read_lock(mm);
|
||||
vma = find_vma(mm, address);
|
||||
|
||||
vma = lock_mm_and_find_vma(mm, address, regs);
|
||||
if (!vma)
|
||||
goto bad_area;
|
||||
if (vma->vm_start <= address)
|
||||
goto good_area;
|
||||
if (!(vma->vm_flags & VM_GROWSDOWN))
|
||||
goto bad_area;
|
||||
if (expand_stack(vma, address))
|
||||
goto bad_area;
|
||||
goto bad_area_nosemaphore;
|
||||
|
||||
/* Ok, we have a good vm_area for this memory access, so
|
||||
* we can handle it..
|
||||
*/
|
||||
|
||||
good_area:
|
||||
code = SEGV_ACCERR;
|
||||
|
||||
if (is_write) {
|
||||
|
@ -205,6 +196,7 @@ void do_page_fault(struct pt_regs *regs)
|
|||
*/
|
||||
bad_area:
|
||||
mmap_read_unlock(mm);
|
||||
bad_area_nosemaphore:
|
||||
if (user_mode(regs)) {
|
||||
current->thread.bad_vaddr = address;
|
||||
current->thread.error_code = is_write;
|
||||
|
|
Loading…
Reference in New Issue