mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	untangling do_mremap(), part 1
Take locating vma and checks on it to a separate helper (it will be shared between MREMAP_FIXED/non-MREMAP_FIXED cases when we split them in the next patch) Acked-by: Russell King <rmk+kernel@arm.linux.org.uk> Acked-by: Hugh Dickins <hugh.dickins@tiscali.co.uk> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
		
							parent
							
								
									3ef884b4c0
								
							
						
					
					
						commit
						54f5de7099
					
				
					 1 changed files with 55 additions and 33 deletions
				
			
		
							
								
								
									
										88
									
								
								mm/mremap.c
									
									
									
									
									
								
							
							
						
						
									
										88
									
								
								mm/mremap.c
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -261,6 +261,58 @@ static unsigned long move_vma(struct vm_area_struct *vma,
 | 
			
		|||
	return new_addr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct vm_area_struct *vma_to_resize(unsigned long addr,
 | 
			
		||||
	unsigned long old_len, unsigned long new_len, unsigned long *p)
 | 
			
		||||
{
 | 
			
		||||
	struct mm_struct *mm = current->mm;
 | 
			
		||||
	struct vm_area_struct *vma = find_vma(mm, addr);
 | 
			
		||||
 | 
			
		||||
	if (!vma || vma->vm_start > addr)
 | 
			
		||||
		goto Efault;
 | 
			
		||||
 | 
			
		||||
	if (is_vm_hugetlb_page(vma))
 | 
			
		||||
		goto Einval;
 | 
			
		||||
 | 
			
		||||
	/* We can't remap across vm area boundaries */
 | 
			
		||||
	if (old_len > vma->vm_end - addr)
 | 
			
		||||
		goto Efault;
 | 
			
		||||
 | 
			
		||||
	if (vma->vm_flags & (VM_DONTEXPAND | VM_PFNMAP)) {
 | 
			
		||||
		if (new_len > old_len)
 | 
			
		||||
			goto Efault;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (vma->vm_flags & VM_LOCKED) {
 | 
			
		||||
		unsigned long locked, lock_limit;
 | 
			
		||||
		locked = mm->locked_vm << PAGE_SHIFT;
 | 
			
		||||
		lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur;
 | 
			
		||||
		locked += new_len - old_len;
 | 
			
		||||
		if (locked > lock_limit && !capable(CAP_IPC_LOCK))
 | 
			
		||||
			goto Eagain;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!may_expand_vm(mm, (new_len - old_len) >> PAGE_SHIFT))
 | 
			
		||||
		goto Enomem;
 | 
			
		||||
 | 
			
		||||
	if (vma->vm_flags & VM_ACCOUNT) {
 | 
			
		||||
		unsigned long charged = (new_len - old_len) >> PAGE_SHIFT;
 | 
			
		||||
		if (security_vm_enough_memory(charged))
 | 
			
		||||
			goto Efault;
 | 
			
		||||
		*p = charged;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return vma;
 | 
			
		||||
 | 
			
		||||
Efault:	/* very odd choice for most of the cases, but... */
 | 
			
		||||
	return ERR_PTR(-EFAULT);
 | 
			
		||||
Einval:
 | 
			
		||||
	return ERR_PTR(-EINVAL);
 | 
			
		||||
Enomem:
 | 
			
		||||
	return ERR_PTR(-ENOMEM);
 | 
			
		||||
Eagain:
 | 
			
		||||
	return ERR_PTR(-EAGAIN);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Expand (or shrink) an existing mapping, potentially moving it at the
 | 
			
		||||
 * same time (controlled by the MREMAP_MAYMOVE flag and available VM space)
 | 
			
		||||
| 
						 | 
				
			
			@ -340,39 +392,10 @@ unsigned long do_mremap(unsigned long addr,
 | 
			
		|||
	/*
 | 
			
		||||
	 * Ok, we need to grow..  or relocate.
 | 
			
		||||
	 */
 | 
			
		||||
	ret = -EFAULT;
 | 
			
		||||
	vma = find_vma(mm, addr);
 | 
			
		||||
	if (!vma || vma->vm_start > addr)
 | 
			
		||||
	vma = vma_to_resize(addr, old_len, new_len, &charged);
 | 
			
		||||
	if (IS_ERR(vma)) {
 | 
			
		||||
		ret = PTR_ERR(vma);
 | 
			
		||||
		goto out;
 | 
			
		||||
	if (is_vm_hugetlb_page(vma)) {
 | 
			
		||||
		ret = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	/* We can't remap across vm area boundaries */
 | 
			
		||||
	if (old_len > vma->vm_end - addr)
 | 
			
		||||
		goto out;
 | 
			
		||||
	if (vma->vm_flags & (VM_DONTEXPAND | VM_PFNMAP)) {
 | 
			
		||||
		if (new_len > old_len)
 | 
			
		||||
			goto out;
 | 
			
		||||
	}
 | 
			
		||||
	if (vma->vm_flags & VM_LOCKED) {
 | 
			
		||||
		unsigned long locked, lock_limit;
 | 
			
		||||
		locked = mm->locked_vm << PAGE_SHIFT;
 | 
			
		||||
		lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur;
 | 
			
		||||
		locked += new_len - old_len;
 | 
			
		||||
		ret = -EAGAIN;
 | 
			
		||||
		if (locked > lock_limit && !capable(CAP_IPC_LOCK))
 | 
			
		||||
			goto out;
 | 
			
		||||
	}
 | 
			
		||||
	if (!may_expand_vm(mm, (new_len - old_len) >> PAGE_SHIFT)) {
 | 
			
		||||
		ret = -ENOMEM;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (vma->vm_flags & VM_ACCOUNT) {
 | 
			
		||||
		charged = (new_len - old_len) >> PAGE_SHIFT;
 | 
			
		||||
		if (security_vm_enough_memory(charged))
 | 
			
		||||
			goto out_nc;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* old_len exactly to the end of the area..
 | 
			
		||||
| 
						 | 
				
			
			@ -430,7 +453,6 @@ unsigned long do_mremap(unsigned long addr,
 | 
			
		|||
out:
 | 
			
		||||
	if (ret & ~PAGE_MASK)
 | 
			
		||||
		vm_unacct_memory(charged);
 | 
			
		||||
out_nc:
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue