diff options
Diffstat (limited to 'mm/pagewalk.c')
-rw-r--r-- | mm/pagewalk.c | 32 |
1 files changed, 31 insertions, 1 deletions
diff --git a/mm/pagewalk.c b/mm/pagewalk.c index d5878bed7841..7b47a57b6646 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,38 @@ 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 | /* | ||
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 | */ | ||
128 | vma = find_vma(walk->mm, addr); | ||
129 | #ifdef CONFIG_HUGETLB_PAGE | ||
130 | if (vma && is_vm_hugetlb_page(vma)) { | ||
131 | pte_t *pte; | ||
132 | struct hstate *hs; | ||
133 | |||
134 | if (vma->vm_end < next) | ||
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; | ||
145 | continue; | ||
146 | } | ||
147 | #endif | ||
120 | if (pgd_none_or_clear_bad(pgd)) { | 148 | if (pgd_none_or_clear_bad(pgd)) { |
121 | if (walk->pte_hole) | 149 | if (walk->pte_hole) |
122 | err = walk->pte_hole(addr, next, walk); | 150 | err = walk->pte_hole(addr, next, walk); |
123 | if (err) | 151 | if (err) |
124 | break; | 152 | break; |
153 | pgd++; | ||
125 | continue; | 154 | continue; |
126 | } | 155 | } |
127 | if (walk->pgd_entry) | 156 | if (walk->pgd_entry) |
@@ -131,7 +160,8 @@ int walk_page_range(unsigned long addr, unsigned long end, | |||
131 | err = walk_pud_range(pgd, addr, next, walk); | 160 | err = walk_pud_range(pgd, addr, next, walk); |
132 | if (err) | 161 | if (err) |
133 | break; | 162 | break; |
134 | } while (pgd++, addr = next, addr != end); | 163 | pgd++; |
164 | } while (addr = next, addr != end); | ||
135 | 165 | ||
136 | return err; | 166 | return err; |
137 | } | 167 | } |