X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=mm%2Fmlock.c;h=ed63dcb8f11f16327f075c6252ead409cf8e73be;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=16b3bf844bf7050161355a3891db81a64c947ad1;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/mm/mlock.c b/mm/mlock.c index 16b3bf844..ed63dcb8f 100644 --- a/mm/mlock.c +++ b/mm/mlock.c @@ -5,35 +5,50 @@ * (C) Copyright 2002 Christoph Hellwig */ +#include #include #include +#include +#include #include -static int mlock_fixup(struct vm_area_struct * vma, +static int mlock_fixup(struct vm_area_struct *vma, struct vm_area_struct **prev, unsigned long start, unsigned long end, unsigned int newflags) { struct mm_struct * mm = vma->vm_mm; + pgoff_t pgoff; int pages; int ret = 0; - if (newflags == vma->vm_flags) + if (newflags == vma->vm_flags) { + *prev = vma; goto out; + } + + pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT); + *prev = vma_merge(mm, *prev, start, end, newflags, vma->anon_vma, + vma->vm_file, pgoff, vma_policy(vma)); + if (*prev) { + vma = *prev; + goto success; + } + + *prev = vma; if (start != vma->vm_start) { - if (split_vma(mm, vma, start, 1)) { - ret = -EAGAIN; + ret = split_vma(mm, vma, start, 1); + if (ret) goto out; - } } if (end != vma->vm_end) { - if (split_vma(mm, vma, end, 0)) { - ret = -EAGAIN; + ret = split_vma(mm, vma, end, 0); + if (ret) goto out; - } } +success: /* * vm_flags is protected by the mmap_sem held in write mode. * It's okay if try_to_unmap_one unmaps a page just after we @@ -47,19 +62,21 @@ static int mlock_fixup(struct vm_area_struct * vma, pages = (end - start) >> PAGE_SHIFT; if (newflags & VM_LOCKED) { pages = -pages; - ret = make_pages_present(start, end); + if (!(newflags & VM_IO)) + ret = make_pages_present(start, end); } - // vma->vm_mm->locked_vm -= pages; - vx_vmlocked_sub(vma->vm_mm, pages); + vx_vmlocked_sub(mm, pages); out: + if (ret == -ENOMEM) + ret = -EAGAIN; return ret; } static int do_mlock(unsigned long start, size_t len, int on) { unsigned long nstart, end, tmp; - struct vm_area_struct * vma, * next; + struct vm_area_struct * vma, * prev; int error; len = PAGE_ALIGN(len); @@ -68,10 +85,13 @@ static int do_mlock(unsigned long start, size_t len, int on) return -EINVAL; if (end == start) return 0; - vma = find_vma(current->mm, start); + vma = find_vma_prev(current->mm, start, &prev); if (!vma || vma->vm_start > start) return -ENOMEM; + if (start > vma->vm_start) + prev = vma; + for (nstart = start ; ; ) { unsigned int newflags; @@ -81,18 +101,19 @@ static int do_mlock(unsigned long start, size_t len, int on) if (!on) newflags &= ~VM_LOCKED; - if (vma->vm_end >= end) { - error = mlock_fixup(vma, nstart, end, newflags); - break; - } - tmp = vma->vm_end; - next = vma->vm_next; - error = mlock_fixup(vma, nstart, tmp, newflags); + if (tmp > end) + tmp = end; + error = mlock_fixup(vma, &prev, nstart, tmp, newflags); if (error) break; nstart = tmp; - vma = next; + if (nstart < prev->vm_end) + nstart = prev->vm_end; + if (nstart >= end) + break; + + vma = prev->vm_next; if (!vma || vma->vm_start != nstart) { error = -ENOMEM; break; @@ -119,7 +140,7 @@ asmlinkage long sys_mlock(unsigned long start, size_t len) goto out; locked = current->mm->locked_vm + grow; - lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur; + lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur; lock_limit >>= PAGE_SHIFT; /* check against resource limits */ @@ -144,7 +165,7 @@ asmlinkage long sys_munlock(unsigned long start, size_t len) static int do_mlockall(int flags) { - struct vm_area_struct * vma; + struct vm_area_struct * vma, * prev = NULL; unsigned int def_flags = 0; if (flags & MCL_FUTURE) @@ -153,7 +174,7 @@ static int do_mlockall(int flags) if (flags == MCL_FUTURE) goto out; - for (vma = current->mm->mmap; vma ; vma = vma->vm_next) { + for (vma = current->mm->mmap; vma ; vma = prev->vm_next) { unsigned int newflags; newflags = vma->vm_flags | VM_LOCKED; @@ -161,7 +182,7 @@ static int do_mlockall(int flags) newflags &= ~VM_LOCKED; /* Ignore errors */ - mlock_fixup(vma, vma->vm_start, vma->vm_end, newflags); + mlock_fixup(vma, &prev, vma->vm_start, vma->vm_end, newflags); } out: return 0; @@ -181,7 +202,7 @@ asmlinkage long sys_mlockall(int flags) down_write(¤t->mm->mmap_sem); - lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur; + lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur; lock_limit >>= PAGE_SHIFT; ret = -ENOMEM; @@ -209,17 +230,17 @@ asmlinkage long sys_munlockall(void) * Objects with different lifetime than processes (SHM_LOCK and SHM_HUGETLB * shm segments) get accounted against the user_struct instead. */ -static spinlock_t shmlock_user_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(shmlock_user_lock); int user_shm_lock(size_t size, struct user_struct *user) { unsigned long lock_limit, locked; int allowed = 0; - spin_lock(&shmlock_user_lock); - locked = size >> PAGE_SHIFT; - lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur; + locked = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; + lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur; lock_limit >>= PAGE_SHIFT; + spin_lock(&shmlock_user_lock); if (locked + user->locked_shm > lock_limit && !capable(CAP_IPC_LOCK)) goto out; get_uid(user); @@ -233,7 +254,7 @@ out: void user_shm_unlock(size_t size, struct user_struct *user) { spin_lock(&shmlock_user_lock); - user->locked_shm -= (size >> PAGE_SHIFT); + user->locked_shm -= (size + PAGE_SIZE - 1) >> PAGE_SHIFT; spin_unlock(&shmlock_user_lock); free_uid(user); }