diff options
Diffstat (limited to 'mm/rmap.c')
-rw-r--r-- | mm/rmap.c | 12 |
1 files changed, 8 insertions, 4 deletions
@@ -569,6 +569,7 @@ pmd_t *mm_find_pmd(struct mm_struct *mm, unsigned long address) | |||
569 | pgd_t *pgd; | 569 | pgd_t *pgd; |
570 | pud_t *pud; | 570 | pud_t *pud; |
571 | pmd_t *pmd = NULL; | 571 | pmd_t *pmd = NULL; |
572 | pmd_t pmde; | ||
572 | 573 | ||
573 | pgd = pgd_offset(mm, address); | 574 | pgd = pgd_offset(mm, address); |
574 | if (!pgd_present(*pgd)) | 575 | if (!pgd_present(*pgd)) |
@@ -579,7 +580,13 @@ pmd_t *mm_find_pmd(struct mm_struct *mm, unsigned long address) | |||
579 | goto out; | 580 | goto out; |
580 | 581 | ||
581 | pmd = pmd_offset(pud, address); | 582 | pmd = pmd_offset(pud, address); |
582 | if (!pmd_present(*pmd)) | 583 | /* |
584 | * Some THP functions use the sequence pmdp_clear_flush(), set_pmd_at() | ||
585 | * without holding anon_vma lock for write. So when looking for a | ||
586 | * genuine pmde (in which to find pte), test present and !THP together. | ||
587 | */ | ||
588 | pmde = ACCESS_ONCE(*pmd); | ||
589 | if (!pmd_present(pmde) || pmd_trans_huge(pmde)) | ||
583 | pmd = NULL; | 590 | pmd = NULL; |
584 | out: | 591 | out: |
585 | return pmd; | 592 | return pmd; |
@@ -615,9 +622,6 @@ pte_t *__page_check_address(struct page *page, struct mm_struct *mm, | |||
615 | if (!pmd) | 622 | if (!pmd) |
616 | return NULL; | 623 | return NULL; |
617 | 624 | ||
618 | if (pmd_trans_huge(*pmd)) | ||
619 | return NULL; | ||
620 | |||
621 | pte = pte_offset_map(pmd, address); | 625 | pte = pte_offset_map(pmd, address); |
622 | /* Make a quick check before getting the lock */ | 626 | /* Make a quick check before getting the lock */ |
623 | if (!sync && !pte_present(*pte)) { | 627 | if (!sync && !pte_present(*pte)) { |