Skip to content

Commit a7f40cf

Browse files
Yang Shitorvalds
Yang Shi
authored andcommitted
mm: mempolicy: make mbind() return -EIO when MPOL_MF_STRICT is specified
When MPOL_MF_STRICT was specified and an existing page was already on a node that does not follow the policy, mbind() should return -EIO. But commit 6f4576e ("mempolicy: apply page table walker on queue_pages_range()") broke the rule. And commit c863379 ("mm: mempolicy: mbind and migrate_pages support thp migration") didn't return the correct value for THP mbind() too. If MPOL_MF_STRICT is set, ignore vma_migratable() to make sure it reaches queue_pages_to_pte_range() or queue_pages_pmd() to check if an existing page was already on a node that does not follow the policy. And, non-migratable vma may be used, return -EIO too if MPOL_MF_MOVE or MPOL_MF_MOVE_ALL was specified. Tested with https://github.com/metan-ucw/ltp/blob/master/testcases/kernel/syscalls/mbind/mbind02.c [[email protected]: tweak code comment] Link: http://lkml.kernel.org/r/[email protected] Fixes: 6f4576e ("mempolicy: apply page table walker on queue_pages_range()") Signed-off-by: Yang Shi <[email protected]> Signed-off-by: Oscar Salvador <[email protected]> Reported-by: Cyril Hrubis <[email protected]> Suggested-by: Kirill A. Shutemov <[email protected]> Acked-by: Rafael Aquini <[email protected]> Reviewed-by: Oscar Salvador <[email protected]> Acked-by: David Rientjes <[email protected]> Cc: Vlastimil Babka <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent a953e77 commit a7f40cf

File tree

1 file changed

+33
-7
lines changed

1 file changed

+33
-7
lines changed

mm/mempolicy.c

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,13 @@ static inline bool queue_pages_required(struct page *page,
428428
return node_isset(nid, *qp->nmask) == !(flags & MPOL_MF_INVERT);
429429
}
430430

431+
/*
432+
* queue_pages_pmd() has three possible return values:
433+
* 1 - pages are placed on the right node or queued successfully.
434+
* 0 - THP was split.
435+
* -EIO - is migration entry or MPOL_MF_STRICT was specified and an existing
436+
* page was already on a node that does not follow the policy.
437+
*/
431438
static int queue_pages_pmd(pmd_t *pmd, spinlock_t *ptl, unsigned long addr,
432439
unsigned long end, struct mm_walk *walk)
433440
{
@@ -437,7 +444,7 @@ static int queue_pages_pmd(pmd_t *pmd, spinlock_t *ptl, unsigned long addr,
437444
unsigned long flags;
438445

439446
if (unlikely(is_pmd_migration_entry(*pmd))) {
440-
ret = 1;
447+
ret = -EIO;
441448
goto unlock;
442449
}
443450
page = pmd_page(*pmd);
@@ -454,8 +461,15 @@ static int queue_pages_pmd(pmd_t *pmd, spinlock_t *ptl, unsigned long addr,
454461
ret = 1;
455462
flags = qp->flags;
456463
/* go to thp migration */
457-
if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL))
464+
if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) {
465+
if (!vma_migratable(walk->vma)) {
466+
ret = -EIO;
467+
goto unlock;
468+
}
469+
458470
migrate_page_add(page, qp->pagelist, flags);
471+
} else
472+
ret = -EIO;
459473
unlock:
460474
spin_unlock(ptl);
461475
out:
@@ -480,8 +494,10 @@ static int queue_pages_pte_range(pmd_t *pmd, unsigned long addr,
480494
ptl = pmd_trans_huge_lock(pmd, vma);
481495
if (ptl) {
482496
ret = queue_pages_pmd(pmd, ptl, addr, end, walk);
483-
if (ret)
497+
if (ret > 0)
484498
return 0;
499+
else if (ret < 0)
500+
return ret;
485501
}
486502

487503
if (pmd_trans_unstable(pmd))
@@ -502,11 +518,16 @@ static int queue_pages_pte_range(pmd_t *pmd, unsigned long addr,
502518
continue;
503519
if (!queue_pages_required(page, qp))
504520
continue;
505-
migrate_page_add(page, qp->pagelist, flags);
521+
if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) {
522+
if (!vma_migratable(vma))
523+
break;
524+
migrate_page_add(page, qp->pagelist, flags);
525+
} else
526+
break;
506527
}
507528
pte_unmap_unlock(pte - 1, ptl);
508529
cond_resched();
509-
return 0;
530+
return addr != end ? -EIO : 0;
510531
}
511532

512533
static int queue_pages_hugetlb(pte_t *pte, unsigned long hmask,
@@ -576,7 +597,12 @@ static int queue_pages_test_walk(unsigned long start, unsigned long end,
576597
unsigned long endvma = vma->vm_end;
577598
unsigned long flags = qp->flags;
578599

579-
if (!vma_migratable(vma))
600+
/*
601+
* Need check MPOL_MF_STRICT to return -EIO if possible
602+
* regardless of vma_migratable
603+
*/
604+
if (!vma_migratable(vma) &&
605+
!(flags & MPOL_MF_STRICT))
580606
return 1;
581607

582608
if (endvma > end)
@@ -603,7 +629,7 @@ static int queue_pages_test_walk(unsigned long start, unsigned long end,
603629
}
604630

605631
/* queue pages from current vma */
606-
if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL))
632+
if (flags & MPOL_MF_VALID)
607633
return 0;
608634
return 1;
609635
}

0 commit comments

Comments
 (0)