diff options
Diffstat (limited to 'mm/pagewalk.c')
-rw-r--r-- | mm/pagewalk.c | 22 |
1 files changed, 19 insertions, 3 deletions
diff --git a/mm/pagewalk.c b/mm/pagewalk.c index a286915e23ef..7b47a57b6646 100644 --- a/mm/pagewalk.c +++ b/mm/pagewalk.c | |||
@@ -120,15 +120,31 @@ int walk_page_range(unsigned long addr, unsigned long end, | |||
120 | do { | 120 | do { |
121 | next = pgd_addr_end(addr, end); | 121 | next = pgd_addr_end(addr, end); |
122 | 122 | ||
123 | /* skip hugetlb vma to avoid hugepage PMD being cleared | 123 | /* |
124 | * in pmd_none_or_clear_bad(). */ | 124 | * handle hugetlb vma individually because pagetable walk for |
125 | * the hugetlb page is dependent on the architecture and | ||
126 | * we can't handled it in the same manner as non-huge pages. | ||
127 | */ | ||
125 | vma = find_vma(walk->mm, addr); | 128 | vma = find_vma(walk->mm, addr); |
129 | #ifdef CONFIG_HUGETLB_PAGE | ||
126 | if (vma && is_vm_hugetlb_page(vma)) { | 130 | if (vma && is_vm_hugetlb_page(vma)) { |
131 | pte_t *pte; | ||
132 | struct hstate *hs; | ||
133 | |||
127 | if (vma->vm_end < next) | 134 | if (vma->vm_end < next) |
128 | next = vma->vm_end; | 135 | next = vma->vm_end; |
136 | hs = hstate_vma(vma); | ||
137 | pte = huge_pte_offset(walk->mm, | ||
138 | addr & huge_page_mask(hs)); | ||
139 | if (pte && !huge_pte_none(huge_ptep_get(pte)) | ||
140 | && walk->hugetlb_entry) | ||
141 | err = walk->hugetlb_entry(pte, addr, | ||
142 | next, walk); | ||
143 | if (err) | ||
144 | break; | ||
129 | continue; | 145 | continue; |
130 | } | 146 | } |
131 | 147 | #endif | |
132 | if (pgd_none_or_clear_bad(pgd)) { | 148 | if (pgd_none_or_clear_bad(pgd)) { |
133 | if (walk->pte_hole) | 149 | if (walk->pte_hole) |
134 | err = walk->pte_hole(addr, next, walk); | 150 | err = walk->pte_hole(addr, next, walk); |