powerpc/mm/book(e)(3s)/64: Add page table accounting
authorBalbir Singh <bsingharora@gmail.com>
Tue, 2 May 2017 05:17:04 +0000 (15:17 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Mon, 5 Jun 2017 09:03:10 +0000 (19:03 +1000)
Introduce a helper pgtable_gfp_flags() which
just returns the current gfp flags and adds
__GFP_ACCOUNT to account for page table allocation.
The generic helper is added to include/asm/pgalloc.h
and has two variants - WARNING ugly bits ahead

1. If the header is included from a module, no check
for mm == &init_mm is done, since init_mm is not
exported
2. For kernel includes, the check is done and required
see (3e79ec7 arch: x86: charge page tables to kmemcg)

The fundamental assumption is that no module should be
doing pgd/pud/pmd and pte alloc's on behalf of init_mm
directly.

NOTE: This adds an overhead to pmd/pud/pgd allocations
similar to x86.  The other alternative was to implement
pmd_alloc_kernel/pud_alloc_kernel and pgd_alloc_kernel
with their offset variants.

For 4k page size, pte_alloc_one no longer calls
pte_alloc_one_kernel.

Signed-off-by: Balbir Singh <bsingharora@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/include/asm/book3s/32/pgalloc.h
arch/powerpc/include/asm/book3s/64/pgalloc.h
arch/powerpc/include/asm/nohash/64/pgalloc.h
arch/powerpc/include/asm/pgalloc.h
arch/powerpc/mm/pgtable_64.c

index d310546e5d9dece35dc46e73a090c21f6b3b0b80..a120e7f8d535a30c7f8d812710b310a60f578ecb 100644 (file)
@@ -31,7 +31,8 @@ extern struct kmem_cache *pgtable_cache[];
 
 static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 {
-       return kmem_cache_alloc(PGT_CACHE(PGD_INDEX_SIZE), GFP_KERNEL);
+       return kmem_cache_alloc(PGT_CACHE(PGD_INDEX_SIZE),
+                       pgtable_gfp_flags(mm, GFP_KERNEL));
 }
 
 static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
index cd5e7aa8cc3489e9f44540e66cafc852bb67d1b7..20b1485ff1e885254b032a2dcbe017fb9566baf2 100644 (file)
@@ -53,10 +53,11 @@ extern void __tlb_remove_table(void *_table);
 static inline pgd_t *radix__pgd_alloc(struct mm_struct *mm)
 {
 #ifdef CONFIG_PPC_64K_PAGES
-       return (pgd_t *)__get_free_page(PGALLOC_GFP);
+       return (pgd_t *)__get_free_page(pgtable_gfp_flags(mm, PGALLOC_GFP));
 #else
        struct page *page;
-       page = alloc_pages(PGALLOC_GFP | __GFP_REPEAT, 4);
+       page = alloc_pages(pgtable_gfp_flags(mm, PGALLOC_GFP | __GFP_REPEAT),
+                               4);
        if (!page)
                return NULL;
        return (pgd_t *) page_address(page);
@@ -76,7 +77,8 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 {
        if (radix_enabled())
                return radix__pgd_alloc(mm);
-       return kmem_cache_alloc(PGT_CACHE(PGD_INDEX_SIZE), GFP_KERNEL);
+       return kmem_cache_alloc(PGT_CACHE(PGD_INDEX_SIZE),
+               pgtable_gfp_flags(mm, GFP_KERNEL));
 }
 
 static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
@@ -93,7 +95,8 @@ static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud)
 
 static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
 {
-       return kmem_cache_alloc(PGT_CACHE(PUD_INDEX_SIZE), GFP_KERNEL);
+       return kmem_cache_alloc(PGT_CACHE(PUD_INDEX_SIZE),
+               pgtable_gfp_flags(mm, GFP_KERNEL));
 }
 
 static inline void pud_free(struct mm_struct *mm, pud_t *pud)
@@ -119,7 +122,8 @@ static inline void __pud_free_tlb(struct mmu_gather *tlb, pud_t *pud,
 
 static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
 {
-       return kmem_cache_alloc(PGT_CACHE(PMD_CACHE_INDEX), GFP_KERNEL);
+       return kmem_cache_alloc(PGT_CACHE(PMD_CACHE_INDEX),
+               pgtable_gfp_flags(mm, GFP_KERNEL));
 }
 
 static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
@@ -168,7 +172,7 @@ static inline pgtable_t pte_alloc_one(struct mm_struct *mm,
        struct page *page;
        pte_t *pte;
 
-       pte = pte_alloc_one_kernel(mm, address);
+       pte = (pte_t *)__get_free_page(GFP_KERNEL | __GFP_ZERO | __GFP_ACCOUNT);
        if (!pte)
                return NULL;
        page = virt_to_page(pte);
index 897d2e1c8a9b84ffa96cc283963e9d322d276ad0..9721c7867b9c5166227e2dc33ed259849f3a41ba 100644 (file)
@@ -43,7 +43,8 @@ extern struct kmem_cache *pgtable_cache[];
 
 static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 {
-       return kmem_cache_alloc(PGT_CACHE(PGD_INDEX_SIZE), GFP_KERNEL);
+       return kmem_cache_alloc(PGT_CACHE(PGD_INDEX_SIZE),
+                       pgtable_gfp_flags(mm, GFP_KERNEL));
 }
 
 static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
@@ -57,7 +58,8 @@ static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 
 static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
 {
-       return kmem_cache_alloc(PGT_CACHE(PUD_INDEX_SIZE), GFP_KERNEL);
+       return kmem_cache_alloc(PGT_CACHE(PUD_INDEX_SIZE),
+                       pgtable_gfp_flags(mm, GFP_KERNEL));
 }
 
 static inline void pud_free(struct mm_struct *mm, pud_t *pud)
@@ -96,7 +98,7 @@ static inline pgtable_t pte_alloc_one(struct mm_struct *mm,
        struct page *page;
        pte_t *pte;
 
-       pte = pte_alloc_one_kernel(mm, address);
+       pte = (pte_t *)__get_free_page(GFP_KERNEL | __GFP_ZERO | __GFP_ACCOUNT);
        if (!pte)
                return NULL;
        page = virt_to_page(pte);
@@ -189,7 +191,8 @@ static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t table,
 
 static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
 {
-       return kmem_cache_alloc(PGT_CACHE(PMD_CACHE_INDEX), GFP_KERNEL);
+       return kmem_cache_alloc(PGT_CACHE(PMD_CACHE_INDEX),
+                       pgtable_gfp_flags(mm, GFP_KERNEL));
 }
 
 static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
index 0413457ba11dc0a08f6d86349a35efb0cae38063..d795c5d5789cfddc584bd1a75c8e71e6e29155cf 100644 (file)
@@ -3,6 +3,20 @@
 
 #include <linux/mm.h>
 
+#ifndef MODULE
+static inline gfp_t pgtable_gfp_flags(struct mm_struct *mm, gfp_t gfp)
+{
+       if (unlikely(mm == &init_mm))
+               return gfp;
+       return gfp | __GFP_ACCOUNT;
+}
+#else /* !MODULE */
+static inline gfp_t pgtable_gfp_flags(struct mm_struct *mm, gfp_t gfp)
+{
+       return gfp | __GFP_ACCOUNT;
+}
+#endif /* MODULE */
+
 #ifdef CONFIG_PPC_BOOK3S
 #include <asm/book3s/pgalloc.h>
 #else
index db93cf747a03826d9dad8223d5735dc4d07cc734..8d2d6742a465158f3764dc74a46ba3bad355bb7f 100644 (file)
@@ -351,12 +351,20 @@ static pte_t *get_from_cache(struct mm_struct *mm)
 static pte_t *__alloc_for_cache(struct mm_struct *mm, int kernel)
 {
        void *ret = NULL;
-       struct page *page = alloc_page(GFP_KERNEL | __GFP_NOTRACK | __GFP_ZERO);
-       if (!page)
-               return NULL;
-       if (!kernel && !pgtable_page_ctor(page)) {
-               __free_page(page);
-               return NULL;
+       struct page *page;
+
+       if (!kernel) {
+               page = alloc_page(PGALLOC_GFP | __GFP_ACCOUNT);
+               if (!page)
+                       return NULL;
+               if (!pgtable_page_ctor(page)) {
+                       __free_page(page);
+                       return NULL;
+               }
+       } else {
+               page = alloc_page(PGALLOC_GFP);
+               if (!page)
+                       return NULL;
        }
 
        ret = page_address(page);