X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=mm%2Fmadvise.c;h=944b5e52d812f051fb2bffaed33a4288ba4c920e;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=81c4ea30c75e60b9001127697045d000ae075fd1;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/mm/madvise.c b/mm/madvise.c index 81c4ea30c..944b5e52d 100644 --- a/mm/madvise.c +++ b/mm/madvise.c @@ -7,7 +7,8 @@ #include #include - +#include +#include /* * We can potentially split a vm area into separate @@ -17,21 +18,23 @@ static long madvise_behavior(struct vm_area_struct * vma, unsigned long start, unsigned long end, int behavior) { struct mm_struct * mm = vma->vm_mm; - int error; + int error = 0; if (start != vma->vm_start) { error = split_vma(mm, vma, start, 1); if (error) - return -EAGAIN; + goto out; } if (end != vma->vm_end) { error = split_vma(mm, vma, end, 0); if (error) - return -EAGAIN; + goto out; } - spin_lock(&mm->page_table_lock); + /* + * vm_flags is protected by the mmap_sem held in write mode. + */ VM_ClearReadHint(vma); switch (behavior) { @@ -44,9 +47,11 @@ static long madvise_behavior(struct vm_area_struct * vma, unsigned long start, default: break; } - spin_unlock(&mm->page_table_lock); - return 0; +out: + if (error == -ENOMEM) + error = -EAGAIN; + return error; } /* @@ -92,16 +97,14 @@ static long madvise_willneed(struct vm_area_struct * vma, static long madvise_dontneed(struct vm_area_struct * vma, unsigned long start, unsigned long end) { - struct zap_details details; - - if (vma->vm_flags & VM_LOCKED) + if ((vma->vm_flags & VM_LOCKED) || is_vm_hugetlb_page(vma)) return -EINVAL; if (unlikely(vma->vm_flags & VM_NONLINEAR)) { - details.check_mapping = NULL; - details.nonlinear_vma = vma; - details.first_index = 0; - details.last_index = ULONG_MAX; + struct zap_details details = { + .nonlinear_vma = vma, + .last_index = ULONG_MAX, + }; zap_page_range(vma, start, end - start, &details); } else zap_page_range(vma, start, end - start, NULL); @@ -170,18 +173,24 @@ static long madvise_vma(struct vm_area_struct * vma, unsigned long start, * -EBADF - map exists, but area maps something that isn't a file. * -EAGAIN - a kernel resource was temporarily unavailable. */ -asmlinkage long sys_madvise(unsigned long start, size_t len, int behavior) +asmlinkage long sys_madvise(unsigned long start, size_t len_in, int behavior) { unsigned long end; struct vm_area_struct * vma; int unmapped_error = 0; int error = -EINVAL; + size_t len; down_write(¤t->mm->mmap_sem); if (start & ~PAGE_MASK) goto out; - len = (len + ~PAGE_MASK) & PAGE_MASK; + len = (len_in + ~PAGE_MASK) & PAGE_MASK; + + /* Check to see whether len was rounded up from small -ve to zero */ + if (len_in && !len) + goto out; + end = start + len; if (end < start) goto out;