diff options
| -rw-r--r-- | arch/x86/mm/fault.c | 23 |
1 files changed, 17 insertions, 6 deletions
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index ad8b9733d6b3..d8ed4006b3d2 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c | |||
| @@ -428,6 +428,16 @@ static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs, | |||
| 428 | } | 428 | } |
| 429 | #endif | 429 | #endif |
| 430 | 430 | ||
| 431 | static int spurious_fault_check(unsigned long error_code, pte_t *pte) | ||
| 432 | { | ||
| 433 | if ((error_code & PF_WRITE) && !pte_write(*pte)) | ||
| 434 | return 0; | ||
| 435 | if ((error_code & PF_INSTR) && !pte_exec(*pte)) | ||
| 436 | return 0; | ||
| 437 | |||
| 438 | return 1; | ||
| 439 | } | ||
| 440 | |||
| 431 | /* | 441 | /* |
| 432 | * Handle a spurious fault caused by a stale TLB entry. This allows | 442 | * Handle a spurious fault caused by a stale TLB entry. This allows |
| 433 | * us to lazily refresh the TLB when increasing the permissions of a | 443 | * us to lazily refresh the TLB when increasing the permissions of a |
| @@ -457,20 +467,21 @@ static int spurious_fault(unsigned long address, | |||
| 457 | if (!pud_present(*pud)) | 467 | if (!pud_present(*pud)) |
| 458 | return 0; | 468 | return 0; |
| 459 | 469 | ||
| 470 | if (pud_large(*pud)) | ||
| 471 | return spurious_fault_check(error_code, (pte_t *) pud); | ||
| 472 | |||
| 460 | pmd = pmd_offset(pud, address); | 473 | pmd = pmd_offset(pud, address); |
| 461 | if (!pmd_present(*pmd)) | 474 | if (!pmd_present(*pmd)) |
| 462 | return 0; | 475 | return 0; |
| 463 | 476 | ||
| 477 | if (pmd_large(*pmd)) | ||
| 478 | return spurious_fault_check(error_code, (pte_t *) pmd); | ||
| 479 | |||
| 464 | pte = pte_offset_kernel(pmd, address); | 480 | pte = pte_offset_kernel(pmd, address); |
| 465 | if (!pte_present(*pte)) | 481 | if (!pte_present(*pte)) |
| 466 | return 0; | 482 | return 0; |
| 467 | 483 | ||
| 468 | if ((error_code & PF_WRITE) && !pte_write(*pte)) | 484 | return spurious_fault_check(error_code, pte); |
| 469 | return 0; | ||
| 470 | if ((error_code & PF_INSTR) && !pte_exec(*pte)) | ||
| 471 | return 0; | ||
| 472 | |||
| 473 | return 1; | ||
| 474 | } | 485 | } |
| 475 | 486 | ||
| 476 | /* | 487 | /* |
