X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=mm%2Fmadvise.c;h=0439c560e0b4ceb474c4e981aa71ddaa2708f77b;hb=d939d46ba7caa14e960be18e18f5c07be8806d7a;hp=81c4ea30c75e60b9001127697045d000ae075fd1;hpb=86090fcac5e27b630656fe3d963a6b80e26dac44;p=linux-2.6.git diff --git a/mm/madvise.c b/mm/madvise.c index 81c4ea30c..0439c560e 100644 --- a/mm/madvise.c +++ b/mm/madvise.c @@ -31,7 +31,9 @@ static long madvise_behavior(struct vm_area_struct * vma, unsigned long start, return -EAGAIN; } - spin_lock(&mm->page_table_lock); + /* + * vm_flags is protected by the mmap_sem held in write mode. + */ VM_ClearReadHint(vma); switch (behavior) { @@ -44,7 +46,6 @@ static long madvise_behavior(struct vm_area_struct * vma, unsigned long start, default: break; } - spin_unlock(&mm->page_table_lock); return 0; } @@ -92,16 +93,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) 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 +169,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;