memcg: fix vmscan count in small memcgs
[linux-2.6.git] / mm / mremap.c
index b09eefa..506fa44 100644 (file)
@@ -41,6 +41,7 @@ static pmd_t *get_old_pmd(struct mm_struct *mm, unsigned long addr)
                return NULL;
 
        pmd = pmd_offset(pud, addr);
+       split_huge_page_pmd(mm, pmd);
        if (pmd_none_or_clear_bad(pmd))
                return NULL;
 
@@ -92,10 +93,7 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd,
                 * and we propagate stale pages into the dst afterward.
                 */
                mapping = vma->vm_file->f_mapping;
-               spin_lock(&mapping->i_mmap_lock);
-               if (new_vma->vm_truncate_count &&
-                   new_vma->vm_truncate_count != vma->vm_truncate_count)
-                       new_vma->vm_truncate_count = 0;
+               mutex_lock(&mapping->i_mmap_mutex);
        }
 
        /*
@@ -124,7 +122,7 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd,
        pte_unmap(new_pte - 1);
        pte_unmap_unlock(old_pte - 1, old_ptl);
        if (mapping)
-               spin_unlock(&mapping->i_mmap_lock);
+               mutex_unlock(&mapping->i_mmap_mutex);
        mmu_notifier_invalidate_range_end(vma->vm_mm, old_start, old_end);
 }
 
@@ -278,9 +276,16 @@ static struct vm_area_struct *vma_to_resize(unsigned long addr,
        if (old_len > vma->vm_end - addr)
                goto Efault;
 
-       if (vma->vm_flags & (VM_DONTEXPAND | VM_PFNMAP)) {
-               if (new_len > old_len)
+       /* Need to be careful about a growing mapping */
+       if (new_len > old_len) {
+               unsigned long pgoff;
+
+               if (vma->vm_flags & (VM_DONTEXPAND | VM_PFNMAP))
                        goto Efault;
+               pgoff = (addr - vma->vm_start) >> PAGE_SHIFT;
+               pgoff += vma->vm_pgoff;
+               if (pgoff + (new_len >> PAGE_SHIFT) < pgoff)
+                       goto Einval;
        }
 
        if (vma->vm_flags & VM_LOCKED) {