diff options
Diffstat (limited to 'mm/mempolicy.c')
-rw-r--r-- | mm/mempolicy.c | 52 |
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 | /* |
611 | static 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 | */ | ||
614 | static 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) | |||
2153 | static struct sp_node *sp_alloc(unsigned long start, unsigned long end, | 2168 | static 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 | ||