Use an explicit memory range throughthe fault handler and any called functions. Signed-off-by: Michel Lespinasse <walken@xxxxxxxxxx> --- arch/x86/mm/fault.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git arch/x86/mm/fault.c arch/x86/mm/fault.c index adbd2b03fcf9..700da3cc3db9 100644 --- arch/x86/mm/fault.c +++ arch/x86/mm/fault.c @@ -938,7 +938,8 @@ static inline bool bad_area_access_from_pkeys(unsigned long error_code, static noinline void bad_area(struct pt_regs *regs, unsigned long error_code, - unsigned long address, struct vm_area_struct *vma) + unsigned long address, struct vm_area_struct *vma, + struct mm_lock_range *range) { u32 pkey = 0; int si_code = SEGV_MAPERR; @@ -983,7 +984,7 @@ bad_area(struct pt_regs *regs, unsigned long error_code, * Something tried to access memory that isn't in our memory map.. * Fix it, but check if it's kernel or user first.. */ - mm_read_unlock(current->mm); + mm_read_range_unlock(current->mm, range); __bad_area_nosemaphore(regs, error_code, address, pkey, si_code); } @@ -1277,6 +1278,7 @@ void do_user_addr_fault(struct pt_regs *regs, unsigned long hw_error_code, unsigned long address) { + struct mm_lock_range *range; struct vm_area_struct *vma; struct task_struct *tsk; struct mm_struct *mm; @@ -1361,6 +1363,8 @@ void do_user_addr_fault(struct pt_regs *regs, } #endif + range = mm_coarse_lock_range(); + /* * Kernel-mode access to the user address space should only occur * on well-defined single instructions listed in the exception @@ -1373,7 +1377,7 @@ void do_user_addr_fault(struct pt_regs *regs, * 1. Failed to acquire mmap_sem, and * 2. The access did not originate in userspace. */ - if (unlikely(!mm_read_trylock(mm))) { + if (unlikely(!mm_read_range_trylock(mm, range))) { if (!user_mode(regs) && !search_exception_tables(regs->ip)) { /* * Fault from code in kernel from @@ -1383,7 +1387,7 @@ void do_user_addr_fault(struct pt_regs *regs, return; } retry: - mm_read_lock(mm); + mm_read_range_lock(mm, range); } else { /* * The above down_read_trylock() might have succeeded in @@ -1395,17 +1399,17 @@ void do_user_addr_fault(struct pt_regs *regs, vma = find_vma(mm, address); if (unlikely(!vma)) { - bad_area(regs, hw_error_code, address, NULL); + bad_area(regs, hw_error_code, address, NULL, range); return; } if (likely(vma->vm_start <= address)) goto good_area; if (unlikely(!(vma->vm_flags & VM_GROWSDOWN))) { - bad_area(regs, hw_error_code, address, NULL); + bad_area(regs, hw_error_code, address, NULL, range); return; } if (unlikely(expand_stack(vma, address))) { - bad_area(regs, hw_error_code, address, NULL); + bad_area(regs, hw_error_code, address, NULL, range); return; } @@ -1415,7 +1419,7 @@ void do_user_addr_fault(struct pt_regs *regs, */ good_area: if (unlikely(access_error(hw_error_code, vma))) { - bad_area(regs, hw_error_code, address, vma); + bad_area(regs, hw_error_code, address, vma, range); return; } @@ -1432,7 +1436,7 @@ void do_user_addr_fault(struct pt_regs *regs, * userland). The return to userland is identified whenever * FAULT_FLAG_USER|FAULT_FLAG_KILLABLE are both set in flags. */ - fault = handle_mm_fault(vma, address, flags); + fault = handle_mm_fault_range(vma, address, flags, range); major |= fault & VM_FAULT_MAJOR; /* @@ -1458,7 +1462,7 @@ void do_user_addr_fault(struct pt_regs *regs, return; } - mm_read_unlock(mm); + mm_read_range_unlock(mm, range); if (unlikely(fault & VM_FAULT_ERROR)) { mm_fault_error(regs, hw_error_code, address, fault); return; -- 2.25.0.341.g760bfbb309-goog