diff options
Diffstat (limited to 'mm/pagewalk.c')
-rw-r--r-- | mm/pagewalk.c | 16 |
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 | ||
5 | static int walk_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, | 6 | static 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 | } |