aboutsummaryrefslogtreecommitdiffstats
path: root/mm/vmalloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/vmalloc.c')
-rw-r--r--mm/vmalloc.c81
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
89static void vunmap_pud_range(pgd_t *pgd, unsigned long addr, unsigned long end) 89static 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
105static 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
105static void vunmap_page_range(unsigned long addr, unsigned long end) 121static 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
163static int vmap_pud_range(pgd_t *pgd, unsigned long addr, 179static 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
196static 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}
264EXPORT_SYMBOL(vmalloc_to_page); 303EXPORT_SYMBOL(vmalloc_to_page);