[RFC,12/24] x86 fault handler: use an explicit MM lock range
diff mbox series

Message ID 20200224203057.162467-13-walken@google.com
State New
Headers show
Series
  • Fine grained MM locking
Related show

Commit Message

Michel Lespinasse Feb. 24, 2020, 8:30 p.m. UTC
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(-)

Patch
diff mbox series

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;