memcg: fix vmscan count in small memcgs
[linux-2.6.git] / mm / mincore.c
index 211604a..a4e6b9d 100644 (file)
@@ -144,6 +144,67 @@ static void mincore_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
        pte_unmap_unlock(ptep - 1, ptl);
 }
 
+static void mincore_pmd_range(struct vm_area_struct *vma, pud_t *pud,
+                       unsigned long addr, unsigned long end,
+                       unsigned char *vec)
+{
+       unsigned long next;
+       pmd_t *pmd;
+
+       pmd = pmd_offset(pud, addr);
+       do {
+               next = pmd_addr_end(addr, end);
+               if (pmd_trans_huge(*pmd)) {
+                       if (mincore_huge_pmd(vma, pmd, addr, next, vec)) {
+                               vec += (next - addr) >> PAGE_SHIFT;
+                               continue;
+                       }
+                       /* fall through */
+               }
+               if (pmd_none_or_clear_bad(pmd))
+                       mincore_unmapped_range(vma, addr, next, vec);
+               else
+                       mincore_pte_range(vma, pmd, addr, next, vec);
+               vec += (next - addr) >> PAGE_SHIFT;
+       } while (pmd++, addr = next, addr != end);
+}
+
+static void mincore_pud_range(struct vm_area_struct *vma, pgd_t *pgd,
+                       unsigned long addr, unsigned long end,
+                       unsigned char *vec)
+{
+       unsigned long next;
+       pud_t *pud;
+
+       pud = pud_offset(pgd, addr);
+       do {
+               next = pud_addr_end(addr, end);
+               if (pud_none_or_clear_bad(pud))
+                       mincore_unmapped_range(vma, addr, next, vec);
+               else
+                       mincore_pmd_range(vma, pud, addr, next, vec);
+               vec += (next - addr) >> PAGE_SHIFT;
+       } while (pud++, addr = next, addr != end);
+}
+
+static void mincore_page_range(struct vm_area_struct *vma,
+                       unsigned long addr, unsigned long end,
+                       unsigned char *vec)
+{
+       unsigned long next;
+       pgd_t *pgd;
+
+       pgd = pgd_offset(vma->vm_mm, addr);
+       do {
+               next = pgd_addr_end(addr, end);
+               if (pgd_none_or_clear_bad(pgd))
+                       mincore_unmapped_range(vma, addr, next, vec);
+               else
+                       mincore_pud_range(vma, pgd, addr, next, vec);
+               vec += (next - addr) >> PAGE_SHIFT;
+       } while (pgd++, addr = next, addr != end);
+}
+
 /*
  * Do a chunk of "sys_mincore()". We've already checked
  * all the arguments, we hold the mmap semaphore: we should
@@ -151,9 +212,6 @@ static void mincore_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
  */
 static long do_mincore(unsigned long addr, unsigned long pages, unsigned char *vec)
 {
-       pgd_t *pgd;
-       pud_t *pud;
-       pmd_t *pmd;
        struct vm_area_struct *vma;
        unsigned long end;
 
@@ -170,21 +228,11 @@ static long do_mincore(unsigned long addr, unsigned long pages, unsigned char *v
 
        end = pmd_addr_end(addr, end);
 
-       pgd = pgd_offset(vma->vm_mm, addr);
-       if (pgd_none_or_clear_bad(pgd))
-               goto none_mapped;
-       pud = pud_offset(pgd, addr);
-       if (pud_none_or_clear_bad(pud))
-               goto none_mapped;
-       pmd = pmd_offset(pud, addr);
-       if (pmd_none_or_clear_bad(pmd))
-               goto none_mapped;
-
-       mincore_pte_range(vma, pmd, addr, end, vec);
-       return (end - addr) >> PAGE_SHIFT;
+       if (is_vm_hugetlb_page(vma))
+               mincore_hugetlb_page_range(vma, addr, end, vec);
+       else
+               mincore_page_range(vma, addr, end, vec);
 
-none_mapped:
-       mincore_unmapped_range(vma, addr, end, vec);
        return (end - addr) >> PAGE_SHIFT;
 }