diff options
-rw-r--r-- | arch/x86/mm/fault.c | 12 | ||||
-rw-r--r-- | include/linux/mm.h | 1 | ||||
-rw-r--r-- | mm/filemap.c | 31 |
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); | |||
654 | int __lock_page_or_retry(struct page *page, struct mm_struct *mm, | 654 | int __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 | ||