diff options
| -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 290fb5bf044..44dd9d1521e 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)  }  /* Step 2: apply policy to a range and do splits. */ -static int mbind_range(struct vm_area_struct *vma, unsigned long start, -		       unsigned long end, struct mempolicy *new) +static int mbind_range(struct mm_struct *mm, unsigned long start, +		       unsigned long end, struct mempolicy *new_pol)  {  	struct vm_area_struct *next; -	int err; +	struct vm_area_struct *prev; +	struct vm_area_struct *vma; +	int err = 0; +	pgoff_t pgoff; +	unsigned long vmstart; +	unsigned long vmend; -	err = 0; -	for (; vma && vma->vm_start < end; vma = next) { +	vma = find_vma_prev(mm, start, &prev); +	if (!vma || vma->vm_start > start) +		return -EFAULT; + +	for (; vma && vma->vm_start < end; prev = vma, vma = next) {  		next = vma->vm_next; -		if (vma->vm_start < start) -			err = split_vma(vma->vm_mm, vma, start, 1); -		if (!err && vma->vm_end > end) -			err = split_vma(vma->vm_mm, vma, end, 0); -		if (!err) -			err = policy_vma(vma, new); +		vmstart = max(start, vma->vm_start); +		vmend   = min(end, vma->vm_end); + +		pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT); +		prev = vma_merge(mm, prev, vmstart, vmend, vma->vm_flags, +				  vma->anon_vma, vma->vm_file, pgoff, new_pol); +		if (prev) { +			vma = prev; +			next = vma->vm_next; +			continue; +		} +		if (vma->vm_start != vmstart) { +			err = split_vma(vma->vm_mm, vma, vmstart, 1); +			if (err) +				goto out; +		} +		if (vma->vm_end != vmend) { +			err = split_vma(vma->vm_mm, vma, vmend, 0); +			if (err) +				goto out; +		} +		err = policy_vma(vma, new_pol);  		if (err) -			break; +			goto out;  	} + + out:  	return err;  } @@ -1047,7 +1073,7 @@ static long do_mbind(unsigned long start, unsigned long len,  	if (!IS_ERR(vma)) {  		int nr_failed = 0; -		err = mbind_range(vma, start, end, new); +		err = mbind_range(mm, start, end, new);  		if (!list_empty(&pagelist))  			nr_failed = migrate_pages(&pagelist, new_vma_page,  |