diff options
Diffstat (limited to 'mm/vmalloc.c')
-rw-r--r-- | mm/vmalloc.c | 81 |
1 files changed, 60 insertions, 21 deletions
diff --git a/mm/vmalloc.c b/mm/vmalloc.c index b4024d688f38..0dd80222b20b 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c | |||
@@ -86,12 +86,12 @@ static void vunmap_pmd_range(pud_t *pud, unsigned long addr, unsigned long end) | |||
86 | } while (pmd++, addr = next, addr != end); | 86 | } while (pmd++, addr = next, addr != end); |
87 | } | 87 | } |
88 | 88 | ||
89 | static void vunmap_pud_range(pgd_t *pgd, unsigned long addr, unsigned long end) | 89 | static void vunmap_pud_range(p4d_t *p4d, unsigned long addr, unsigned long end) |
90 | { | 90 | { |
91 | pud_t *pud; | 91 | pud_t *pud; |
92 | unsigned long next; | 92 | unsigned long next; |
93 | 93 | ||
94 | pud = pud_offset(pgd, addr); | 94 | pud = pud_offset(p4d, addr); |
95 | do { | 95 | do { |
96 | next = pud_addr_end(addr, end); | 96 | next = pud_addr_end(addr, end); |
97 | if (pud_clear_huge(pud)) | 97 | if (pud_clear_huge(pud)) |
@@ -102,6 +102,22 @@ static void vunmap_pud_range(pgd_t *pgd, unsigned long addr, unsigned long end) | |||
102 | } while (pud++, addr = next, addr != end); | 102 | } while (pud++, addr = next, addr != end); |
103 | } | 103 | } |
104 | 104 | ||
105 | static void vunmap_p4d_range(pgd_t *pgd, unsigned long addr, unsigned long end) | ||
106 | { | ||
107 | p4d_t *p4d; | ||
108 | unsigned long next; | ||
109 | |||
110 | p4d = p4d_offset(pgd, addr); | ||
111 | do { | ||
112 | next = p4d_addr_end(addr, end); | ||
113 | if (p4d_clear_huge(p4d)) | ||
114 | continue; | ||
115 | if (p4d_none_or_clear_bad(p4d)) | ||
116 | continue; | ||
117 | vunmap_pud_range(p4d, addr, next); | ||
118 | } while (p4d++, addr = next, addr != end); | ||
119 | } | ||
120 | |||
105 | static void vunmap_page_range(unsigned long addr, unsigned long end) | 121 | static void vunmap_page_range(unsigned long addr, unsigned long end) |
106 | { | 122 | { |
107 | pgd_t *pgd; | 123 | pgd_t *pgd; |
@@ -113,7 +129,7 @@ static void vunmap_page_range(unsigned long addr, unsigned long end) | |||
113 | next = pgd_addr_end(addr, end); | 129 | next = pgd_addr_end(addr, end); |
114 | if (pgd_none_or_clear_bad(pgd)) | 130 | if (pgd_none_or_clear_bad(pgd)) |
115 | continue; | 131 | continue; |
116 | vunmap_pud_range(pgd, addr, next); | 132 | vunmap_p4d_range(pgd, addr, next); |
117 | } while (pgd++, addr = next, addr != end); | 133 | } while (pgd++, addr = next, addr != end); |
118 | } | 134 | } |
119 | 135 | ||
@@ -160,13 +176,13 @@ static int vmap_pmd_range(pud_t *pud, unsigned long addr, | |||
160 | return 0; | 176 | return 0; |
161 | } | 177 | } |
162 | 178 | ||
163 | static int vmap_pud_range(pgd_t *pgd, unsigned long addr, | 179 | static int vmap_pud_range(p4d_t *p4d, unsigned long addr, |
164 | unsigned long end, pgprot_t prot, struct page **pages, int *nr) | 180 | unsigned long end, pgprot_t prot, struct page **pages, int *nr) |
165 | { | 181 | { |
166 | pud_t *pud; | 182 | pud_t *pud; |
167 | unsigned long next; | 183 | unsigned long next; |
168 | 184 | ||
169 | pud = pud_alloc(&init_mm, pgd, addr); | 185 | pud = pud_alloc(&init_mm, p4d, addr); |
170 | if (!pud) | 186 | if (!pud) |
171 | return -ENOMEM; | 187 | return -ENOMEM; |
172 | do { | 188 | do { |
@@ -177,6 +193,23 @@ static int vmap_pud_range(pgd_t *pgd, unsigned long addr, | |||
177 | return 0; | 193 | return 0; |
178 | } | 194 | } |
179 | 195 | ||
196 | static int vmap_p4d_range(pgd_t *pgd, unsigned long addr, | ||
197 | unsigned long end, pgprot_t prot, struct page **pages, int *nr) | ||
198 | { | ||
199 | p4d_t *p4d; | ||
200 | unsigned long next; | ||
201 | |||
202 | p4d = p4d_alloc(&init_mm, pgd, addr); | ||
203 | if (!p4d) | ||
204 | return -ENOMEM; | ||
205 | do { | ||
206 | next = p4d_addr_end(addr, end); | ||
207 | if (vmap_pud_range(p4d, addr, next, prot, pages, nr)) | ||
208 | return -ENOMEM; | ||
209 | } while (p4d++, addr = next, addr != end); | ||
210 | return 0; | ||
211 | } | ||
212 | |||
180 | /* | 213 | /* |
181 | * Set up page tables in kva (addr, end). The ptes shall have prot "prot", and | 214 | * Set up page tables in kva (addr, end). The ptes shall have prot "prot", and |
182 | * will have pfns corresponding to the "pages" array. | 215 | * will have pfns corresponding to the "pages" array. |
@@ -196,7 +229,7 @@ static int vmap_page_range_noflush(unsigned long start, unsigned long end, | |||
196 | pgd = pgd_offset_k(addr); | 229 | pgd = pgd_offset_k(addr); |
197 | do { | 230 | do { |
198 | next = pgd_addr_end(addr, end); | 231 | next = pgd_addr_end(addr, end); |
199 | err = vmap_pud_range(pgd, addr, next, prot, pages, &nr); | 232 | err = vmap_p4d_range(pgd, addr, next, prot, pages, &nr); |
200 | if (err) | 233 | if (err) |
201 | return err; | 234 | return err; |
202 | } while (pgd++, addr = next, addr != end); | 235 | } while (pgd++, addr = next, addr != end); |
@@ -237,6 +270,10 @@ struct page *vmalloc_to_page(const void *vmalloc_addr) | |||
237 | unsigned long addr = (unsigned long) vmalloc_addr; | 270 | unsigned long addr = (unsigned long) vmalloc_addr; |
238 | struct page *page = NULL; | 271 | struct page *page = NULL; |
239 | pgd_t *pgd = pgd_offset_k(addr); | 272 | pgd_t *pgd = pgd_offset_k(addr); |
273 | p4d_t *p4d; | ||
274 | pud_t *pud; | ||
275 | pmd_t *pmd; | ||
276 | pte_t *ptep, pte; | ||
240 | 277 | ||
241 | /* | 278 | /* |
242 | * XXX we might need to change this if we add VIRTUAL_BUG_ON for | 279 | * XXX we might need to change this if we add VIRTUAL_BUG_ON for |
@@ -244,21 +281,23 @@ struct page *vmalloc_to_page(const void *vmalloc_addr) | |||
244 | */ | 281 | */ |
245 | VIRTUAL_BUG_ON(!is_vmalloc_or_module_addr(vmalloc_addr)); | 282 | VIRTUAL_BUG_ON(!is_vmalloc_or_module_addr(vmalloc_addr)); |
246 | 283 | ||
247 | if (!pgd_none(*pgd)) { | 284 | if (pgd_none(*pgd)) |
248 | pud_t *pud = pud_offset(pgd, addr); | 285 | return NULL; |
249 | if (!pud_none(*pud)) { | 286 | p4d = p4d_offset(pgd, addr); |
250 | pmd_t *pmd = pmd_offset(pud, addr); | 287 | if (p4d_none(*p4d)) |
251 | if (!pmd_none(*pmd)) { | 288 | return NULL; |
252 | pte_t *ptep, pte; | 289 | pud = pud_offset(p4d, addr); |
253 | 290 | if (pud_none(*pud)) | |
254 | ptep = pte_offset_map(pmd, addr); | 291 | return NULL; |
255 | pte = *ptep; | 292 | pmd = pmd_offset(pud, addr); |
256 | if (pte_present(pte)) | 293 | if (pmd_none(*pmd)) |
257 | page = pte_page(pte); | 294 | return NULL; |
258 | pte_unmap(ptep); | 295 | |
259 | } | 296 | ptep = pte_offset_map(pmd, addr); |
260 | } | 297 | pte = *ptep; |
261 | } | 298 | if (pte_present(pte)) |
299 | page = pte_page(pte); | ||
300 | pte_unmap(ptep); | ||
262 | return page; | 301 | return page; |
263 | } | 302 | } |
264 | EXPORT_SYMBOL(vmalloc_to_page); | 303 | EXPORT_SYMBOL(vmalloc_to_page); |