vserver 1.9.5.x5
[linux-2.6.git] / mm / madvise.c
index 81c4ea3..944b5e5 100644 (file)
@@ -7,7 +7,8 @@
 
 #include <linux/mman.h>
 #include <linux/pagemap.h>
-
+#include <linux/syscalls.h>
+#include <linux/hugetlb.h>
 
 /*
  * 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(&current->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;