diff options
Diffstat (limited to 'mm/mempolicy.c')
-rw-r--r-- | mm/mempolicy.c | 54 |
1 files changed, 37 insertions, 17 deletions
diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 8778f58880c4..e07e27e846a2 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c | |||
@@ -87,6 +87,8 @@ | |||
87 | #include <linux/seq_file.h> | 87 | #include <linux/seq_file.h> |
88 | #include <linux/proc_fs.h> | 88 | #include <linux/proc_fs.h> |
89 | #include <linux/migrate.h> | 89 | #include <linux/migrate.h> |
90 | #include <linux/rmap.h> | ||
91 | #include <linux/security.h> | ||
90 | 92 | ||
91 | #include <asm/tlbflush.h> | 93 | #include <asm/tlbflush.h> |
92 | #include <asm/uaccess.h> | 94 | #include <asm/uaccess.h> |
@@ -587,6 +589,11 @@ static void migrate_page_add(struct page *page, struct list_head *pagelist, | |||
587 | isolate_lru_page(page, pagelist); | 589 | isolate_lru_page(page, pagelist); |
588 | } | 590 | } |
589 | 591 | ||
592 | static struct page *new_node_page(struct page *page, unsigned long node, int **x) | ||
593 | { | ||
594 | return alloc_pages_node(node, GFP_HIGHUSER, 0); | ||
595 | } | ||
596 | |||
590 | /* | 597 | /* |
591 | * Migrate pages from one node to a target node. | 598 | * Migrate pages from one node to a target node. |
592 | * Returns error or the number of pages not migrated. | 599 | * Returns error or the number of pages not migrated. |
@@ -603,11 +610,9 @@ int migrate_to_node(struct mm_struct *mm, int source, int dest, int flags) | |||
603 | check_range(mm, mm->mmap->vm_start, TASK_SIZE, &nmask, | 610 | check_range(mm, mm->mmap->vm_start, TASK_SIZE, &nmask, |
604 | flags | MPOL_MF_DISCONTIG_OK, &pagelist); | 611 | flags | MPOL_MF_DISCONTIG_OK, &pagelist); |
605 | 612 | ||
606 | if (!list_empty(&pagelist)) { | 613 | if (!list_empty(&pagelist)) |
607 | err = migrate_pages_to(&pagelist, NULL, dest); | 614 | err = migrate_pages(&pagelist, new_node_page, dest); |
608 | if (!list_empty(&pagelist)) | 615 | |
609 | putback_lru_pages(&pagelist); | ||
610 | } | ||
611 | return err; | 616 | return err; |
612 | } | 617 | } |
613 | 618 | ||
@@ -627,6 +632,10 @@ int do_migrate_pages(struct mm_struct *mm, | |||
627 | 632 | ||
628 | down_read(&mm->mmap_sem); | 633 | down_read(&mm->mmap_sem); |
629 | 634 | ||
635 | err = migrate_vmas(mm, from_nodes, to_nodes, flags); | ||
636 | if (err) | ||
637 | goto out; | ||
638 | |||
630 | /* | 639 | /* |
631 | * Find a 'source' bit set in 'tmp' whose corresponding 'dest' | 640 | * Find a 'source' bit set in 'tmp' whose corresponding 'dest' |
632 | * bit in 'to' is not also set in 'tmp'. Clear the found 'source' | 641 | * bit in 'to' is not also set in 'tmp'. Clear the found 'source' |
@@ -686,7 +695,7 @@ int do_migrate_pages(struct mm_struct *mm, | |||
686 | if (err < 0) | 695 | if (err < 0) |
687 | break; | 696 | break; |
688 | } | 697 | } |
689 | 698 | out: | |
690 | up_read(&mm->mmap_sem); | 699 | up_read(&mm->mmap_sem); |
691 | if (err < 0) | 700 | if (err < 0) |
692 | return err; | 701 | return err; |
@@ -694,6 +703,12 @@ int do_migrate_pages(struct mm_struct *mm, | |||
694 | 703 | ||
695 | } | 704 | } |
696 | 705 | ||
706 | static struct page *new_vma_page(struct page *page, unsigned long private, int **x) | ||
707 | { | ||
708 | struct vm_area_struct *vma = (struct vm_area_struct *)private; | ||
709 | |||
710 | return alloc_page_vma(GFP_HIGHUSER, vma, page_address_in_vma(page, vma)); | ||
711 | } | ||
697 | #else | 712 | #else |
698 | 713 | ||
699 | static void migrate_page_add(struct page *page, struct list_head *pagelist, | 714 | static void migrate_page_add(struct page *page, struct list_head *pagelist, |
@@ -706,6 +721,11 @@ int do_migrate_pages(struct mm_struct *mm, | |||
706 | { | 721 | { |
707 | return -ENOSYS; | 722 | return -ENOSYS; |
708 | } | 723 | } |
724 | |||
725 | static struct page *new_vma_page(struct page *page, unsigned long private) | ||
726 | { | ||
727 | return NULL; | ||
728 | } | ||
709 | #endif | 729 | #endif |
710 | 730 | ||
711 | long do_mbind(unsigned long start, unsigned long len, | 731 | long do_mbind(unsigned long start, unsigned long len, |
@@ -767,15 +787,13 @@ long do_mbind(unsigned long start, unsigned long len, | |||
767 | err = mbind_range(vma, start, end, new); | 787 | err = mbind_range(vma, start, end, new); |
768 | 788 | ||
769 | if (!list_empty(&pagelist)) | 789 | if (!list_empty(&pagelist)) |
770 | nr_failed = migrate_pages_to(&pagelist, vma, -1); | 790 | nr_failed = migrate_pages(&pagelist, new_vma_page, |
791 | (unsigned long)vma); | ||
771 | 792 | ||
772 | if (!err && nr_failed && (flags & MPOL_MF_STRICT)) | 793 | if (!err && nr_failed && (flags & MPOL_MF_STRICT)) |
773 | err = -EIO; | 794 | err = -EIO; |
774 | } | 795 | } |
775 | 796 | ||
776 | if (!list_empty(&pagelist)) | ||
777 | putback_lru_pages(&pagelist); | ||
778 | |||
779 | up_write(&mm->mmap_sem); | 797 | up_write(&mm->mmap_sem); |
780 | mpol_free(new); | 798 | mpol_free(new); |
781 | return err; | 799 | return err; |
@@ -929,6 +947,10 @@ asmlinkage long sys_migrate_pages(pid_t pid, unsigned long maxnode, | |||
929 | goto out; | 947 | goto out; |
930 | } | 948 | } |
931 | 949 | ||
950 | err = security_task_movememory(task); | ||
951 | if (err) | ||
952 | goto out; | ||
953 | |||
932 | err = do_migrate_pages(mm, &old, &new, | 954 | err = do_migrate_pages(mm, &old, &new, |
933 | capable(CAP_SYS_NICE) ? MPOL_MF_MOVE_ALL : MPOL_MF_MOVE); | 955 | capable(CAP_SYS_NICE) ? MPOL_MF_MOVE_ALL : MPOL_MF_MOVE); |
934 | out: | 956 | out: |
@@ -1187,10 +1209,8 @@ static struct page *alloc_page_interleave(gfp_t gfp, unsigned order, | |||
1187 | 1209 | ||
1188 | zl = NODE_DATA(nid)->node_zonelists + gfp_zone(gfp); | 1210 | zl = NODE_DATA(nid)->node_zonelists + gfp_zone(gfp); |
1189 | page = __alloc_pages(gfp, order, zl); | 1211 | page = __alloc_pages(gfp, order, zl); |
1190 | if (page && page_zone(page) == zl->zones[0]) { | 1212 | if (page && page_zone(page) == zl->zones[0]) |
1191 | zone_pcp(zl->zones[0],get_cpu())->interleave_hit++; | 1213 | inc_zone_page_state(page, NUMA_INTERLEAVE_HIT); |
1192 | put_cpu(); | ||
1193 | } | ||
1194 | return page; | 1214 | return page; |
1195 | } | 1215 | } |
1196 | 1216 | ||
@@ -1799,7 +1819,7 @@ static inline void check_huge_range(struct vm_area_struct *vma, | |||
1799 | 1819 | ||
1800 | int show_numa_map(struct seq_file *m, void *v) | 1820 | int show_numa_map(struct seq_file *m, void *v) |
1801 | { | 1821 | { |
1802 | struct task_struct *task = m->private; | 1822 | struct proc_maps_private *priv = m->private; |
1803 | struct vm_area_struct *vma = v; | 1823 | struct vm_area_struct *vma = v; |
1804 | struct numa_maps *md; | 1824 | struct numa_maps *md; |
1805 | struct file *file = vma->vm_file; | 1825 | struct file *file = vma->vm_file; |
@@ -1815,7 +1835,7 @@ int show_numa_map(struct seq_file *m, void *v) | |||
1815 | return 0; | 1835 | return 0; |
1816 | 1836 | ||
1817 | mpol_to_str(buffer, sizeof(buffer), | 1837 | mpol_to_str(buffer, sizeof(buffer), |
1818 | get_vma_policy(task, vma, vma->vm_start)); | 1838 | get_vma_policy(priv->task, vma, vma->vm_start)); |
1819 | 1839 | ||
1820 | seq_printf(m, "%08lx %s", vma->vm_start, buffer); | 1840 | seq_printf(m, "%08lx %s", vma->vm_start, buffer); |
1821 | 1841 | ||
@@ -1869,7 +1889,7 @@ out: | |||
1869 | kfree(md); | 1889 | kfree(md); |
1870 | 1890 | ||
1871 | if (m->count < m->size) | 1891 | if (m->count < m->size) |
1872 | m->version = (vma != get_gate_vma(task)) ? vma->vm_start : 0; | 1892 | m->version = (vma != priv->tail_vma) ? vma->vm_start : 0; |
1873 | return 0; | 1893 | return 0; |
1874 | } | 1894 | } |
1875 | 1895 | ||