diff options
Diffstat (limited to 'mm/mempolicy.c')
-rw-r--r-- | mm/mempolicy.c | 82 |
1 files changed, 64 insertions, 18 deletions
diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 7dd9d9f80694..290fb5bf0440 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c | |||
@@ -85,10 +85,12 @@ | |||
85 | #include <linux/seq_file.h> | 85 | #include <linux/seq_file.h> |
86 | #include <linux/proc_fs.h> | 86 | #include <linux/proc_fs.h> |
87 | #include <linux/migrate.h> | 87 | #include <linux/migrate.h> |
88 | #include <linux/ksm.h> | ||
88 | #include <linux/rmap.h> | 89 | #include <linux/rmap.h> |
89 | #include <linux/security.h> | 90 | #include <linux/security.h> |
90 | #include <linux/syscalls.h> | 91 | #include <linux/syscalls.h> |
91 | #include <linux/ctype.h> | 92 | #include <linux/ctype.h> |
93 | #include <linux/mm_inline.h> | ||
92 | 94 | ||
93 | #include <asm/tlbflush.h> | 95 | #include <asm/tlbflush.h> |
94 | #include <asm/uaccess.h> | 96 | #include <asm/uaccess.h> |
@@ -412,17 +414,11 @@ static int check_pte_range(struct vm_area_struct *vma, pmd_t *pmd, | |||
412 | if (!page) | 414 | if (!page) |
413 | continue; | 415 | continue; |
414 | /* | 416 | /* |
415 | * The check for PageReserved here is important to avoid | 417 | * vm_normal_page() filters out zero pages, but there might |
416 | * handling zero pages and other pages that may have been | 418 | * still be PageReserved pages to skip, perhaps in a VDSO. |
417 | * marked special by the system. | 419 | * And we cannot move PageKsm pages sensibly or safely yet. |
418 | * | ||
419 | * If the PageReserved would not be checked here then f.e. | ||
420 | * the location of the zero page could have an influence | ||
421 | * on MPOL_MF_STRICT, zero pages would be counted for | ||
422 | * the per node stats, and there would be useless attempts | ||
423 | * to put zero pages on the migration list. | ||
424 | */ | 420 | */ |
425 | if (PageReserved(page)) | 421 | if (PageReserved(page) || PageKsm(page)) |
426 | continue; | 422 | continue; |
427 | nid = page_to_nid(page); | 423 | nid = page_to_nid(page); |
428 | if (node_isset(nid, *nodes) == !!(flags & MPOL_MF_INVERT)) | 424 | if (node_isset(nid, *nodes) == !!(flags & MPOL_MF_INVERT)) |
@@ -809,6 +805,8 @@ static void migrate_page_add(struct page *page, struct list_head *pagelist, | |||
809 | if ((flags & MPOL_MF_MOVE_ALL) || page_mapcount(page) == 1) { | 805 | if ((flags & MPOL_MF_MOVE_ALL) || page_mapcount(page) == 1) { |
810 | if (!isolate_lru_page(page)) { | 806 | if (!isolate_lru_page(page)) { |
811 | list_add_tail(&page->lru, pagelist); | 807 | list_add_tail(&page->lru, pagelist); |
808 | inc_zone_page_state(page, NR_ISOLATED_ANON + | ||
809 | page_is_file_cache(page)); | ||
812 | } | 810 | } |
813 | } | 811 | } |
814 | } | 812 | } |
@@ -836,7 +834,7 @@ static int migrate_to_node(struct mm_struct *mm, int source, int dest, | |||
836 | flags | MPOL_MF_DISCONTIG_OK, &pagelist); | 834 | flags | MPOL_MF_DISCONTIG_OK, &pagelist); |
837 | 835 | ||
838 | if (!list_empty(&pagelist)) | 836 | if (!list_empty(&pagelist)) |
839 | err = migrate_pages(&pagelist, new_node_page, dest); | 837 | err = migrate_pages(&pagelist, new_node_page, dest, 0); |
840 | 838 | ||
841 | return err; | 839 | return err; |
842 | } | 840 | } |
@@ -1024,7 +1022,7 @@ static long do_mbind(unsigned long start, unsigned long len, | |||
1024 | 1022 | ||
1025 | err = migrate_prep(); | 1023 | err = migrate_prep(); |
1026 | if (err) | 1024 | if (err) |
1027 | return err; | 1025 | goto mpol_out; |
1028 | } | 1026 | } |
1029 | { | 1027 | { |
1030 | NODEMASK_SCRATCH(scratch); | 1028 | NODEMASK_SCRATCH(scratch); |
@@ -1039,10 +1037,9 @@ static long do_mbind(unsigned long start, unsigned long len, | |||
1039 | err = -ENOMEM; | 1037 | err = -ENOMEM; |
1040 | NODEMASK_SCRATCH_FREE(scratch); | 1038 | NODEMASK_SCRATCH_FREE(scratch); |
1041 | } | 1039 | } |
1042 | if (err) { | 1040 | if (err) |
1043 | mpol_put(new); | 1041 | goto mpol_out; |
1044 | return err; | 1042 | |
1045 | } | ||
1046 | vma = check_range(mm, start, end, nmask, | 1043 | vma = check_range(mm, start, end, nmask, |
1047 | flags | MPOL_MF_INVERT, &pagelist); | 1044 | flags | MPOL_MF_INVERT, &pagelist); |
1048 | 1045 | ||
@@ -1054,13 +1051,15 @@ static long do_mbind(unsigned long start, unsigned long len, | |||
1054 | 1051 | ||
1055 | if (!list_empty(&pagelist)) | 1052 | if (!list_empty(&pagelist)) |
1056 | nr_failed = migrate_pages(&pagelist, new_vma_page, | 1053 | nr_failed = migrate_pages(&pagelist, new_vma_page, |
1057 | (unsigned long)vma); | 1054 | (unsigned long)vma, 0); |
1058 | 1055 | ||
1059 | if (!err && nr_failed && (flags & MPOL_MF_STRICT)) | 1056 | if (!err && nr_failed && (flags & MPOL_MF_STRICT)) |
1060 | err = -EIO; | 1057 | err = -EIO; |
1061 | } | 1058 | } else |
1059 | putback_lru_pages(&pagelist); | ||
1062 | 1060 | ||
1063 | up_write(&mm->mmap_sem); | 1061 | up_write(&mm->mmap_sem); |
1062 | mpol_out: | ||
1064 | mpol_put(new); | 1063 | mpol_put(new); |
1065 | return err; | 1064 | return err; |
1066 | } | 1065 | } |
@@ -1564,6 +1563,53 @@ struct zonelist *huge_zonelist(struct vm_area_struct *vma, unsigned long addr, | |||
1564 | } | 1563 | } |
1565 | return zl; | 1564 | return zl; |
1566 | } | 1565 | } |
1566 | |||
1567 | /* | ||
1568 | * init_nodemask_of_mempolicy | ||
1569 | * | ||
1570 | * If the current task's mempolicy is "default" [NULL], return 'false' | ||
1571 | * to indicate default policy. Otherwise, extract the policy nodemask | ||
1572 | * for 'bind' or 'interleave' policy into the argument nodemask, or | ||
1573 | * initialize the argument nodemask to contain the single node for | ||
1574 | * 'preferred' or 'local' policy and return 'true' to indicate presence | ||
1575 | * of non-default mempolicy. | ||
1576 | * | ||
1577 | * We don't bother with reference counting the mempolicy [mpol_get/put] | ||
1578 | * because the current task is examining it's own mempolicy and a task's | ||
1579 | * mempolicy is only ever changed by the task itself. | ||
1580 | * | ||
1581 | * N.B., it is the caller's responsibility to free a returned nodemask. | ||
1582 | */ | ||
1583 | bool init_nodemask_of_mempolicy(nodemask_t *mask) | ||
1584 | { | ||
1585 | struct mempolicy *mempolicy; | ||
1586 | int nid; | ||
1587 | |||
1588 | if (!(mask && current->mempolicy)) | ||
1589 | return false; | ||
1590 | |||
1591 | mempolicy = current->mempolicy; | ||
1592 | switch (mempolicy->mode) { | ||
1593 | case MPOL_PREFERRED: | ||
1594 | if (mempolicy->flags & MPOL_F_LOCAL) | ||
1595 | nid = numa_node_id(); | ||
1596 | else | ||
1597 | nid = mempolicy->v.preferred_node; | ||
1598 | init_nodemask_of_node(mask, nid); | ||
1599 | break; | ||
1600 | |||
1601 | case MPOL_BIND: | ||
1602 | /* Fall through */ | ||
1603 | case MPOL_INTERLEAVE: | ||
1604 | *mask = mempolicy->v.nodes; | ||
1605 | break; | ||
1606 | |||
1607 | default: | ||
1608 | BUG(); | ||
1609 | } | ||
1610 | |||
1611 | return true; | ||
1612 | } | ||
1567 | #endif | 1613 | #endif |
1568 | 1614 | ||
1569 | /* Allocate a page in interleaved policy. | 1615 | /* Allocate a page in interleaved policy. |