diff options
Diffstat (limited to 'mm/mremap.c')
-rw-r--r-- | mm/mremap.c | 27 |
1 files changed, 14 insertions, 13 deletions
diff --git a/mm/mremap.c b/mm/mremap.c index f9766f460299..463a25705ac6 100644 --- a/mm/mremap.c +++ b/mm/mremap.c | |||
@@ -135,7 +135,7 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd, | |||
135 | pte_unmap(new_pte - 1); | 135 | pte_unmap(new_pte - 1); |
136 | pte_unmap_unlock(old_pte - 1, old_ptl); | 136 | pte_unmap_unlock(old_pte - 1, old_ptl); |
137 | if (anon_vma) | 137 | if (anon_vma) |
138 | anon_vma_unlock(anon_vma); | 138 | anon_vma_unlock_write(anon_vma); |
139 | if (mapping) | 139 | if (mapping) |
140 | mutex_unlock(&mapping->i_mmap_mutex); | 140 | mutex_unlock(&mapping->i_mmap_mutex); |
141 | } | 141 | } |
@@ -209,7 +209,7 @@ unsigned long move_page_tables(struct vm_area_struct *vma, | |||
209 | 209 | ||
210 | static unsigned long move_vma(struct vm_area_struct *vma, | 210 | static unsigned long move_vma(struct vm_area_struct *vma, |
211 | unsigned long old_addr, unsigned long old_len, | 211 | unsigned long old_addr, unsigned long old_len, |
212 | unsigned long new_len, unsigned long new_addr) | 212 | unsigned long new_len, unsigned long new_addr, bool *locked) |
213 | { | 213 | { |
214 | struct mm_struct *mm = vma->vm_mm; | 214 | struct mm_struct *mm = vma->vm_mm; |
215 | struct vm_area_struct *new_vma; | 215 | struct vm_area_struct *new_vma; |
@@ -300,9 +300,7 @@ static unsigned long move_vma(struct vm_area_struct *vma, | |||
300 | 300 | ||
301 | if (vm_flags & VM_LOCKED) { | 301 | if (vm_flags & VM_LOCKED) { |
302 | mm->locked_vm += new_len >> PAGE_SHIFT; | 302 | mm->locked_vm += new_len >> PAGE_SHIFT; |
303 | if (new_len > old_len) | 303 | *locked = true; |
304 | mlock_vma_pages_range(new_vma, new_addr + old_len, | ||
305 | new_addr + new_len); | ||
306 | } | 304 | } |
307 | 305 | ||
308 | return new_addr; | 306 | return new_addr; |
@@ -367,9 +365,8 @@ Eagain: | |||
367 | return ERR_PTR(-EAGAIN); | 365 | return ERR_PTR(-EAGAIN); |
368 | } | 366 | } |
369 | 367 | ||
370 | static unsigned long mremap_to(unsigned long addr, | 368 | static unsigned long mremap_to(unsigned long addr, unsigned long old_len, |
371 | unsigned long old_len, unsigned long new_addr, | 369 | unsigned long new_addr, unsigned long new_len, bool *locked) |
372 | unsigned long new_len) | ||
373 | { | 370 | { |
374 | struct mm_struct *mm = current->mm; | 371 | struct mm_struct *mm = current->mm; |
375 | struct vm_area_struct *vma; | 372 | struct vm_area_struct *vma; |
@@ -419,7 +416,7 @@ static unsigned long mremap_to(unsigned long addr, | |||
419 | if (ret & ~PAGE_MASK) | 416 | if (ret & ~PAGE_MASK) |
420 | goto out1; | 417 | goto out1; |
421 | 418 | ||
422 | ret = move_vma(vma, addr, old_len, new_len, new_addr); | 419 | ret = move_vma(vma, addr, old_len, new_len, new_addr, locked); |
423 | if (!(ret & ~PAGE_MASK)) | 420 | if (!(ret & ~PAGE_MASK)) |
424 | goto out; | 421 | goto out; |
425 | out1: | 422 | out1: |
@@ -457,6 +454,7 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len, | |||
457 | struct vm_area_struct *vma; | 454 | struct vm_area_struct *vma; |
458 | unsigned long ret = -EINVAL; | 455 | unsigned long ret = -EINVAL; |
459 | unsigned long charged = 0; | 456 | unsigned long charged = 0; |
457 | bool locked = false; | ||
460 | 458 | ||
461 | down_write(¤t->mm->mmap_sem); | 459 | down_write(¤t->mm->mmap_sem); |
462 | 460 | ||
@@ -479,7 +477,8 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len, | |||
479 | 477 | ||
480 | if (flags & MREMAP_FIXED) { | 478 | if (flags & MREMAP_FIXED) { |
481 | if (flags & MREMAP_MAYMOVE) | 479 | if (flags & MREMAP_MAYMOVE) |
482 | ret = mremap_to(addr, old_len, new_addr, new_len); | 480 | ret = mremap_to(addr, old_len, new_addr, new_len, |
481 | &locked); | ||
483 | goto out; | 482 | goto out; |
484 | } | 483 | } |
485 | 484 | ||
@@ -521,8 +520,8 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len, | |||
521 | vm_stat_account(mm, vma->vm_flags, vma->vm_file, pages); | 520 | vm_stat_account(mm, vma->vm_flags, vma->vm_file, pages); |
522 | if (vma->vm_flags & VM_LOCKED) { | 521 | if (vma->vm_flags & VM_LOCKED) { |
523 | mm->locked_vm += pages; | 522 | mm->locked_vm += pages; |
524 | mlock_vma_pages_range(vma, addr + old_len, | 523 | locked = true; |
525 | addr + new_len); | 524 | new_addr = addr; |
526 | } | 525 | } |
527 | ret = addr; | 526 | ret = addr; |
528 | goto out; | 527 | goto out; |
@@ -548,11 +547,13 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len, | |||
548 | goto out; | 547 | goto out; |
549 | } | 548 | } |
550 | 549 | ||
551 | ret = move_vma(vma, addr, old_len, new_len, new_addr); | 550 | ret = move_vma(vma, addr, old_len, new_len, new_addr, &locked); |
552 | } | 551 | } |
553 | out: | 552 | out: |
554 | if (ret & ~PAGE_MASK) | 553 | if (ret & ~PAGE_MASK) |
555 | vm_unacct_memory(charged); | 554 | vm_unacct_memory(charged); |
556 | up_write(¤t->mm->mmap_sem); | 555 | up_write(¤t->mm->mmap_sem); |
556 | if (locked && new_len > old_len) | ||
557 | mm_populate(new_addr + old_len, new_len - old_len); | ||
557 | return ret; | 558 | return ret; |
558 | } | 559 | } |