Skip to content

Commit

Permalink
mm: introduce fault_signal_pending()
Browse files Browse the repository at this point in the history
For most architectures, we've got a quick path to detect fatal signal
after a handle_mm_fault().  Introduce a helper for that quick path.

It cleans the current codes a bit so we don't need to duplicate the same
check across archs.  More importantly, this will be an unified place that
we handle the signal immediately right after an interrupted page fault, so
it'll be much easier for us if we want to change the behavior of handling
signals later on for all the archs.

Note that currently only part of the archs are using this new helper,
because some archs have their own way to handle signals.  In the follow up
patches, we'll try to apply this helper to all the rest of archs.

Another note is that the "regs" parameter in the new helper is not used
yet.  It'll be used very soon.  Now we kept it in this patch only to avoid
touching all the archs again in the follow up patches.

[[email protected]: fix sparse warnings]
  Link: http://lkml.kernel.org/r/20200311145921.GD479302@xz-x1
Signed-off-by: Peter Xu <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Tested-by: Brian Geffon <[email protected]>
Cc: Andrea Arcangeli <[email protected]>
Cc: Bobby Powers <[email protected]>
Cc: David Hildenbrand <[email protected]>
Cc: Denis Plotnikov <[email protected]>
Cc: "Dr . David Alan Gilbert" <[email protected]>
Cc: Hugh Dickins <[email protected]>
Cc: Jerome Glisse <[email protected]>
Cc: Johannes Weiner <[email protected]>
Cc: "Kirill A . Shutemov" <[email protected]>
Cc: Martin Cracauer <[email protected]>
Cc: Marty McFadden <[email protected]>
Cc: Matthew Wilcox <[email protected]>
Cc: Maya Gokhale <[email protected]>
Cc: Mel Gorman <[email protected]>
Cc: Mike Kravetz <[email protected]>
Cc: Mike Rapoport <[email protected]>
Cc: Pavel Emelyanov <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
xzpeter authored and torvalds committed Apr 2, 2020
1 parent ad415db commit 4ef8732
Show file tree
Hide file tree
Showing 18 changed files with 32 additions and 18 deletions.
2 changes: 1 addition & 1 deletion arch/alpha/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
the fault. */
fault = handle_mm_fault(vma, address, flags);

if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
if (fault_signal_pending(fault, regs))
return;

if (unlikely(fault & VM_FAULT_ERROR)) {
Expand Down
2 changes: 1 addition & 1 deletion arch/arm/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
* signal first. We do not need to release the mmap_sem because
* it would already be released in __lock_page_or_retry in
* mm/filemap.c. */
if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) {
if (fault_signal_pending(fault, regs)) {
if (!user_mode(regs))
goto no_context;
return 0;
Expand Down
2 changes: 1 addition & 1 deletion arch/hexagon/mm/vm_fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ void do_page_fault(unsigned long address, long cause, struct pt_regs *regs)

fault = handle_mm_fault(vma, address, flags);

if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
if (fault_signal_pending(fault, regs))
return;

/* The most common case -- we are done. */
Expand Down
2 changes: 1 addition & 1 deletion arch/ia64/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
*/
fault = handle_mm_fault(vma, address, flags);

if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
if (fault_signal_pending(fault, regs))
return;

if (unlikely(fault & VM_FAULT_ERROR)) {
Expand Down
2 changes: 1 addition & 1 deletion arch/m68k/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ int do_page_fault(struct pt_regs *regs, unsigned long address,
fault = handle_mm_fault(vma, address, flags);
pr_debug("handle_mm_fault returns %x\n", fault);

if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
if (fault_signal_pending(fault, regs))
return 0;

if (unlikely(fault & VM_FAULT_ERROR)) {
Expand Down
2 changes: 1 addition & 1 deletion arch/microblaze/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long address,
*/
fault = handle_mm_fault(vma, address, flags);

if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
if (fault_signal_pending(fault, regs))
return;

if (unlikely(fault & VM_FAULT_ERROR)) {
Expand Down
2 changes: 1 addition & 1 deletion arch/mips/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ static void __kprobes __do_page_fault(struct pt_regs *regs, unsigned long write,
*/
fault = handle_mm_fault(vma, address, flags);

if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
if (fault_signal_pending(fault, regs))
return;

perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
Expand Down
2 changes: 1 addition & 1 deletion arch/nds32/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ void do_page_fault(unsigned long entry, unsigned long addr,
* signal first. We do not need to release the mmap_sem because it
* would already be released in __lock_page_or_retry in mm/filemap.c.
*/
if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) {
if (fault_signal_pending(fault, regs)) {
if (!user_mode(regs))
goto no_context;
return;
Expand Down
2 changes: 1 addition & 1 deletion arch/nios2/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long cause,
*/
fault = handle_mm_fault(vma, address, flags);

if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
if (fault_signal_pending(fault, regs))
return;

if (unlikely(fault & VM_FAULT_ERROR)) {
Expand Down
2 changes: 1 addition & 1 deletion arch/openrisc/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long address,

fault = handle_mm_fault(vma, address, flags);

if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
if (fault_signal_pending(fault, regs))
return;

if (unlikely(fault & VM_FAULT_ERROR)) {
Expand Down
2 changes: 1 addition & 1 deletion arch/parisc/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long code,

fault = handle_mm_fault(vma, address, flags);

if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
if (fault_signal_pending(fault, regs))
return;

if (unlikely(fault & VM_FAULT_ERROR)) {
Expand Down
2 changes: 1 addition & 1 deletion arch/riscv/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs)
* signal first. We do not need to release the mmap_sem because it
* would already be released in __lock_page_or_retry in mm/filemap.c.
*/
if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(tsk))
if (fault_signal_pending(fault, regs))
return;

if (unlikely(fault & VM_FAULT_ERROR)) {
Expand Down
3 changes: 1 addition & 2 deletions arch/s390/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -480,8 +480,7 @@ static inline vm_fault_t do_exception(struct pt_regs *regs, int access)
* the fault.
*/
fault = handle_mm_fault(vma, address, flags);
/* No reason to continue if interrupted by SIGKILL. */
if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) {
if (fault_signal_pending(fault, regs)) {
fault = VM_FAULT_SIGNAL;
if (flags & FAULT_FLAG_RETRY_NOWAIT)
goto out_up;
Expand Down
2 changes: 1 addition & 1 deletion arch/sparc/mm/fault_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
*/
fault = handle_mm_fault(vma, address, flags);

if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
if (fault_signal_pending(fault, regs))
return;

if (unlikely(fault & VM_FAULT_ERROR)) {
Expand Down
2 changes: 1 addition & 1 deletion arch/sparc/mm/fault_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)

fault = handle_mm_fault(vma, address, flags);

if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
if (fault_signal_pending(fault, regs))
goto exit_exception;

if (unlikely(fault & VM_FAULT_ERROR)) {
Expand Down
2 changes: 1 addition & 1 deletion arch/unicore32/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ static int do_pf(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
* signal first. We do not need to release the mmap_sem because
* it would already be released in __lock_page_or_retry in
* mm/filemap.c. */
if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
if (fault_signal_pending(fault, regs))
return 0;

if (!(fault & VM_FAULT_ERROR) && (flags & FAULT_FLAG_ALLOW_RETRY)) {
Expand Down
2 changes: 1 addition & 1 deletion arch/xtensa/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ void do_page_fault(struct pt_regs *regs)
*/
fault = handle_mm_fault(vma, address, flags);

if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
if (fault_signal_pending(fault, regs))
return;

if (unlikely(fault & VM_FAULT_ERROR)) {
Expand Down
15 changes: 15 additions & 0 deletions include/linux/sched/signal.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#include <linux/cred.h>
#include <linux/refcount.h>
#include <linux/posix-timers.h>
#include <linux/mm_types.h>
#include <asm/ptrace.h>

/*
* Types defining task->signal and task->sighand and APIs using them:
Expand Down Expand Up @@ -369,6 +371,19 @@ static inline int signal_pending_state(long state, struct task_struct *p)
return (state & TASK_INTERRUPTIBLE) || __fatal_signal_pending(p);
}

/*
* This should only be used in fault handlers to decide whether we
* should stop the current fault routine to handle the signals
* instead, especially with the case where we've got interrupted with
* a VM_FAULT_RETRY.
*/
static inline bool fault_signal_pending(vm_fault_t fault_flags,
struct pt_regs *regs)
{
return unlikely((fault_flags & VM_FAULT_RETRY) &&
fatal_signal_pending(current));
}

/*
* Reevaluate whether the task has signals pending delivery.
* Wake the task if so.
Expand Down

0 comments on commit 4ef8732

Please sign in to comment.