aboutsummaryrefslogtreecommitdiffstats
path: root/mm/mempolicy.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/mempolicy.c')
-rw-r--r--mm/mempolicy.c52
1 files changed, 38 insertions, 14 deletions
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index 92daa267baf2..f0728ae74672 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -607,24 +607,39 @@ 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 */ 610/*
611static int policy_vma(struct vm_area_struct *vma, struct mempolicy *new) 611 * Apply policy to a single VMA
612 * This must be called with the mmap_sem held for writing.
613 */
614static int vma_replace_policy(struct vm_area_struct *vma,
615 struct mempolicy *pol)
612{ 616{
613 int err = 0; 617 int err;
614 struct mempolicy *old = vma->vm_policy; 618 struct mempolicy *old;
619 struct mempolicy *new;
615 620
616 pr_debug("vma %lx-%lx/%lx vm_ops %p vm_file %p set_policy %p\n", 621 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, 622 vma->vm_start, vma->vm_end, vma->vm_pgoff,
618 vma->vm_ops, vma->vm_file, 623 vma->vm_ops, vma->vm_file,
619 vma->vm_ops ? vma->vm_ops->set_policy : NULL); 624 vma->vm_ops ? vma->vm_ops->set_policy : NULL);
620 625
621 if (vma->vm_ops && vma->vm_ops->set_policy) 626 new = mpol_dup(pol);
627 if (IS_ERR(new))
628 return PTR_ERR(new);
629
630 if (vma->vm_ops && vma->vm_ops->set_policy) {
622 err = vma->vm_ops->set_policy(vma, new); 631 err = vma->vm_ops->set_policy(vma, new);
623 if (!err) { 632 if (err)
624 mpol_get(new); 633 goto err_out;
625 vma->vm_policy = new;
626 mpol_put(old);
627 } 634 }
635
636 old = vma->vm_policy;
637 vma->vm_policy = new; /* protected by mmap_sem */
638 mpol_put(old);
639
640 return 0;
641 err_out:
642 mpol_put(new);
628 return err; 643 return err;
629} 644}
630 645
@@ -676,7 +691,7 @@ static int mbind_range(struct mm_struct *mm, unsigned long start,
676 if (err) 691 if (err)
677 goto out; 692 goto out;
678 } 693 }
679 err = policy_vma(vma, new_pol); 694 err = vma_replace_policy(vma, new_pol);
680 if (err) 695 if (err)
681 goto out; 696 goto out;
682 } 697 }
@@ -2153,15 +2168,24 @@ static void sp_delete(struct shared_policy *sp, struct sp_node *n)
2153static struct sp_node *sp_alloc(unsigned long start, unsigned long end, 2168static struct sp_node *sp_alloc(unsigned long start, unsigned long end,
2154 struct mempolicy *pol) 2169 struct mempolicy *pol)
2155{ 2170{
2156 struct sp_node *n = kmem_cache_alloc(sn_cache, GFP_KERNEL); 2171 struct sp_node *n;
2172 struct mempolicy *newpol;
2157 2173
2174 n = kmem_cache_alloc(sn_cache, GFP_KERNEL);
2158 if (!n) 2175 if (!n)
2159 return NULL; 2176 return NULL;
2177
2178 newpol = mpol_dup(pol);
2179 if (IS_ERR(newpol)) {
2180 kmem_cache_free(sn_cache, n);
2181 return NULL;
2182 }
2183 newpol->flags |= MPOL_F_SHARED;
2184
2160 n->start = start; 2185 n->start = start;
2161 n->end = end; 2186 n->end = end;
2162 mpol_get(pol); 2187 n->policy = newpol;
2163 pol->flags |= MPOL_F_SHARED; /* for unref */ 2188
2164 n->policy = pol;
2165 return n; 2189 return n;
2166} 2190}
2167 2191