aboutsummaryrefslogtreecommitdiffstats
path: root/mm/pagewalk.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/pagewalk.c')
-rw-r--r--mm/pagewalk.c16
1 files changed, 15 insertions, 1 deletions
diff --git a/mm/pagewalk.c b/mm/pagewalk.c
index d5878bed7841..a286915e23ef 100644
--- a/mm/pagewalk.c
+++ b/mm/pagewalk.c
@@ -1,6 +1,7 @@
1#include <linux/mm.h> 1#include <linux/mm.h>
2#include <linux/highmem.h> 2#include <linux/highmem.h>
3#include <linux/sched.h> 3#include <linux/sched.h>
4#include <linux/hugetlb.h>
4 5
5static int walk_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, 6static int walk_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
6 struct mm_walk *walk) 7 struct mm_walk *walk)
@@ -107,6 +108,7 @@ int walk_page_range(unsigned long addr, unsigned long end,
107 pgd_t *pgd; 108 pgd_t *pgd;
108 unsigned long next; 109 unsigned long next;
109 int err = 0; 110 int err = 0;
111 struct vm_area_struct *vma;
110 112
111 if (addr >= end) 113 if (addr >= end)
112 return err; 114 return err;
@@ -117,11 +119,22 @@ int walk_page_range(unsigned long addr, unsigned long end,
117 pgd = pgd_offset(walk->mm, addr); 119 pgd = pgd_offset(walk->mm, addr);
118 do { 120 do {
119 next = pgd_addr_end(addr, end); 121 next = pgd_addr_end(addr, end);
122
123 /* skip hugetlb vma to avoid hugepage PMD being cleared
124 * in pmd_none_or_clear_bad(). */
125 vma = find_vma(walk->mm, addr);
126 if (vma && is_vm_hugetlb_page(vma)) {
127 if (vma->vm_end < next)
128 next = vma->vm_end;
129 continue;
130 }
131
120 if (pgd_none_or_clear_bad(pgd)) { 132 if (pgd_none_or_clear_bad(pgd)) {
121 if (walk->pte_hole) 133 if (walk->pte_hole)
122 err = walk->pte_hole(addr, next, walk); 134 err = walk->pte_hole(addr, next, walk);
123 if (err) 135 if (err)
124 break; 136 break;
137 pgd++;
125 continue; 138 continue;
126 } 139 }
127 if (walk->pgd_entry) 140 if (walk->pgd_entry)
@@ -131,7 +144,8 @@ int walk_page_range(unsigned long addr, unsigned long end,
131 err = walk_pud_range(pgd, addr, next, walk); 144 err = walk_pud_range(pgd, addr, next, walk);
132 if (err) 145 if (err)
133 break; 146 break;
134 } while (pgd++, addr = next, addr != end); 147 pgd++;
148 } while (addr = next, addr != end);
135 149
136 return err; 150 return err;
137} 151}