diff options
Diffstat (limited to 'mm/mempolicy.c')
-rw-r--r-- | mm/mempolicy.c | 83 |
1 files changed, 48 insertions, 35 deletions
diff --git a/mm/mempolicy.c b/mm/mempolicy.c index b19569137529..1d771e4200d2 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c | |||
@@ -390,7 +390,7 @@ static void mpol_rebind_policy(struct mempolicy *pol, const nodemask_t *newmask, | |||
390 | { | 390 | { |
391 | if (!pol) | 391 | if (!pol) |
392 | return; | 392 | return; |
393 | if (!mpol_store_user_nodemask(pol) && step == 0 && | 393 | if (!mpol_store_user_nodemask(pol) && step == MPOL_REBIND_ONCE && |
394 | nodes_equal(pol->w.cpuset_mems_allowed, *newmask)) | 394 | nodes_equal(pol->w.cpuset_mems_allowed, *newmask)) |
395 | return; | 395 | return; |
396 | 396 | ||
@@ -607,27 +607,6 @@ check_range(struct mm_struct *mm, unsigned long start, unsigned long end, | |||
607 | return first; | 607 | return first; |
608 | } | 608 | } |
609 | 609 | ||
610 | /* Apply policy to a single VMA */ | ||
611 | static int policy_vma(struct vm_area_struct *vma, struct mempolicy *new) | ||
612 | { | ||
613 | int err = 0; | ||
614 | struct mempolicy *old = vma->vm_policy; | ||
615 | |||
616 | pr_debug("vma %lx-%lx/%lx vm_ops %p vm_file %p set_policy %p\n", | ||
617 | vma->vm_start, vma->vm_end, vma->vm_pgoff, | ||
618 | vma->vm_ops, vma->vm_file, | ||
619 | vma->vm_ops ? vma->vm_ops->set_policy : NULL); | ||
620 | |||
621 | if (vma->vm_ops && vma->vm_ops->set_policy) | ||
622 | err = vma->vm_ops->set_policy(vma, new); | ||
623 | if (!err) { | ||
624 | mpol_get(new); | ||
625 | vma->vm_policy = new; | ||
626 | mpol_put(old); | ||
627 | } | ||
628 | return err; | ||
629 | } | ||
630 | |||
631 | /* Step 2: apply policy to a range and do splits. */ | 610 | /* Step 2: apply policy to a range and do splits. */ |
632 | static int mbind_range(struct mm_struct *mm, unsigned long start, | 611 | static int mbind_range(struct mm_struct *mm, unsigned long start, |
633 | unsigned long end, struct mempolicy *new_pol) | 612 | unsigned long end, struct mempolicy *new_pol) |
@@ -676,9 +655,23 @@ static int mbind_range(struct mm_struct *mm, unsigned long start, | |||
676 | if (err) | 655 | if (err) |
677 | goto out; | 656 | goto out; |
678 | } | 657 | } |
679 | err = policy_vma(vma, new_pol); | 658 | |
680 | if (err) | 659 | /* |
681 | goto out; | 660 | * Apply policy to a single VMA. The reference counting of |
661 | * policy for vma_policy linkages has already been handled by | ||
662 | * vma_merge and split_vma as necessary. If this is a shared | ||
663 | * policy then ->set_policy will increment the reference count | ||
664 | * for an sp node. | ||
665 | */ | ||
666 | pr_debug("vma %lx-%lx/%lx vm_ops %p vm_file %p set_policy %p\n", | ||
667 | vma->vm_start, vma->vm_end, vma->vm_pgoff, | ||
668 | vma->vm_ops, vma->vm_file, | ||
669 | vma->vm_ops ? vma->vm_ops->set_policy : NULL); | ||
670 | if (vma->vm_ops && vma->vm_ops->set_policy) { | ||
671 | err = vma->vm_ops->set_policy(vma, new_pol); | ||
672 | if (err) | ||
673 | goto out; | ||
674 | } | ||
682 | } | 675 | } |
683 | 676 | ||
684 | out: | 677 | out: |
@@ -957,8 +950,8 @@ static int migrate_to_node(struct mm_struct *mm, int source, int dest, | |||
957 | * | 950 | * |
958 | * Returns the number of page that could not be moved. | 951 | * Returns the number of page that could not be moved. |
959 | */ | 952 | */ |
960 | int do_migrate_pages(struct mm_struct *mm, | 953 | int do_migrate_pages(struct mm_struct *mm, const nodemask_t *from, |
961 | const nodemask_t *from_nodes, const nodemask_t *to_nodes, int flags) | 954 | const nodemask_t *to, int flags) |
962 | { | 955 | { |
963 | int busy = 0; | 956 | int busy = 0; |
964 | int err; | 957 | int err; |
@@ -970,7 +963,7 @@ int do_migrate_pages(struct mm_struct *mm, | |||
970 | 963 | ||
971 | down_read(&mm->mmap_sem); | 964 | down_read(&mm->mmap_sem); |
972 | 965 | ||
973 | err = migrate_vmas(mm, from_nodes, to_nodes, flags); | 966 | err = migrate_vmas(mm, from, to, flags); |
974 | if (err) | 967 | if (err) |
975 | goto out; | 968 | goto out; |
976 | 969 | ||
@@ -1005,14 +998,34 @@ int do_migrate_pages(struct mm_struct *mm, | |||
1005 | * moved to an empty node, then there is nothing left worth migrating. | 998 | * moved to an empty node, then there is nothing left worth migrating. |
1006 | */ | 999 | */ |
1007 | 1000 | ||
1008 | tmp = *from_nodes; | 1001 | tmp = *from; |
1009 | while (!nodes_empty(tmp)) { | 1002 | while (!nodes_empty(tmp)) { |
1010 | int s,d; | 1003 | int s,d; |
1011 | int source = -1; | 1004 | int source = -1; |
1012 | int dest = 0; | 1005 | int dest = 0; |
1013 | 1006 | ||
1014 | for_each_node_mask(s, tmp) { | 1007 | for_each_node_mask(s, tmp) { |
1015 | d = node_remap(s, *from_nodes, *to_nodes); | 1008 | |
1009 | /* | ||
1010 | * do_migrate_pages() tries to maintain the relative | ||
1011 | * node relationship of the pages established between | ||
1012 | * threads and memory areas. | ||
1013 | * | ||
1014 | * However if the number of source nodes is not equal to | ||
1015 | * the number of destination nodes we can not preserve | ||
1016 | * this node relative relationship. In that case, skip | ||
1017 | * copying memory from a node that is in the destination | ||
1018 | * mask. | ||
1019 | * | ||
1020 | * Example: [2,3,4] -> [3,4,5] moves everything. | ||
1021 | * [0-7] - > [3,4,5] moves only 0,1,2,6,7. | ||
1022 | */ | ||
1023 | |||
1024 | if ((nodes_weight(*from) != nodes_weight(*to)) && | ||
1025 | (node_isset(s, *to))) | ||
1026 | continue; | ||
1027 | |||
1028 | d = node_remap(s, *from, *to); | ||
1016 | if (s == d) | 1029 | if (s == d) |
1017 | continue; | 1030 | continue; |
1018 | 1031 | ||
@@ -1072,8 +1085,8 @@ static void migrate_page_add(struct page *page, struct list_head *pagelist, | |||
1072 | { | 1085 | { |
1073 | } | 1086 | } |
1074 | 1087 | ||
1075 | int do_migrate_pages(struct mm_struct *mm, | 1088 | int do_migrate_pages(struct mm_struct *mm, const nodemask_t *from, |
1076 | const nodemask_t *from_nodes, const nodemask_t *to_nodes, int flags) | 1089 | const nodemask_t *to, int flags) |
1077 | { | 1090 | { |
1078 | return -ENOSYS; | 1091 | return -ENOSYS; |
1079 | } | 1092 | } |
@@ -1164,7 +1177,7 @@ static long do_mbind(unsigned long start, unsigned long len, | |||
1164 | if (!list_empty(&pagelist)) { | 1177 | if (!list_empty(&pagelist)) { |
1165 | nr_failed = migrate_pages(&pagelist, new_vma_page, | 1178 | nr_failed = migrate_pages(&pagelist, new_vma_page, |
1166 | (unsigned long)vma, | 1179 | (unsigned long)vma, |
1167 | false, true); | 1180 | false, MIGRATE_SYNC); |
1168 | if (nr_failed) | 1181 | if (nr_failed) |
1169 | putback_lru_pages(&pagelist); | 1182 | putback_lru_pages(&pagelist); |
1170 | } | 1183 | } |
@@ -1334,8 +1347,8 @@ SYSCALL_DEFINE4(migrate_pages, pid_t, pid, unsigned long, maxnode, | |||
1334 | * userid as the target process. | 1347 | * userid as the target process. |
1335 | */ | 1348 | */ |
1336 | tcred = __task_cred(task); | 1349 | tcred = __task_cred(task); |
1337 | if (cred->euid != tcred->suid && cred->euid != tcred->uid && | 1350 | if (!uid_eq(cred->euid, tcred->suid) && !uid_eq(cred->euid, tcred->uid) && |
1338 | cred->uid != tcred->suid && cred->uid != tcred->uid && | 1351 | !uid_eq(cred->uid, tcred->suid) && !uid_eq(cred->uid, tcred->uid) && |
1339 | !capable(CAP_SYS_NICE)) { | 1352 | !capable(CAP_SYS_NICE)) { |
1340 | rcu_read_unlock(); | 1353 | rcu_read_unlock(); |
1341 | err = -EPERM; | 1354 | err = -EPERM; |