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); |
