diff options
Diffstat (limited to 'mm/mlock.c')
-rw-r--r-- | mm/mlock.c | 56 |
1 files changed, 8 insertions, 48 deletions
diff --git a/mm/mlock.c b/mm/mlock.c index e125156c664e..037161d61b4e 100644 --- a/mm/mlock.c +++ b/mm/mlock.c | |||
@@ -294,14 +294,10 @@ static inline int __mlock_posix_error_return(long retval) | |||
294 | * | 294 | * |
295 | * 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 |
296 | * of "special" vmas. | 296 | * of "special" vmas. |
297 | * | ||
298 | * return negative error if vma spanning @start-@range disappears while | ||
299 | * mmap semaphore is dropped. Unlikely? | ||
300 | */ | 297 | */ |
301 | long mlock_vma_pages_range(struct vm_area_struct *vma, | 298 | long mlock_vma_pages_range(struct vm_area_struct *vma, |
302 | unsigned long start, unsigned long end) | 299 | unsigned long start, unsigned long end) |
303 | { | 300 | { |
304 | struct mm_struct *mm = vma->vm_mm; | ||
305 | int nr_pages = (end - start) / PAGE_SIZE; | 301 | int nr_pages = (end - start) / PAGE_SIZE; |
306 | BUG_ON(!(vma->vm_flags & VM_LOCKED)); | 302 | BUG_ON(!(vma->vm_flags & VM_LOCKED)); |
307 | 303 | ||
@@ -314,20 +310,11 @@ long mlock_vma_pages_range(struct vm_area_struct *vma, | |||
314 | if (!((vma->vm_flags & (VM_DONTEXPAND | VM_RESERVED)) || | 310 | if (!((vma->vm_flags & (VM_DONTEXPAND | VM_RESERVED)) || |
315 | is_vm_hugetlb_page(vma) || | 311 | is_vm_hugetlb_page(vma) || |
316 | vma == get_gate_vma(current))) { | 312 | vma == get_gate_vma(current))) { |
317 | long error; | ||
318 | downgrade_write(&mm->mmap_sem); | ||
319 | |||
320 | error = __mlock_vma_pages_range(vma, start, end, 1); | ||
321 | 313 | ||
322 | up_read(&mm->mmap_sem); | 314 | __mlock_vma_pages_range(vma, start, end, 1); |
323 | /* vma can change or disappear */ | ||
324 | down_write(&mm->mmap_sem); | ||
325 | vma = find_vma(mm, start); | ||
326 | /* non-NULL vma must contain @start, but need to check @end */ | ||
327 | if (!vma || end > vma->vm_end) | ||
328 | return -ENOMEM; | ||
329 | 315 | ||
330 | return 0; /* hide other errors from mmap(), et al */ | 316 | /* Hide errors from mmap() and other callers */ |
317 | return 0; | ||
331 | } | 318 | } |
332 | 319 | ||
333 | /* | 320 | /* |
@@ -438,41 +425,14 @@ success: | |||
438 | vma->vm_flags = newflags; | 425 | vma->vm_flags = newflags; |
439 | 426 | ||
440 | if (lock) { | 427 | if (lock) { |
441 | /* | ||
442 | * mmap_sem is currently held for write. Downgrade the write | ||
443 | * lock to a read lock so that other faults, mmap scans, ... | ||
444 | * while we fault in all pages. | ||
445 | */ | ||
446 | downgrade_write(&mm->mmap_sem); | ||
447 | |||
448 | ret = __mlock_vma_pages_range(vma, start, end, 1); | 428 | ret = __mlock_vma_pages_range(vma, start, end, 1); |
449 | 429 | ||
450 | /* | 430 | if (ret > 0) { |
451 | * Need to reacquire mmap sem in write mode, as our callers | ||
452 | * expect this. We have no support for atomically upgrading | ||
453 | * a sem to write, so we need to check for ranges while sem | ||
454 | * is unlocked. | ||
455 | */ | ||
456 | up_read(&mm->mmap_sem); | ||
457 | /* vma can change or disappear */ | ||
458 | down_write(&mm->mmap_sem); | ||
459 | *prev = find_vma(mm, start); | ||
460 | /* non-NULL *prev must contain @start, but need to check @end */ | ||
461 | if (!(*prev) || end > (*prev)->vm_end) | ||
462 | ret = -ENOMEM; | ||
463 | else if (ret > 0) { | ||
464 | mm->locked_vm -= ret; | 431 | mm->locked_vm -= ret; |
465 | ret = 0; | 432 | ret = 0; |
466 | } else | 433 | } else |
467 | ret = __mlock_posix_error_return(ret); /* translate if needed */ | 434 | ret = __mlock_posix_error_return(ret); /* translate if needed */ |
468 | } else { | 435 | } else { |
469 | /* | ||
470 | * TODO: for unlocking, pages will already be resident, so | ||
471 | * we don't need to wait for allocations/reclaim/pagein, ... | ||
472 | * However, unlocking a very large region can still take a | ||
473 | * while. Should we downgrade the semaphore for both lock | ||
474 | * AND unlock ? | ||
475 | */ | ||
476 | __mlock_vma_pages_range(vma, start, end, 0); | 436 | __mlock_vma_pages_range(vma, start, end, 0); |
477 | } | 437 | } |
478 | 438 | ||
@@ -530,7 +490,7 @@ static int do_mlock(unsigned long start, size_t len, int on) | |||
530 | return error; | 490 | return error; |
531 | } | 491 | } |
532 | 492 | ||
533 | asmlinkage long sys_mlock(unsigned long start, size_t len) | 493 | SYSCALL_DEFINE2(mlock, unsigned long, start, size_t, len) |
534 | { | 494 | { |
535 | unsigned long locked; | 495 | unsigned long locked; |
536 | unsigned long lock_limit; | 496 | unsigned long lock_limit; |
@@ -558,7 +518,7 @@ asmlinkage long sys_mlock(unsigned long start, size_t len) | |||
558 | return error; | 518 | return error; |
559 | } | 519 | } |
560 | 520 | ||
561 | asmlinkage long sys_munlock(unsigned long start, size_t len) | 521 | SYSCALL_DEFINE2(munlock, unsigned long, start, size_t, len) |
562 | { | 522 | { |
563 | int ret; | 523 | int ret; |
564 | 524 | ||
@@ -595,7 +555,7 @@ out: | |||
595 | return 0; | 555 | return 0; |
596 | } | 556 | } |
597 | 557 | ||
598 | asmlinkage long sys_mlockall(int flags) | 558 | SYSCALL_DEFINE1(mlockall, int, flags) |
599 | { | 559 | { |
600 | unsigned long lock_limit; | 560 | unsigned long lock_limit; |
601 | int ret = -EINVAL; | 561 | int ret = -EINVAL; |
@@ -623,7 +583,7 @@ out: | |||
623 | return ret; | 583 | return ret; |
624 | } | 584 | } |
625 | 585 | ||
626 | asmlinkage long sys_munlockall(void) | 586 | SYSCALL_DEFINE0(munlockall) |
627 | { | 587 | { |
628 | int ret; | 588 | int ret; |
629 | 589 | ||