aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorJohannes Weiner <hannes@cmpxchg.org>2013-09-12 18:13:40 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-09-12 18:38:01 -0400
commit3a13c4d761b4b979ba8767f42345fed3274991b0 (patch)
tree9f6f0b09875b6b510720bea2c2a0ac1fd6878f67 /arch
parent759496ba6407c6994d6a5ce3a5e74937d7816208 (diff)
x86: finish user fault error path with fatal signal
The x86 fault handler bails in the middle of error handling when the task has a fatal signal pending. For a subsequent patch this is a problem in OOM situations because it relies on pagefault_out_of_memory() being called even when the task has been killed, to perform proper per-task OOM state unwinding. Shortcutting the fault like this is a rather minor optimization that saves a few instructions in rare cases. Just remove it for user-triggered faults. Use the opportunity to split the fault retry handling from actual fault errors and add locking documentation that reads suprisingly similar to ARM's. Signed-off-by: Johannes Weiner <hannes@cmpxchg.org> Reviewed-by: Michal Hocko <mhocko@suse.cz> Acked-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Cc: David Rientjes <rientjes@google.com> Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: azurIt <azurit@pobox.sk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/mm/fault.c35
1 files changed, 17 insertions, 18 deletions
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 6d77c3866faa..3aaeffcfd67a 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -842,23 +842,15 @@ do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address,
842 force_sig_info_fault(SIGBUS, code, address, tsk, fault); 842 force_sig_info_fault(SIGBUS, code, address, tsk, fault);
843} 843}
844 844
845static noinline int 845static noinline void
846mm_fault_error(struct pt_regs *regs, unsigned long error_code, 846mm_fault_error(struct pt_regs *regs, unsigned long error_code,
847 unsigned long address, unsigned int fault) 847 unsigned long address, unsigned int fault)
848{ 848{
849 /* 849 if (fatal_signal_pending(current) && !(error_code & PF_USER)) {
850 * Pagefault was interrupted by SIGKILL. We have no reason to 850 up_read(&current->mm->mmap_sem);
851 * continue pagefault. 851 no_context(regs, error_code, address, 0, 0);
852 */ 852 return;
853 if (fatal_signal_pending(current)) {
854 if (!(fault & VM_FAULT_RETRY))
855 up_read(&current->mm->mmap_sem);
856 if (!(error_code & PF_USER))
857 no_context(regs, error_code, address, 0, 0);
858 return 1;
859 } 853 }
860 if (!(fault & VM_FAULT_ERROR))
861 return 0;
862 854
863 if (fault & VM_FAULT_OOM) { 855 if (fault & VM_FAULT_OOM) {
864 /* Kernel mode? Handle exceptions or die: */ 856 /* Kernel mode? Handle exceptions or die: */
@@ -866,7 +858,7 @@ mm_fault_error(struct pt_regs *regs, unsigned long error_code,
866 up_read(&current->mm->mmap_sem); 858 up_read(&current->mm->mmap_sem);
867 no_context(regs, error_code, address, 859 no_context(regs, error_code, address,
868 SIGSEGV, SEGV_MAPERR); 860 SIGSEGV, SEGV_MAPERR);
869 return 1; 861 return;
870 } 862 }
871 863
872 up_read(&current->mm->mmap_sem); 864 up_read(&current->mm->mmap_sem);
@@ -884,7 +876,6 @@ mm_fault_error(struct pt_regs *regs, unsigned long error_code,
884 else 876 else
885 BUG(); 877 BUG();
886 } 878 }
887 return 1;
888} 879}
889 880
890static int spurious_fault_check(unsigned long error_code, pte_t *pte) 881static int spurious_fault_check(unsigned long error_code, pte_t *pte)
@@ -1189,9 +1180,17 @@ good_area:
1189 */ 1180 */
1190 fault = handle_mm_fault(mm, vma, address, flags); 1181 fault = handle_mm_fault(mm, vma, address, flags);
1191 1182
1192 if (unlikely(fault & (VM_FAULT_RETRY|VM_FAULT_ERROR))) { 1183 /*
1193 if (mm_fault_error(regs, error_code, address, fault)) 1184 * If we need to retry but a fatal signal is pending, handle the
1194 return; 1185 * signal first. We do not need to release the mmap_sem because it
1186 * would already be released in __lock_page_or_retry in mm/filemap.c.
1187 */
1188 if (unlikely((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)))
1189 return;
1190
1191 if (unlikely(fault & VM_FAULT_ERROR)) {
1192 mm_fault_error(regs, error_code, address, fault);
1193 return;
1195 } 1194 }
1196 1195
1197 /* 1196 /*