|
@@ -203,9 +203,14 @@ static pgd_t *get_current_pgd(void)
|
|
|
* interrupt or a critical region, and must do as little as possible.
|
|
|
* Similarly, we can't use atomic ops here, since we may be handling a
|
|
|
* fault caused by an atomic op access.
|
|
|
+ *
|
|
|
+ * If we find a migrating PTE while we're in an NMI context, and we're
|
|
|
+ * at a PC that has a registered exception handler, we don't wait,
|
|
|
+ * since this thread may (e.g.) have been interrupted while migrating
|
|
|
+ * its own stack, which would then cause us to self-deadlock.
|
|
|
*/
|
|
|
static int handle_migrating_pte(pgd_t *pgd, int fault_num,
|
|
|
- unsigned long address,
|
|
|
+ unsigned long address, unsigned long pc,
|
|
|
int is_kernel_mode, int write)
|
|
|
{
|
|
|
pud_t *pud;
|
|
@@ -227,6 +232,8 @@ static int handle_migrating_pte(pgd_t *pgd, int fault_num,
|
|
|
pte_offset_kernel(pmd, address);
|
|
|
pteval = *pte;
|
|
|
if (pte_migrating(pteval)) {
|
|
|
+ if (in_nmi() && search_exception_tables(pc))
|
|
|
+ return 0;
|
|
|
wait_for_migration(pte);
|
|
|
return 1;
|
|
|
}
|
|
@@ -300,7 +307,7 @@ static int handle_page_fault(struct pt_regs *regs,
|
|
|
* rather than trying to patch up the existing PTE.
|
|
|
*/
|
|
|
pgd = get_current_pgd();
|
|
|
- if (handle_migrating_pte(pgd, fault_num, address,
|
|
|
+ if (handle_migrating_pte(pgd, fault_num, address, regs->pc,
|
|
|
is_kernel_mode, write))
|
|
|
return 1;
|
|
|
|
|
@@ -665,7 +672,7 @@ struct intvec_state do_page_fault_ics(struct pt_regs *regs, int fault_num,
|
|
|
*/
|
|
|
if (fault_num == INT_DTLB_ACCESS)
|
|
|
write = 1;
|
|
|
- if (handle_migrating_pte(pgd, fault_num, address, 1, write))
|
|
|
+ if (handle_migrating_pte(pgd, fault_num, address, pc, 1, write))
|
|
|
return state;
|
|
|
|
|
|
/* Return zero so that we continue on with normal fault handling. */
|