aboutsummaryrefslogtreecommitdiffstats
path: root/mm/mempolicy.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/mempolicy.c')
-rw-r--r--mm/mempolicy.c110
1 files changed, 72 insertions, 38 deletions
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index 08c41da429cf..cb41c31e7c87 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -238,46 +238,80 @@ static struct mempolicy *mpol_new(int mode, unsigned long *nodes)
238} 238}
239 239
240/* Ensure all existing pages follow the policy. */ 240/* Ensure all existing pages follow the policy. */
241static int 241static int check_pte_range(struct mm_struct *mm, pmd_t *pmd,
242verify_pages(struct mm_struct *mm, 242 unsigned long addr, unsigned long end, unsigned long *nodes)
243 unsigned long addr, unsigned long end, unsigned long *nodes)
244{ 243{
245 while (addr < end) { 244 pte_t *orig_pte;
246 struct page *p; 245 pte_t *pte;
247 pte_t *pte; 246
248 pmd_t *pmd; 247 spin_lock(&mm->page_table_lock);
249 pud_t *pud; 248 orig_pte = pte = pte_offset_map(pmd, addr);
250 pgd_t *pgd; 249 do {
251 pgd = pgd_offset(mm, addr); 250 unsigned long pfn;
252 if (pgd_none(*pgd)) { 251 unsigned int nid;
253 unsigned long next = (addr + PGDIR_SIZE) & PGDIR_MASK; 252
254 if (next > addr) 253 if (!pte_present(*pte))
255 break;
256 addr = next;
257 continue; 254 continue;
258 } 255 pfn = pte_pfn(*pte);
259 pud = pud_offset(pgd, addr); 256 if (!pfn_valid(pfn))
260 if (pud_none(*pud)) {
261 addr = (addr + PUD_SIZE) & PUD_MASK;
262 continue; 257 continue;
263 } 258 nid = pfn_to_nid(pfn);
264 pmd = pmd_offset(pud, addr); 259 if (!test_bit(nid, nodes))
265 if (pmd_none(*pmd)) { 260 break;
266 addr = (addr + PMD_SIZE) & PMD_MASK; 261 } while (pte++, addr += PAGE_SIZE, addr != end);
262 pte_unmap(orig_pte);
263 spin_unlock(&mm->page_table_lock);
264 return addr != end;
265}
266
267static inline int check_pmd_range(struct mm_struct *mm, pud_t *pud,
268 unsigned long addr, unsigned long end, unsigned long *nodes)
269{
270 pmd_t *pmd;
271 unsigned long next;
272
273 pmd = pmd_offset(pud, addr);
274 do {
275 next = pmd_addr_end(addr, end);
276 if (pmd_none_or_clear_bad(pmd))
267 continue; 277 continue;
268 } 278 if (check_pte_range(mm, pmd, addr, next, nodes))
269 p = NULL; 279 return -EIO;
270 pte = pte_offset_map(pmd, addr); 280 } while (pmd++, addr = next, addr != end);
271 if (pte_present(*pte)) 281 return 0;
272 p = pte_page(*pte); 282}
273 pte_unmap(pte); 283
274 if (p) { 284static inline int check_pud_range(struct mm_struct *mm, pgd_t *pgd,
275 unsigned nid = page_to_nid(p); 285 unsigned long addr, unsigned long end, unsigned long *nodes)
276 if (!test_bit(nid, nodes)) 286{
277 return -EIO; 287 pud_t *pud;
278 } 288 unsigned long next;
279 addr += PAGE_SIZE; 289
280 } 290 pud = pud_offset(pgd, addr);
291 do {
292 next = pud_addr_end(addr, end);
293 if (pud_none_or_clear_bad(pud))
294 continue;
295 if (check_pmd_range(mm, pud, addr, next, nodes))
296 return -EIO;
297 } while (pud++, addr = next, addr != end);
298 return 0;
299}
300
301static inline int check_pgd_range(struct mm_struct *mm,
302 unsigned long addr, unsigned long end, unsigned long *nodes)
303{
304 pgd_t *pgd;
305 unsigned long next;
306
307 pgd = pgd_offset(mm, addr);
308 do {
309 next = pgd_addr_end(addr, end);
310 if (pgd_none_or_clear_bad(pgd))
311 continue;
312 if (check_pud_range(mm, pgd, addr, next, nodes))
313 return -EIO;
314 } while (pgd++, addr = next, addr != end);
281 return 0; 315 return 0;
282} 316}
283 317
@@ -299,7 +333,7 @@ check_range(struct mm_struct *mm, unsigned long start, unsigned long end,
299 if (prev && prev->vm_end < vma->vm_start) 333 if (prev && prev->vm_end < vma->vm_start)
300 return ERR_PTR(-EFAULT); 334 return ERR_PTR(-EFAULT);
301 if ((flags & MPOL_MF_STRICT) && !is_vm_hugetlb_page(vma)) { 335 if ((flags & MPOL_MF_STRICT) && !is_vm_hugetlb_page(vma)) {
302 err = verify_pages(vma->vm_mm, 336 err = check_pgd_range(vma->vm_mm,
303 vma->vm_start, vma->vm_end, nodes); 337 vma->vm_start, vma->vm_end, nodes);
304 if (err) { 338 if (err) {
305 first = ERR_PTR(err); 339 first = ERR_PTR(err);
@@ -721,7 +755,7 @@ static struct page *alloc_page_interleave(unsigned int __nocast gfp, unsigned or
721 zl = NODE_DATA(nid)->node_zonelists + (gfp & GFP_ZONEMASK); 755 zl = NODE_DATA(nid)->node_zonelists + (gfp & GFP_ZONEMASK);
722 page = __alloc_pages(gfp, order, zl); 756 page = __alloc_pages(gfp, order, zl);
723 if (page && page_zone(page) == zl->zones[0]) { 757 if (page && page_zone(page) == zl->zones[0]) {
724 zl->zones[0]->pageset[get_cpu()].interleave_hit++; 758 zone_pcp(zl->zones[0],get_cpu())->interleave_hit++;
725 put_cpu(); 759 put_cpu();
726 } 760 }
727 return page; 761 return page;