Recently, we found that cross-die access to pagetable pages on ARM64 machines can cause performance fluctuations in our business. Currently, there are no PMU events available to track this situation on our ARM64 machines, so accurate pagetable accounting can help to analyze this issue, but now the PUD level pagetable accounting is missed. So introduce pagetable_pud_ctor/dtor() to help to get accurate PUD pagetable accounting, as well as converting the architectures which use generic PUD pagetable allocation to add corresponding PUD pagetable accounting. Moreover this patch will mark the PUD level pagetable with PG_table flag, which will help to do sanity validation in unpoison_memory(). On my testing machine, I can see more pagetables statistics after the patch with page-types tool: Before patch: flags page-count MB symbolic-flags long-symbolic-flags 0x0000000004000000 27326 106 __________________________g_________________ pgtable After patch: 0x0000000004000000 27541 107 __________________________g_________________ pgtable Link: https://lkml.kernel.org/r/876c71c03a7e69c17722a690e3225a4f7b172fb2.1695017383.git.baolin.wang@linux.alibaba.com Signed-off-by: Baolin Wang <baolin.wang@linux.alibaba.com> Acked-by: Mike Rapoport (IBM) <rppt@kernel.org> Acked-by: Vishal Moola (Oracle) <vishal.moola@gmail.com> Cc: Andy Lutomirski <luto@kernel.org> Cc: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Borislav Petkov <bp@alien8.de> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Dave Hansen <dave.hansen@linux.intel.com> Cc: Huacai Chen <chenhuacai@kernel.org> Cc: Ingo Molnar <mingo@redhat.com> Cc: Matthew Wilcox (Oracle) <willy@infradead.org> Cc: Nicholas Piggin <npiggin@gmail.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Will Deacon <will@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
117 lines
2.5 KiB
C
117 lines
2.5 KiB
C
/*
|
|
* This file is subject to the terms and conditions of the GNU General Public
|
|
* License. See the file "COPYING" in the main directory of this archive
|
|
* for more details.
|
|
*
|
|
* Copyright (C) 1994 - 2001, 2003 by Ralf Baechle
|
|
* Copyright (C) 1999, 2000, 2001 Silicon Graphics, Inc.
|
|
*/
|
|
#ifndef _ASM_PGALLOC_H
|
|
#define _ASM_PGALLOC_H
|
|
|
|
#include <linux/highmem.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/sched.h>
|
|
|
|
#define __HAVE_ARCH_PMD_ALLOC_ONE
|
|
#define __HAVE_ARCH_PUD_ALLOC_ONE
|
|
#define __HAVE_ARCH_PGD_FREE
|
|
#include <asm-generic/pgalloc.h>
|
|
|
|
static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,
|
|
pte_t *pte)
|
|
{
|
|
set_pmd(pmd, __pmd((unsigned long)pte));
|
|
}
|
|
|
|
static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
|
|
pgtable_t pte)
|
|
{
|
|
set_pmd(pmd, __pmd((unsigned long)page_address(pte)));
|
|
}
|
|
|
|
/*
|
|
* Initialize a new pmd table with invalid pointers.
|
|
*/
|
|
extern void pmd_init(void *addr);
|
|
|
|
#ifndef __PAGETABLE_PMD_FOLDED
|
|
|
|
static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
|
|
{
|
|
set_pud(pud, __pud((unsigned long)pmd));
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Initialize a new pgd table with invalid pointers.
|
|
*/
|
|
extern void pgd_init(void *addr);
|
|
extern pgd_t *pgd_alloc(struct mm_struct *mm);
|
|
|
|
static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
|
|
{
|
|
pagetable_free(virt_to_ptdesc(pgd));
|
|
}
|
|
|
|
#define __pte_free_tlb(tlb, pte, address) \
|
|
do { \
|
|
pagetable_pte_dtor(page_ptdesc(pte)); \
|
|
tlb_remove_page_ptdesc((tlb), page_ptdesc(pte)); \
|
|
} while (0)
|
|
|
|
#ifndef __PAGETABLE_PMD_FOLDED
|
|
|
|
static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
|
|
{
|
|
pmd_t *pmd;
|
|
struct ptdesc *ptdesc;
|
|
|
|
ptdesc = pagetable_alloc(GFP_KERNEL_ACCOUNT, PMD_TABLE_ORDER);
|
|
if (!ptdesc)
|
|
return NULL;
|
|
|
|
if (!pagetable_pmd_ctor(ptdesc)) {
|
|
pagetable_free(ptdesc);
|
|
return NULL;
|
|
}
|
|
|
|
pmd = ptdesc_address(ptdesc);
|
|
pmd_init(pmd);
|
|
return pmd;
|
|
}
|
|
|
|
#define __pmd_free_tlb(tlb, x, addr) pmd_free((tlb)->mm, x)
|
|
|
|
#endif
|
|
|
|
#ifndef __PAGETABLE_PUD_FOLDED
|
|
|
|
static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address)
|
|
{
|
|
pud_t *pud;
|
|
struct ptdesc *ptdesc = pagetable_alloc(GFP_KERNEL & ~__GFP_HIGHMEM,
|
|
PUD_TABLE_ORDER);
|
|
|
|
if (!ptdesc)
|
|
return NULL;
|
|
pagetable_pud_ctor(ptdesc);
|
|
pud = ptdesc_address(ptdesc);
|
|
|
|
pud_init(pud);
|
|
return pud;
|
|
}
|
|
|
|
static inline void p4d_populate(struct mm_struct *mm, p4d_t *p4d, pud_t *pud)
|
|
{
|
|
set_p4d(p4d, __p4d((unsigned long)pud));
|
|
}
|
|
|
|
#define __pud_free_tlb(tlb, x, addr) pud_free((tlb)->mm, x)
|
|
|
|
#endif /* __PAGETABLE_PUD_FOLDED */
|
|
|
|
extern void pagetable_init(void);
|
|
|
|
#endif /* _ASM_PGALLOC_H */
|