aboutsummaryrefslogtreecommitdiffstats
path: root/mm/mlock.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/mlock.c')
-rw-r--r--mm/mlock.c64
1 files changed, 11 insertions, 53 deletions
diff --git a/mm/mlock.c b/mm/mlock.c
index 3035a56e7616..028ec482fdd4 100644
--- a/mm/mlock.c
+++ b/mm/mlock.c
@@ -173,12 +173,13 @@ static long __mlock_vma_pages_range(struct vm_area_struct *vma,
173 (atomic_read(&mm->mm_users) != 0)); 173 (atomic_read(&mm->mm_users) != 0));
174 174
175 /* 175 /*
176 * mlock: don't page populate if page has PROT_NONE permission. 176 * mlock: don't page populate if vma has PROT_NONE permission.
177 * munlock: the pages always do munlock althrough 177 * munlock: always do munlock although the vma has PROT_NONE
178 * its has PROT_NONE permission. 178 * permission, or SIGKILL is pending.
179 */ 179 */
180 if (!mlock) 180 if (!mlock)
181 gup_flags |= GUP_FLAGS_IGNORE_VMA_PERMISSIONS; 181 gup_flags |= GUP_FLAGS_IGNORE_VMA_PERMISSIONS |
182 GUP_FLAGS_IGNORE_SIGKILL;
182 183
183 if (vma->vm_flags & VM_WRITE) 184 if (vma->vm_flags & VM_WRITE)
184 gup_flags |= GUP_FLAGS_WRITE; 185 gup_flags |= GUP_FLAGS_WRITE;
@@ -293,14 +294,10 @@ static inline int __mlock_posix_error_return(long retval)
293 * 294 *
294 * return number of pages [> 0] to be removed from locked_vm on success 295 * return number of pages [> 0] to be removed from locked_vm on success
295 * of "special" vmas. 296 * of "special" vmas.
296 *
297 * return negative error if vma spanning @start-@range disappears while
298 * mmap semaphore is dropped. Unlikely?
299 */ 297 */
300long mlock_vma_pages_range(struct vm_area_struct *vma, 298long mlock_vma_pages_range(struct vm_area_struct *vma,
301 unsigned long start, unsigned long end) 299 unsigned long start, unsigned long end)
302{ 300{
303 struct mm_struct *mm = vma->vm_mm;
304 int nr_pages = (end - start) / PAGE_SIZE; 301 int nr_pages = (end - start) / PAGE_SIZE;
305 BUG_ON(!(vma->vm_flags & VM_LOCKED)); 302 BUG_ON(!(vma->vm_flags & VM_LOCKED));
306 303
@@ -313,20 +310,8 @@ long mlock_vma_pages_range(struct vm_area_struct *vma,
313 if (!((vma->vm_flags & (VM_DONTEXPAND | VM_RESERVED)) || 310 if (!((vma->vm_flags & (VM_DONTEXPAND | VM_RESERVED)) ||
314 is_vm_hugetlb_page(vma) || 311 is_vm_hugetlb_page(vma) ||
315 vma == get_gate_vma(current))) { 312 vma == get_gate_vma(current))) {
316 long error;
317 downgrade_write(&mm->mmap_sem);
318
319 error = __mlock_vma_pages_range(vma, start, end, 1);
320 313
321 up_read(&mm->mmap_sem); 314 return __mlock_vma_pages_range(vma, start, end, 1);
322 /* vma can change or disappear */
323 down_write(&mm->mmap_sem);
324 vma = find_vma(mm, start);
325 /* non-NULL vma must contain @start, but need to check @end */
326 if (!vma || end > vma->vm_end)
327 return -ENOMEM;
328
329 return 0; /* hide other errors from mmap(), et al */
330 } 315 }
331 316
332 /* 317 /*
@@ -437,41 +422,14 @@ success:
437 vma->vm_flags = newflags; 422 vma->vm_flags = newflags;
438 423
439 if (lock) { 424 if (lock) {
440 /*
441 * mmap_sem is currently held for write. Downgrade the write
442 * lock to a read lock so that other faults, mmap scans, ...
443 * while we fault in all pages.
444 */
445 downgrade_write(&mm->mmap_sem);
446
447 ret = __mlock_vma_pages_range(vma, start, end, 1); 425 ret = __mlock_vma_pages_range(vma, start, end, 1);
448 426
449 /* 427 if (ret > 0) {
450 * Need to reacquire mmap sem in write mode, as our callers
451 * expect this. We have no support for atomically upgrading
452 * a sem to write, so we need to check for ranges while sem
453 * is unlocked.
454 */
455 up_read(&mm->mmap_sem);
456 /* vma can change or disappear */
457 down_write(&mm->mmap_sem);
458 *prev = find_vma(mm, start);
459 /* non-NULL *prev must contain @start, but need to check @end */
460 if (!(*prev) || end > (*prev)->vm_end)
461 ret = -ENOMEM;
462 else if (ret > 0) {
463 mm->locked_vm -= ret; 428 mm->locked_vm -= ret;
464 ret = 0; 429 ret = 0;
465 } else 430 } else
466 ret = __mlock_posix_error_return(ret); /* translate if needed */ 431 ret = __mlock_posix_error_return(ret); /* translate if needed */
467 } else { 432 } else {
468 /*
469 * TODO: for unlocking, pages will already be resident, so
470 * we don't need to wait for allocations/reclaim/pagein, ...
471 * However, unlocking a very large region can still take a
472 * while. Should we downgrade the semaphore for both lock
473 * AND unlock ?
474 */
475 __mlock_vma_pages_range(vma, start, end, 0); 433 __mlock_vma_pages_range(vma, start, end, 0);
476 } 434 }
477 435
@@ -529,7 +487,7 @@ static int do_mlock(unsigned long start, size_t len, int on)
529 return error; 487 return error;
530} 488}
531 489
532asmlinkage long sys_mlock(unsigned long start, size_t len) 490SYSCALL_DEFINE2(mlock, unsigned long, start, size_t, len)
533{ 491{
534 unsigned long locked; 492 unsigned long locked;
535 unsigned long lock_limit; 493 unsigned long lock_limit;
@@ -557,7 +515,7 @@ asmlinkage long sys_mlock(unsigned long start, size_t len)
557 return error; 515 return error;
558} 516}
559 517
560asmlinkage long sys_munlock(unsigned long start, size_t len) 518SYSCALL_DEFINE2(munlock, unsigned long, start, size_t, len)
561{ 519{
562 int ret; 520 int ret;
563 521
@@ -594,7 +552,7 @@ out:
594 return 0; 552 return 0;
595} 553}
596 554
597asmlinkage long sys_mlockall(int flags) 555SYSCALL_DEFINE1(mlockall, int, flags)
598{ 556{
599 unsigned long lock_limit; 557 unsigned long lock_limit;
600 int ret = -EINVAL; 558 int ret = -EINVAL;
@@ -622,7 +580,7 @@ out:
622 return ret; 580 return ret;
623} 581}
624 582
625asmlinkage long sys_munlockall(void) 583SYSCALL_DEFINE0(munlockall)
626{ 584{
627 int ret; 585 int ret;
628 586