diff options
Diffstat (limited to 'mm/mlock.c')
-rw-r--r-- | mm/mlock.c | 64 |
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 | */ |
300 | long mlock_vma_pages_range(struct vm_area_struct *vma, | 298 | long 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 | ||
532 | asmlinkage long sys_mlock(unsigned long start, size_t len) | 490 | SYSCALL_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 | ||
560 | asmlinkage long sys_munlock(unsigned long start, size_t len) | 518 | SYSCALL_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 | ||
597 | asmlinkage long sys_mlockall(int flags) | 555 | SYSCALL_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 | ||
625 | asmlinkage long sys_munlockall(void) | 583 | SYSCALL_DEFINE0(munlockall) |
626 | { | 584 | { |
627 | int ret; | 585 | int ret; |
628 | 586 | ||