aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/mm/fault.c12
-rw-r--r--include/linux/mm.h1
-rw-r--r--mm/filemap.c31
3 files changed, 36 insertions, 8 deletions
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index bcb394dfbb35..f7a2a054a3c0 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -965,7 +965,7 @@ do_page_fault(struct pt_regs *regs, unsigned long error_code)
965 struct mm_struct *mm; 965 struct mm_struct *mm;
966 int fault; 966 int fault;
967 int write = error_code & PF_WRITE; 967 int write = error_code & PF_WRITE;
968 unsigned int flags = FAULT_FLAG_ALLOW_RETRY | 968 unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
969 (write ? FAULT_FLAG_WRITE : 0); 969 (write ? FAULT_FLAG_WRITE : 0);
970 970
971 tsk = current; 971 tsk = current;
@@ -1139,6 +1139,16 @@ good_area:
1139 } 1139 }
1140 1140
1141 /* 1141 /*
1142 * Pagefault was interrupted by SIGKILL. We have no reason to
1143 * continue pagefault.
1144 */
1145 if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) {
1146 if (!(error_code & PF_USER))
1147 no_context(regs, error_code, address);
1148 return;
1149 }
1150
1151 /*
1142 * Major/minor page fault accounting is only done on the 1152 * Major/minor page fault accounting is only done on the
1143 * initial attempt. If we go through a retry, it is extremely 1153 * initial attempt. If we go through a retry, it is extremely
1144 * likely that the page will be found in page cache at that point. 1154 * likely that the page will be found in page cache at that point.
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 1746f67c33de..57d3d5fade16 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -153,6 +153,7 @@ extern pgprot_t protection_map[16];
153#define FAULT_FLAG_MKWRITE 0x04 /* Fault was mkwrite of existing pte */ 153#define FAULT_FLAG_MKWRITE 0x04 /* Fault was mkwrite of existing pte */
154#define FAULT_FLAG_ALLOW_RETRY 0x08 /* Retry fault if blocking */ 154#define FAULT_FLAG_ALLOW_RETRY 0x08 /* Retry fault if blocking */
155#define FAULT_FLAG_RETRY_NOWAIT 0x10 /* Don't drop mmap_sem and wait when retrying */ 155#define FAULT_FLAG_RETRY_NOWAIT 0x10 /* Don't drop mmap_sem and wait when retrying */
156#define FAULT_FLAG_KILLABLE 0x20 /* The fault task is in SIGKILL killable region */
156 157
157/* 158/*
158 * This interface is used by x86 PAT code to identify a pfn mapping that is 159 * This interface is used by x86 PAT code to identify a pfn mapping that is
diff --git a/mm/filemap.c b/mm/filemap.c
index dea8a38bb2bb..8144f87dcbb4 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -654,15 +654,32 @@ EXPORT_SYMBOL_GPL(__lock_page_killable);
654int __lock_page_or_retry(struct page *page, struct mm_struct *mm, 654int __lock_page_or_retry(struct page *page, struct mm_struct *mm,
655 unsigned int flags) 655 unsigned int flags)
656{ 656{
657 if (!(flags & FAULT_FLAG_ALLOW_RETRY)) { 657 if (flags & FAULT_FLAG_ALLOW_RETRY) {
658 __lock_page(page); 658 /*
659 return 1; 659 * CAUTION! In this case, mmap_sem is not released
660 } else { 660 * even though return 0.
661 if (!(flags & FAULT_FLAG_RETRY_NOWAIT)) { 661 */
662 up_read(&mm->mmap_sem); 662 if (flags & FAULT_FLAG_RETRY_NOWAIT)
663 return 0;
664
665 up_read(&mm->mmap_sem);
666 if (flags & FAULT_FLAG_KILLABLE)
667 wait_on_page_locked_killable(page);
668 else
663 wait_on_page_locked(page); 669 wait_on_page_locked(page);
664 }
665 return 0; 670 return 0;
671 } else {
672 if (flags & FAULT_FLAG_KILLABLE) {
673 int ret;
674
675 ret = __lock_page_killable(page);
676 if (ret) {
677 up_read(&mm->mmap_sem);
678 return 0;
679 }
680 } else
681 __lock_page(page);
682 return 1;
666 } 683 }
667} 684}
668 685