diff options
Diffstat (limited to 'mm/mempolicy.c')
| -rw-r--r-- | mm/mempolicy.c | 29 |
1 files changed, 16 insertions, 13 deletions
diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 43b1199af591..11d824f282f1 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c | |||
| @@ -223,13 +223,13 @@ static struct mempolicy *mpol_new(int mode, nodemask_t *nodes) | |||
| 223 | } | 223 | } |
| 224 | 224 | ||
| 225 | /* Ensure all existing pages follow the policy. */ | 225 | /* Ensure all existing pages follow the policy. */ |
| 226 | static int check_pte_range(struct mm_struct *mm, pmd_t *pmd, | 226 | static int check_pte_range(struct vm_area_struct *vma, pmd_t *pmd, |
| 227 | unsigned long addr, unsigned long end, nodemask_t *nodes) | 227 | unsigned long addr, unsigned long end, nodemask_t *nodes) |
| 228 | { | 228 | { |
| 229 | pte_t *orig_pte; | 229 | pte_t *orig_pte; |
| 230 | pte_t *pte; | 230 | pte_t *pte; |
| 231 | 231 | ||
| 232 | spin_lock(&mm->page_table_lock); | 232 | spin_lock(&vma->vm_mm->page_table_lock); |
| 233 | orig_pte = pte = pte_offset_map(pmd, addr); | 233 | orig_pte = pte = pte_offset_map(pmd, addr); |
| 234 | do { | 234 | do { |
| 235 | unsigned long pfn; | 235 | unsigned long pfn; |
| @@ -238,18 +238,20 @@ static int check_pte_range(struct mm_struct *mm, pmd_t *pmd, | |||
| 238 | if (!pte_present(*pte)) | 238 | if (!pte_present(*pte)) |
| 239 | continue; | 239 | continue; |
| 240 | pfn = pte_pfn(*pte); | 240 | pfn = pte_pfn(*pte); |
| 241 | if (!pfn_valid(pfn)) | 241 | if (!pfn_valid(pfn)) { |
| 242 | print_bad_pte(vma, *pte, addr); | ||
| 242 | continue; | 243 | continue; |
| 244 | } | ||
| 243 | nid = pfn_to_nid(pfn); | 245 | nid = pfn_to_nid(pfn); |
| 244 | if (!node_isset(nid, *nodes)) | 246 | if (!node_isset(nid, *nodes)) |
| 245 | break; | 247 | break; |
| 246 | } while (pte++, addr += PAGE_SIZE, addr != end); | 248 | } while (pte++, addr += PAGE_SIZE, addr != end); |
| 247 | pte_unmap(orig_pte); | 249 | pte_unmap(orig_pte); |
| 248 | spin_unlock(&mm->page_table_lock); | 250 | spin_unlock(&vma->vm_mm->page_table_lock); |
| 249 | return addr != end; | 251 | return addr != end; |
| 250 | } | 252 | } |
| 251 | 253 | ||
| 252 | static inline int check_pmd_range(struct mm_struct *mm, pud_t *pud, | 254 | static inline int check_pmd_range(struct vm_area_struct *vma, pud_t *pud, |
| 253 | unsigned long addr, unsigned long end, nodemask_t *nodes) | 255 | unsigned long addr, unsigned long end, nodemask_t *nodes) |
| 254 | { | 256 | { |
| 255 | pmd_t *pmd; | 257 | pmd_t *pmd; |
| @@ -260,13 +262,13 @@ static inline int check_pmd_range(struct mm_struct *mm, pud_t *pud, | |||
| 260 | next = pmd_addr_end(addr, end); | 262 | next = pmd_addr_end(addr, end); |
| 261 | if (pmd_none_or_clear_bad(pmd)) | 263 | if (pmd_none_or_clear_bad(pmd)) |
| 262 | continue; | 264 | continue; |
| 263 | if (check_pte_range(mm, pmd, addr, next, nodes)) | 265 | if (check_pte_range(vma, pmd, addr, next, nodes)) |
| 264 | return -EIO; | 266 | return -EIO; |
| 265 | } while (pmd++, addr = next, addr != end); | 267 | } while (pmd++, addr = next, addr != end); |
| 266 | return 0; | 268 | return 0; |
| 267 | } | 269 | } |
| 268 | 270 | ||
| 269 | static inline int check_pud_range(struct mm_struct *mm, pgd_t *pgd, | 271 | static inline int check_pud_range(struct vm_area_struct *vma, pgd_t *pgd, |
| 270 | unsigned long addr, unsigned long end, nodemask_t *nodes) | 272 | unsigned long addr, unsigned long end, nodemask_t *nodes) |
| 271 | { | 273 | { |
| 272 | pud_t *pud; | 274 | pud_t *pud; |
| @@ -277,24 +279,24 @@ static inline int check_pud_range(struct mm_struct *mm, pgd_t *pgd, | |||
| 277 | next = pud_addr_end(addr, end); | 279 | next = pud_addr_end(addr, end); |
| 278 | if (pud_none_or_clear_bad(pud)) | 280 | if (pud_none_or_clear_bad(pud)) |
| 279 | continue; | 281 | continue; |
| 280 | if (check_pmd_range(mm, pud, addr, next, nodes)) | 282 | if (check_pmd_range(vma, pud, addr, next, nodes)) |
| 281 | return -EIO; | 283 | return -EIO; |
| 282 | } while (pud++, addr = next, addr != end); | 284 | } while (pud++, addr = next, addr != end); |
| 283 | return 0; | 285 | return 0; |
| 284 | } | 286 | } |
| 285 | 287 | ||
| 286 | static inline int check_pgd_range(struct mm_struct *mm, | 288 | static inline int check_pgd_range(struct vm_area_struct *vma, |
| 287 | unsigned long addr, unsigned long end, nodemask_t *nodes) | 289 | unsigned long addr, unsigned long end, nodemask_t *nodes) |
| 288 | { | 290 | { |
| 289 | pgd_t *pgd; | 291 | pgd_t *pgd; |
| 290 | unsigned long next; | 292 | unsigned long next; |
| 291 | 293 | ||
| 292 | pgd = pgd_offset(mm, addr); | 294 | pgd = pgd_offset(vma->vm_mm, addr); |
| 293 | do { | 295 | do { |
| 294 | next = pgd_addr_end(addr, end); | 296 | next = pgd_addr_end(addr, end); |
| 295 | if (pgd_none_or_clear_bad(pgd)) | 297 | if (pgd_none_or_clear_bad(pgd)) |
| 296 | continue; | 298 | continue; |
| 297 | if (check_pud_range(mm, pgd, addr, next, nodes)) | 299 | if (check_pud_range(vma, pgd, addr, next, nodes)) |
| 298 | return -EIO; | 300 | return -EIO; |
| 299 | } while (pgd++, addr = next, addr != end); | 301 | } while (pgd++, addr = next, addr != end); |
| 300 | return 0; | 302 | return 0; |
| @@ -311,6 +313,8 @@ check_range(struct mm_struct *mm, unsigned long start, unsigned long end, | |||
| 311 | first = find_vma(mm, start); | 313 | first = find_vma(mm, start); |
| 312 | if (!first) | 314 | if (!first) |
| 313 | return ERR_PTR(-EFAULT); | 315 | return ERR_PTR(-EFAULT); |
| 316 | if (first->vm_flags & VM_RESERVED) | ||
| 317 | return ERR_PTR(-EACCES); | ||
| 314 | prev = NULL; | 318 | prev = NULL; |
| 315 | for (vma = first; vma && vma->vm_start < end; vma = vma->vm_next) { | 319 | for (vma = first; vma && vma->vm_start < end; vma = vma->vm_next) { |
| 316 | if (!vma->vm_next && vma->vm_end < end) | 320 | if (!vma->vm_next && vma->vm_end < end) |
| @@ -323,8 +327,7 @@ check_range(struct mm_struct *mm, unsigned long start, unsigned long end, | |||
| 323 | endvma = end; | 327 | endvma = end; |
| 324 | if (vma->vm_start > start) | 328 | if (vma->vm_start > start) |
| 325 | start = vma->vm_start; | 329 | start = vma->vm_start; |
| 326 | err = check_pgd_range(vma->vm_mm, | 330 | err = check_pgd_range(vma, start, endvma, nodes); |
| 327 | start, endvma, nodes); | ||
| 328 | if (err) { | 331 | if (err) { |
| 329 | first = ERR_PTR(err); | 332 | first = ERR_PTR(err); |
| 330 | break; | 333 | break; |
