Pull ec into release branch
[pandora-kernel.git] / mm / madvise.c
index 4e19615..603c525 100644 (file)
@@ -155,10 +155,14 @@ static long madvise_dontneed(struct vm_area_struct * vma,
  * Other filesystems return -ENOSYS.
  */
 static long madvise_remove(struct vm_area_struct *vma,
+                               struct vm_area_struct **prev,
                                unsigned long start, unsigned long end)
 {
        struct address_space *mapping;
-        loff_t offset, endoff;
+       loff_t offset, endoff;
+       int error;
+
+       *prev = NULL;   /* tell sys_madvise we drop mmap_sem */
 
        if (vma->vm_flags & (VM_LOCKED|VM_NONLINEAR|VM_HUGETLB))
                return -EINVAL;
@@ -177,7 +181,12 @@ static long madvise_remove(struct vm_area_struct *vma,
                        + ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
        endoff = (loff_t)(end - vma->vm_start - 1)
                        + ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
-       return  vmtruncate_range(mapping->host, offset, endoff);
+
+       /* vmtruncate_range needs to take i_mutex and i_alloc_sem */
+       up_write(&current->mm->mmap_sem);
+       error = vmtruncate_range(mapping->host, offset, endoff);
+       down_write(&current->mm->mmap_sem);
+       return error;
 }
 
 static long
@@ -199,7 +208,7 @@ madvise_vma(struct vm_area_struct *vma, struct vm_area_struct **prev,
                error = madvise_behavior(vma, prev, start, end, behavior);
                break;
        case MADV_REMOVE:
-               error = madvise_remove(vma, start, end);
+               error = madvise_remove(vma, prev, start, end);
                break;
 
        case MADV_WILLNEED:
@@ -312,12 +321,15 @@ asmlinkage long sys_madvise(unsigned long start, size_t len_in, int behavior)
                if (error)
                        goto out;
                start = tmp;
-               if (start < prev->vm_end)
+               if (prev && start < prev->vm_end)
                        start = prev->vm_end;
                error = unmapped_error;
                if (start >= end)
                        goto out;
-               vma = prev->vm_next;
+               if (prev)
+                       vma = prev->vm_next;
+               else    /* madvise_remove dropped mmap_sem */
+                       vma = find_vma(current->mm, start);
        }
 out:
        up_write(&current->mm->mmap_sem);