#define _ASM_EXTABLE_UA(from, to) \
_ASM_EXTABLE_TYPE(from, to, EX_TYPE_UACCESS)
+#define _ASM_EXTABLE_UA_INTR(from, to) \
+ _ASM_EXTABLE_TYPE(from, to, EX_TYPE_UACCESS_INTERRUPTIBLE)
+
#define _ASM_EXTABLE_FAULT(from, to) \
_ASM_EXTABLE_TYPE(from, to, EX_TYPE_FAULT)
#define EX_TYPE_DEFAULT 1
#define EX_TYPE_FAULT 2
#define EX_TYPE_UACCESS 3
-/* unused, was: #define EX_TYPE_COPY 4 */
+#define EX_TYPE_UACCESS_INTERRUPTIBLE 4
#define EX_TYPE_CLEAR_FS 5
#define EX_TYPE_FPU_RESTORE 6
#define EX_TYPE_BPF 7
#define X86_TRAP_VC 29 /* VMM Communication Exception */
#define X86_TRAP_IRET 32 /* IRET Exception */
+#define X86_TRAP_INTERRUPTIBLE 0x40000000 /* Internal, for interruptible exceptions */
#endif
asm volatile("1: xchgb %0, %2\n"
"xor %1, %1\n"
"2:\n"
- _ASM_EXTABLE_UA(1b, 2b)
+ _ASM_EXTABLE_UA_INTR(1b, 2b)
: "+q" (st_preempted),
"+&r" (err),
"+m" (st->preempted));
- if (err)
+ if (err) {
+ if (signal_pending(current))
+ err = -EINTR;
goto out;
+ }
user_access_end();
reg = FIELD_GET(EX_DATA_REG_MASK, e->data);
imm = FIELD_GET(EX_DATA_IMM_MASK, e->data);
+ if (trapnr & X86_TRAP_INTERRUPTIBLE) {
+ trapnr &= ~X86_TRAP_INTERRUPTIBLE;
+ if (type != EX_TYPE_UACCESS_INTERRUPTIBLE)
+ return 0;
+ }
+
switch (type) {
case EX_TYPE_DEFAULT:
case EX_TYPE_DEFAULT_MCE_SAFE:
case EX_TYPE_FAULT_MCE_SAFE:
return ex_handler_fault(e, regs, trapnr);
case EX_TYPE_UACCESS:
+ case EX_TYPE_UACCESS_INTERRUPTIBLE:
return ex_handler_uaccess(e, regs, trapnr, fault_addr);
case EX_TYPE_CLEAR_FS:
return ex_handler_clear_fs(e, regs);
*/
fault = handle_mm_fault(vma, address, flags, regs);
- if (fault_signal_pending(fault, regs)) {
- /*
- * Quick path to respond to signals. The core mm code
- * has unlocked the mm for us if we get here.
- */
- if (!user_mode(regs))
- kernelmode_fixup_or_oops(regs, error_code, address,
- SIGBUS, BUS_ADRERR,
- ARCH_DEFAULT_PKEY);
- return;
- }
-
/* The fault is fully completed (including releasing mmap lock) */
if (fault & VM_FAULT_COMPLETED)
return;
* that we made any progress. Handle this case first.
*/
if (unlikely(fault & VM_FAULT_RETRY)) {
+ if (signal_pending(current)) {
+ if (user_mode(regs))
+ return;
+
+ if (fatal_signal_pending(current)) {
+ kernelmode_fixup_or_oops(regs, error_code, address,
+ SIGBUS, BUS_ADRERR,
+ ARCH_DEFAULT_PKEY);
+ return;
+ }
+
+ /*
+ * First time round, if woken by a signal, see if there
+ * is an interruptible exception handler. If so, do it.
+ * Else, switch off FAULT_FLAG_INTERRUPTIBLE.
+ */
+ if (fixup_exception(regs, X86_TRAP_INTERRUPTIBLE | X86_TRAP_PF,
+ error_code, address))
+ return;
+
+ flags &= ~FAULT_FLAG_INTERRUPTIBLE;
+ }
+
flags |= FAULT_FLAG_TRIED;
goto retry;
}