diff options
Diffstat (limited to 'mm/mempolicy.c')
-rw-r--r-- | mm/mempolicy.c | 52 |
1 files changed, 39 insertions, 13 deletions
diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 290fb5bf0440..44dd9d1521ec 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c | |||
@@ -563,24 +563,50 @@ static int policy_vma(struct vm_area_struct *vma, struct mempolicy *new) | |||
563 | } | 563 | } |
564 | 564 | ||
565 | /* Step 2: apply policy to a range and do splits. */ | 565 | /* Step 2: apply policy to a range and do splits. */ |
566 | static int mbind_range(struct vm_area_struct *vma, unsigned long start, | 566 | static int mbind_range(struct mm_struct *mm, unsigned long start, |
567 | unsigned long end, struct mempolicy *new) | 567 | unsigned long end, struct mempolicy *new_pol) |
568 | { | 568 | { |
569 | struct vm_area_struct *next; | 569 | struct vm_area_struct *next; |
570 | int err; | 570 | struct vm_area_struct *prev; |
571 | struct vm_area_struct *vma; | ||
572 | int err = 0; | ||
573 | pgoff_t pgoff; | ||
574 | unsigned long vmstart; | ||
575 | unsigned long vmend; | ||
571 | 576 | ||
572 | err = 0; | 577 | vma = find_vma_prev(mm, start, &prev); |
573 | for (; vma && vma->vm_start < end; vma = next) { | 578 | if (!vma || vma->vm_start > start) |
579 | return -EFAULT; | ||
580 | |||
581 | for (; vma && vma->vm_start < end; prev = vma, vma = next) { | ||
574 | next = vma->vm_next; | 582 | next = vma->vm_next; |
575 | if (vma->vm_start < start) | 583 | vmstart = max(start, vma->vm_start); |
576 | err = split_vma(vma->vm_mm, vma, start, 1); | 584 | vmend = min(end, vma->vm_end); |
577 | if (!err && vma->vm_end > end) | 585 | |
578 | err = split_vma(vma->vm_mm, vma, end, 0); | 586 | pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT); |
579 | if (!err) | 587 | prev = vma_merge(mm, prev, vmstart, vmend, vma->vm_flags, |
580 | err = policy_vma(vma, new); | 588 | vma->anon_vma, vma->vm_file, pgoff, new_pol); |
589 | if (prev) { | ||
590 | vma = prev; | ||
591 | next = vma->vm_next; | ||
592 | continue; | ||
593 | } | ||
594 | if (vma->vm_start != vmstart) { | ||
595 | err = split_vma(vma->vm_mm, vma, vmstart, 1); | ||
596 | if (err) | ||
597 | goto out; | ||
598 | } | ||
599 | if (vma->vm_end != vmend) { | ||
600 | err = split_vma(vma->vm_mm, vma, vmend, 0); | ||
601 | if (err) | ||
602 | goto out; | ||
603 | } | ||
604 | err = policy_vma(vma, new_pol); | ||
581 | if (err) | 605 | if (err) |
582 | break; | 606 | goto out; |
583 | } | 607 | } |
608 | |||
609 | out: | ||
584 | return err; | 610 | return err; |
585 | } | 611 | } |
586 | 612 | ||
@@ -1047,7 +1073,7 @@ static long do_mbind(unsigned long start, unsigned long len, | |||
1047 | if (!IS_ERR(vma)) { | 1073 | if (!IS_ERR(vma)) { |
1048 | int nr_failed = 0; | 1074 | int nr_failed = 0; |
1049 | 1075 | ||
1050 | err = mbind_range(vma, start, end, new); | 1076 | err = mbind_range(mm, start, end, new); |
1051 | 1077 | ||
1052 | if (!list_empty(&pagelist)) | 1078 | if (!list_empty(&pagelist)) |
1053 | nr_failed = migrate_pages(&pagelist, new_vma_page, | 1079 | nr_failed = migrate_pages(&pagelist, new_vma_page, |