@@ -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;
Use an explicit memory range throughthe fault handler and any called functions. Signed-off-by: Michel Lespinasse <walken@google.com> --- arch/x86/mm/fault.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-)