Message ID | 20200515140023.25469-2-joro@8bytes.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | mm: Get rid of vmalloc_sync_(un)mappings() | expand |
Hi Joerg, On Fri, May 15, 2020 at 04:00:17PM +0200, Joerg Roedel wrote: > diff --git a/include/linux/mm.h b/include/linux/mm.h > index 5a323422d783..022fe682af9e 100644 > --- a/include/linux/mm.h > +++ b/include/linux/mm.h > @@ -2078,13 +2078,54 @@ static inline pud_t *pud_alloc(struct mm_struct *mm, p4d_t *p4d, > return (unlikely(p4d_none(*p4d)) && __pud_alloc(mm, p4d, address)) ? > NULL : pud_offset(p4d, address); > } > + > +static inline p4d_t *p4d_alloc_track(struct mm_struct *mm, pgd_t *pgd, > + unsigned long address, > + pgtbl_mod_mask *mod_mask) > + > +{ > + if (unlikely(pgd_none(*pgd))) { > + if (__p4d_alloc(mm, pgd, address)) > + return NULL; > + *mod_mask |= PGTBL_PGD_MODIFIED; > + } > + > + return p4d_offset(pgd, address); > +} > + > #endif /* !__ARCH_HAS_5LEVEL_HACK */ > > +static inline pud_t *pud_alloc_track(struct mm_struct *mm, p4d_t *p4d, > + unsigned long address, > + pgtbl_mod_mask *mod_mask) > +{ > + if (unlikely(p4d_none(*p4d))) { > + if (__pud_alloc(mm, p4d, address)) > + return NULL; > + *mod_mask |= PGTBL_P4D_MODIFIED; > + } > + > + return pud_offset(p4d, address); > +} This patch causes a kernel panic on arm64 (and possibly powerpc, I haven't tried). arm64 still uses the 5level-fixup.h and pud_alloc() checks for the empty p4d with pgd_none() instead of p4d_none(). The patch below fixes it: -----------------------8<----------------------------------- From 8fb5f4c1e0983bb501c8ec71f9bb9dd344b80e87 Mon Sep 17 00:00:00 2001 From: Catalin Marinas <catalin.marinas@arm.com> Date: Fri, 5 Jun 2020 10:56:03 +0100 Subject: [PATCH] mm: Use pgd_none() in pud_alloc_track() with __ARCH_HAS_5LEVEL_HACK Commit d8626138009b ("mm: add functions to track page directory modifications") introduced the pud_alloc_track() function checking for an empty p4d using p4d_none(). However, when __ARCH_HAS_5LEVEL_HACK is defined, the pud_alloc() counterpart checks for an empty p4d using pgd_none(). Since p4d_none() is always 0 in this case, no pud would be allocated and the kernel panics during boot on arm64 (at least). Until all architectures are moved away from the 5level-fixup.h, define a pud_alloc_track() that matches the __ARCH_HAS_5LEVEL_HACK pud_alloc(). Fixes: d8626138009b ("mm: add functions to track page directory modifications") Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> Cc: Joerg Roedel <jroedel@suse.de> Cc: Andrew Morton <akpm@linux-foundation.org> --- include/linux/mm.h | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index fda41eb7f1c8..9d3761a1fad5 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -2106,8 +2106,6 @@ static inline p4d_t *p4d_alloc_track(struct mm_struct *mm, pgd_t *pgd, return p4d_offset(pgd, address); } -#endif /* !__ARCH_HAS_5LEVEL_HACK */ - static inline pud_t *pud_alloc_track(struct mm_struct *mm, p4d_t *p4d, unsigned long address, pgtbl_mod_mask *mod_mask) @@ -2121,6 +2119,23 @@ static inline pud_t *pud_alloc_track(struct mm_struct *mm, p4d_t *p4d, return pud_offset(p4d, address); } +#else /* __ARCH_HAS_5LEVEL_HACK */ + +static inline pud_t *pud_alloc_track(struct mm_struct *mm, p4d_t *p4d, + unsigned long address, + pgtbl_mod_mask *mod_mask) +{ + if (unlikely(pgd_none(*p4d))) { + if (__pud_alloc(mm, p4d, address)) + return NULL; + *mod_mask |= PGTBL_P4D_MODIFIED; + } + + return pud_offset(p4d, address); +} + +#endif /* !__ARCH_HAS_5LEVEL_HACK */ + static inline pmd_t *pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address) { return (unlikely(pud_none(*pud)) && __pmd_alloc(mm, pud, address))?
On Fri, Jun 05, 2020 at 11:08:13AM +0100, Catalin Marinas wrote: > This patch causes a kernel panic on arm64 (and possibly powerpc, I > haven't tried). arm64 still uses the 5level-fixup.h and pud_alloc() > checks for the empty p4d with pgd_none() instead of p4d_none(). Ah, should have checked the list first (https://lore.kernel.org/linux-mm/20200604074446.23944-1-joro@8bytes.org/). Please ignore my patch then.
On Fri, 5 Jun 2020 12:46:55 +0100 Catalin Marinas <catalin.marinas@arm.com> wrote: > On Fri, Jun 05, 2020 at 11:08:13AM +0100, Catalin Marinas wrote: > > This patch causes a kernel panic on arm64 (and possibly powerpc, I > > haven't tried). arm64 still uses the 5level-fixup.h and pud_alloc() > > checks for the empty p4d with pgd_none() instead of p4d_none(). > > Ah, should have checked the list first > (https://lore.kernel.org/linux-mm/20200604074446.23944-1-joro@8bytes.org/). > Sorry about that. Can you confirm that the merge of Mike's 5level_hack zappage has fixed the arm64 wontboot?
On Fri, Jun 05, 2020 at 06:01:16PM -0700, Andrew Morton wrote: > On Fri, 5 Jun 2020 12:46:55 +0100 Catalin Marinas <catalin.marinas@arm.com> wrote: > > On Fri, Jun 05, 2020 at 11:08:13AM +0100, Catalin Marinas wrote: > > > This patch causes a kernel panic on arm64 (and possibly powerpc, I > > > haven't tried). arm64 still uses the 5level-fixup.h and pud_alloc() > > > checks for the empty p4d with pgd_none() instead of p4d_none(). > > > > Ah, should have checked the list first > > (https://lore.kernel.org/linux-mm/20200604074446.23944-1-joro@8bytes.org/). > > Can you confirm that the merge of Mike's 5level_hack zappage has fixed > the arm64 wontboot? Yes, it has. Mainline is booting again on arm64. Thanks.
diff --git a/include/asm-generic/5level-fixup.h b/include/asm-generic/5level-fixup.h index 4c74b1c1d13b..58046ddc08d0 100644 --- a/include/asm-generic/5level-fixup.h +++ b/include/asm-generic/5level-fixup.h @@ -17,8 +17,9 @@ ((unlikely(pgd_none(*(p4d))) && __pud_alloc(mm, p4d, address)) ? \ NULL : pud_offset(p4d, address)) -#define p4d_alloc(mm, pgd, address) (pgd) -#define p4d_offset(pgd, start) (pgd) +#define p4d_alloc(mm, pgd, address) (pgd) +#define p4d_alloc_track(mm, pgd, address, mask) (pgd) +#define p4d_offset(pgd, start) (pgd) #ifndef __ASSEMBLY__ static inline int p4d_none(p4d_t p4d) diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h index 329b8c8ca703..bf1418ae91a2 100644 --- a/include/asm-generic/pgtable.h +++ b/include/asm-generic/pgtable.h @@ -1209,6 +1209,29 @@ static inline bool arch_has_pfn_modify_check(void) # define PAGE_KERNEL_EXEC PAGE_KERNEL #endif +/* + * Page Table Modification bits for pgtbl_mod_mask. + * + * These are used by the p?d_alloc_track*() set of functions an in the generic + * vmalloc/ioremap code to track at which page-table levels entries have been + * modified. Based on that the code can better decide when vmalloc and ioremap + * mapping changes need to be synchronized to other page-tables in the system. + */ +#define __PGTBL_PGD_MODIFIED 0 +#define __PGTBL_P4D_MODIFIED 1 +#define __PGTBL_PUD_MODIFIED 2 +#define __PGTBL_PMD_MODIFIED 3 +#define __PGTBL_PTE_MODIFIED 4 + +#define PGTBL_PGD_MODIFIED BIT(__PGTBL_PGD_MODIFIED) +#define PGTBL_P4D_MODIFIED BIT(__PGTBL_P4D_MODIFIED) +#define PGTBL_PUD_MODIFIED BIT(__PGTBL_PUD_MODIFIED) +#define PGTBL_PMD_MODIFIED BIT(__PGTBL_PMD_MODIFIED) +#define PGTBL_PTE_MODIFIED BIT(__PGTBL_PTE_MODIFIED) + +/* Page-Table Modification Mask */ +typedef unsigned int pgtbl_mod_mask; + #endif /* !__ASSEMBLY__ */ #ifndef io_remap_pfn_range diff --git a/include/linux/mm.h b/include/linux/mm.h index 5a323422d783..022fe682af9e 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -2078,13 +2078,54 @@ static inline pud_t *pud_alloc(struct mm_struct *mm, p4d_t *p4d, return (unlikely(p4d_none(*p4d)) && __pud_alloc(mm, p4d, address)) ? NULL : pud_offset(p4d, address); } + +static inline p4d_t *p4d_alloc_track(struct mm_struct *mm, pgd_t *pgd, + unsigned long address, + pgtbl_mod_mask *mod_mask) + +{ + if (unlikely(pgd_none(*pgd))) { + if (__p4d_alloc(mm, pgd, address)) + return NULL; + *mod_mask |= PGTBL_PGD_MODIFIED; + } + + return p4d_offset(pgd, address); +} + #endif /* !__ARCH_HAS_5LEVEL_HACK */ +static inline pud_t *pud_alloc_track(struct mm_struct *mm, p4d_t *p4d, + unsigned long address, + pgtbl_mod_mask *mod_mask) +{ + if (unlikely(p4d_none(*p4d))) { + if (__pud_alloc(mm, p4d, address)) + return NULL; + *mod_mask |= PGTBL_P4D_MODIFIED; + } + + return pud_offset(p4d, address); +} + static inline pmd_t *pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address) { return (unlikely(pud_none(*pud)) && __pmd_alloc(mm, pud, address))? NULL: pmd_offset(pud, address); } + +static inline pmd_t *pmd_alloc_track(struct mm_struct *mm, pud_t *pud, + unsigned long address, + pgtbl_mod_mask *mod_mask) +{ + if (unlikely(pud_none(*pud))) { + if (__pmd_alloc(mm, pud, address)) + return NULL; + *mod_mask |= PGTBL_PUD_MODIFIED; + } + + return pmd_offset(pud, address); +} #endif /* CONFIG_MMU */ #if USE_SPLIT_PTE_PTLOCKS @@ -2200,6 +2241,11 @@ static inline void pgtable_pte_page_dtor(struct page *page) ((unlikely(pmd_none(*(pmd))) && __pte_alloc_kernel(pmd))? \ NULL: pte_offset_kernel(pmd, address)) +#define pte_alloc_kernel_track(pmd, address, mask) \ + ((unlikely(pmd_none(*(pmd))) && \ + (__pte_alloc_kernel(pmd) || ({*(mask)|=PGTBL_PMD_MODIFIED;0;})))?\ + NULL: pte_offset_kernel(pmd, address)) + #if USE_SPLIT_PMD_PTLOCKS static struct page *pmd_to_page(pmd_t *pmd)