Message ID | 20240220203256.31153-3-mbland@motorola.com (mailing list archive) |
---|---|
State | Not Applicable |
Headers | show |
Series | arm64: mm: support dynamic vmalloc/pmd configuration | expand |
Le 20/02/2024 à 21:32, Maxwell Bland a écrit : > [Vous ne recevez pas souvent de courriers de mbland@motorola.com. Découvrez pourquoi ceci est important à https://aka.ms/LearnAboutSenderIdentification ] > > While other descriptors (e.g. pud) allow allocations conditional on > which virtual address is allocated, pmd descriptor allocations do not. > However, adding support for this is straightforward and is beneficial to > future kernel development targeting the PMD memory granularity. > > As many architectures already implement pmd_populate_kernel in an > address-generic manner, it is necessary to roll out support > incrementally. For this purpose a preprocessor flag, Is it really worth it ? It is only 48 call sites that need to be updated. It would avoid that processor flag and avoid introducing that pmd_populate_kernel_at() in kernel core. $ git grep -l pmd_populate_kernel -- arch/ | wc -l 48 > __HAVE_ARCH_ADDR_COND_PMD is introduced to capture whether the > architecture supports some feature requiring PMD allocation conditional > on virtual address. Some microarchitectures (e.g. arm64) support > configurations for table descriptors, for example to enforce Privilege > eXecute Never, which benefit from knowing the virtual memory addresses > referenced by PMDs. > > Thus two major arguments in favor of this change are (1) unformity of > allocation between PMD and other table descriptor types and (2) the > capability of address-specific PMD allocation. Can you give more details on that uniformity ? I can't find any function called pud_populate_kernel(). Previously, pmd_populate_kernel() had same arguments as pmd_populate(). Why not also updating pmd_populate() to keep consistancy ? (can be done in a follow-up patch, not in this patch). > > Signed-off-by: Maxwell Bland <mbland@motorola.com> > --- > include/asm-generic/pgalloc.h | 18 ++++++++++++++++++ > include/linux/mm.h | 4 ++-- > mm/hugetlb_vmemmap.c | 4 ++-- > mm/kasan/init.c | 22 +++++++++++++--------- > mm/memory.c | 4 ++-- > mm/percpu.c | 2 +- > mm/pgalloc-track.h | 3 ++- > mm/sparse-vmemmap.c | 2 +- > 8 files changed, 41 insertions(+), 18 deletions(-) > > diff --git a/include/asm-generic/pgalloc.h b/include/asm-generic/pgalloc.h > index 879e5f8aa5e9..e5cdce77c6e4 100644 > --- a/include/asm-generic/pgalloc.h > +++ b/include/asm-generic/pgalloc.h > @@ -142,6 +142,24 @@ static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr) > } > #endif > > +#ifdef __HAVE_ARCH_ADDR_COND_PMD > +static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, > + pte_t *ptep, unsigned long address); > +#else > +static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, > + pte_t *ptep); > +#endif > + > +static inline void pmd_populate_kernel_at(struct mm_struct *mm, pmd_t *pmdp, > + pte_t *ptep, unsigned long address) > +{ > +#ifdef __HAVE_ARCH_ADDR_COND_PMD > + pmd_populate_kernel(mm, pmdp, ptep, address); > +#else > + pmd_populate_kernel(mm, pmdp, ptep); > +#endif > +} > + > #ifndef __HAVE_ARCH_PMD_FREE > static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) > { > diff --git a/include/linux/mm.h b/include/linux/mm.h > index f5a97dec5169..6a9d5ded428d 100644 > --- a/include/linux/mm.h > +++ b/include/linux/mm.h > @@ -2782,7 +2782,7 @@ static inline void mm_dec_nr_ptes(struct mm_struct *mm) {} > #endif > > int __pte_alloc(struct mm_struct *mm, pmd_t *pmd); > -int __pte_alloc_kernel(pmd_t *pmd); > +int __pte_alloc_kernel(pmd_t *pmd, unsigned long address); > > #if defined(CONFIG_MMU) > > @@ -2977,7 +2977,7 @@ pte_t *pte_offset_map_nolock(struct mm_struct *mm, pmd_t *pmd, > NULL : pte_offset_map_lock(mm, pmd, address, ptlp)) > > #define pte_alloc_kernel(pmd, address) \ > - ((unlikely(pmd_none(*(pmd))) && __pte_alloc_kernel(pmd))? \ > + ((unlikely(pmd_none(*(pmd))) && __pte_alloc_kernel(pmd, address)) ? \ > NULL: pte_offset_kernel(pmd, address)) > > #if USE_SPLIT_PMD_PTLOCKS > diff --git a/mm/hugetlb_vmemmap.c b/mm/hugetlb_vmemmap.c > index da177e49d956..1f5664b656f1 100644 > --- a/mm/hugetlb_vmemmap.c > +++ b/mm/hugetlb_vmemmap.c > @@ -58,7 +58,7 @@ static int vmemmap_split_pmd(pmd_t *pmd, struct page *head, unsigned long start, > if (!pgtable) > return -ENOMEM; > > - pmd_populate_kernel(&init_mm, &__pmd, pgtable); > + pmd_populate_kernel_at(&init_mm, &__pmd, pgtable, addr); > > for (i = 0; i < PTRS_PER_PTE; i++, addr += PAGE_SIZE) { > pte_t entry, *pte; > @@ -81,7 +81,7 @@ static int vmemmap_split_pmd(pmd_t *pmd, struct page *head, unsigned long start, > > /* Make pte visible before pmd. See comment in pmd_install(). */ > smp_wmb(); > - pmd_populate_kernel(&init_mm, pmd, pgtable); > + pmd_populate_kernel_at(&init_mm, pmd, pgtable, addr); > if (!(walk->flags & VMEMMAP_SPLIT_NO_TLB_FLUSH)) > flush_tlb_kernel_range(start, start + PMD_SIZE); > } else { > diff --git a/mm/kasan/init.c b/mm/kasan/init.c > index 89895f38f722..1e31d965a14e 100644 > --- a/mm/kasan/init.c > +++ b/mm/kasan/init.c > @@ -116,8 +116,9 @@ static int __ref zero_pmd_populate(pud_t *pud, unsigned long addr, > next = pmd_addr_end(addr, end); > > if (IS_ALIGNED(addr, PMD_SIZE) && end - addr >= PMD_SIZE) { > - pmd_populate_kernel(&init_mm, pmd, > - lm_alias(kasan_early_shadow_pte)); > + pmd_populate_kernel_at(&init_mm, pmd, > + lm_alias(kasan_early_shadow_pte), > + addr); > continue; > } > > @@ -131,7 +132,7 @@ static int __ref zero_pmd_populate(pud_t *pud, unsigned long addr, > if (!p) > return -ENOMEM; > > - pmd_populate_kernel(&init_mm, pmd, p); > + pmd_populate_kernel_at(&init_mm, pmd, p, addr); > } > zero_pte_populate(pmd, addr, next); > } while (pmd++, addr = next, addr != end); > @@ -157,8 +158,9 @@ static int __ref zero_pud_populate(p4d_t *p4d, unsigned long addr, > pud_populate(&init_mm, pud, > lm_alias(kasan_early_shadow_pmd)); > pmd = pmd_offset(pud, addr); > - pmd_populate_kernel(&init_mm, pmd, > - lm_alias(kasan_early_shadow_pte)); > + pmd_populate_kernel_at(&init_mm, pmd, > + lm_alias(kasan_early_shadow_pte), > + addr); > continue; > } > > @@ -203,8 +205,9 @@ static int __ref zero_p4d_populate(pgd_t *pgd, unsigned long addr, > pud_populate(&init_mm, pud, > lm_alias(kasan_early_shadow_pmd)); > pmd = pmd_offset(pud, addr); > - pmd_populate_kernel(&init_mm, pmd, > - lm_alias(kasan_early_shadow_pte)); > + pmd_populate_kernel_at(&init_mm, pmd, > + lm_alias(kasan_early_shadow_pte), > + addr); > continue; > } > > @@ -266,8 +269,9 @@ int __ref kasan_populate_early_shadow(const void *shadow_start, > pud_populate(&init_mm, pud, > lm_alias(kasan_early_shadow_pmd)); > pmd = pmd_offset(pud, addr); > - pmd_populate_kernel(&init_mm, pmd, > - lm_alias(kasan_early_shadow_pte)); > + pmd_populate_kernel_at(&init_mm, pmd, > + lm_alias(kasan_early_shadow_pte), > + addr); > continue; > } > > diff --git a/mm/memory.c b/mm/memory.c > index 15f8b10ea17c..15702822d904 100644 > --- a/mm/memory.c > +++ b/mm/memory.c > @@ -447,7 +447,7 @@ int __pte_alloc(struct mm_struct *mm, pmd_t *pmd) > return 0; > } > > -int __pte_alloc_kernel(pmd_t *pmd) > +int __pte_alloc_kernel(pmd_t *pmd, unsigned long address) > { > pte_t *new = pte_alloc_one_kernel(&init_mm); > if (!new) > @@ -456,7 +456,7 @@ int __pte_alloc_kernel(pmd_t *pmd) > spin_lock(&init_mm.page_table_lock); > if (likely(pmd_none(*pmd))) { /* Has another populated it ? */ > smp_wmb(); /* See comment in pmd_install() */ > - pmd_populate_kernel(&init_mm, pmd, new); > + pmd_populate_kernel_at(&init_mm, pmd, new, address); > new = NULL; > } > spin_unlock(&init_mm.page_table_lock); > diff --git a/mm/percpu.c b/mm/percpu.c > index 4e11fc1e6def..7312e584c1b5 100644 > --- a/mm/percpu.c > +++ b/mm/percpu.c > @@ -3238,7 +3238,7 @@ void __init __weak pcpu_populate_pte(unsigned long addr) > new = memblock_alloc(PTE_TABLE_SIZE, PTE_TABLE_SIZE); > if (!new) > goto err_alloc; > - pmd_populate_kernel(&init_mm, pmd, new); > + pmd_populate_kernel_at(&init_mm, pmd, new, addr); > } > > return; > diff --git a/mm/pgalloc-track.h b/mm/pgalloc-track.h > index e9e879de8649..0984681c03d4 100644 > --- a/mm/pgalloc-track.h > +++ b/mm/pgalloc-track.h > @@ -45,7 +45,8 @@ static inline pmd_t *pmd_alloc_track(struct mm_struct *mm, pud_t *pud, > > #define pte_alloc_kernel_track(pmd, address, mask) \ > ((unlikely(pmd_none(*(pmd))) && \ > - (__pte_alloc_kernel(pmd) || ({*(mask)|=PGTBL_PMD_MODIFIED;0;})))?\ > + (__pte_alloc_kernel(pmd, address) || \ > + ({*(mask) |= PGTBL_PMD_MODIFIED; 0; }))) ? \ > NULL: pte_offset_kernel(pmd, address)) > > #endif /* _LINUX_PGALLOC_TRACK_H */ > diff --git a/mm/sparse-vmemmap.c b/mm/sparse-vmemmap.c > index a2cbe44c48e1..d876cc4dc700 100644 > --- a/mm/sparse-vmemmap.c > +++ b/mm/sparse-vmemmap.c > @@ -191,7 +191,7 @@ pmd_t * __meminit vmemmap_pmd_populate(pud_t *pud, unsigned long addr, int node) > void *p = vmemmap_alloc_block_zero(PAGE_SIZE, node); > if (!p) > return NULL; > - pmd_populate_kernel(&init_mm, pmd, p); > + pmd_populate_kernel_at(&init_mm, pmd, p, addr); > } > return pmd; > } > -- > 2.39.2 >
On 21.02.24 08:13, Christophe Leroy wrote: > > > Le 20/02/2024 à 21:32, Maxwell Bland a écrit : >> [Vous ne recevez pas souvent de courriers de mbland@motorola.com. Découvrez pourquoi ceci est important à https://aka.ms/LearnAboutSenderIdentification ] >> >> While other descriptors (e.g. pud) allow allocations conditional on >> which virtual address is allocated, pmd descriptor allocations do not. >> However, adding support for this is straightforward and is beneficial to >> future kernel development targeting the PMD memory granularity. >> >> As many architectures already implement pmd_populate_kernel in an >> address-generic manner, it is necessary to roll out support >> incrementally. For this purpose a preprocessor flag, > > Is it really worth it ? It is only 48 call sites that need to be > updated. It would avoid that processor flag and avoid introducing that > pmd_populate_kernel_at() in kernel core. +1, let's avoid that if possible.
> On February 21, 2024 3:27 AM David Hildenbrand wrote > On 21.02.24 08:13, Christophe Leroy wrote: > > Le 20/02/2024 à 21:32, Maxwell Bland a écrit : > >> > >> While other descriptors (e.g. pud) allow allocations conditional on > >> which virtual address is allocated, pmd descriptor allocations do not. > >> However, adding support for this is straightforward and is beneficial to > >> future kernel development targeting the PMD memory granularity. > >> > >> As many architectures already implement pmd_populate_kernel in an > >> address-generic manner, it is necessary to roll out support > >> incrementally. For this purpose a preprocessor flag, > > > > Is it really worth it ? It is only 48 call sites that need to be > > updated. It would avoid that processor flag and avoid introducing that > > pmd_populate_kernel_at() in kernel core. > > +1, let's avoid that if possible. Will fix, thank you! Maxwell
Hi Maxwell, kernel test robot noticed the following build errors: [auto build test ERROR on b401b621758e46812da61fa58a67c3fd8d91de0d] url: https://github.com/intel-lab-lkp/linux/commits/Maxwell-Bland/mm-vmalloc-allow-arch-specific-vmalloc_node-overrides/20240221-043458 base: b401b621758e46812da61fa58a67c3fd8d91de0d patch link: https://lore.kernel.org/r/20240220203256.31153-3-mbland%40motorola.com patch subject: [PATCH 2/4] mm: pgalloc: support address-conditional pmd allocation config: arm-defconfig (https://download.01.org/0day-ci/archive/20240222/202402220006.5v6axq6B-lkp@intel.com/config) compiler: clang version 14.0.6 (https://github.com/llvm/llvm-project.git f28c006a5895fc0e329fe15fead81e37457cb1d1) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240222/202402220006.5v6axq6B-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202402220006.5v6axq6B-lkp@intel.com/ All errors (new ones prefixed by >>): >> mm/memory.c:459:3: error: implicit declaration of function 'pmd_populate_kernel_at' is invalid in C99 [-Werror,-Wimplicit-function-declaration] pmd_populate_kernel_at(&init_mm, pmd, new, address); ^ mm/memory.c:459:3: note: did you mean 'pmd_populate_kernel'? arch/arm/include/asm/pgalloc.h:125:1: note: 'pmd_populate_kernel' declared here pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep) ^ 1 error generated. vim +/pmd_populate_kernel_at +459 mm/memory.c 449 450 int __pte_alloc_kernel(pmd_t *pmd, unsigned long address) 451 { 452 pte_t *new = pte_alloc_one_kernel(&init_mm); 453 if (!new) 454 return -ENOMEM; 455 456 spin_lock(&init_mm.page_table_lock); 457 if (likely(pmd_none(*pmd))) { /* Has another populated it ? */ 458 smp_wmb(); /* See comment in pmd_install() */ > 459 pmd_populate_kernel_at(&init_mm, pmd, new, address); 460 new = NULL; 461 } 462 spin_unlock(&init_mm.page_table_lock); 463 if (new) 464 pte_free_kernel(&init_mm, new); 465 return 0; 466 } 467
Hi Maxwell, kernel test robot noticed the following build errors: [auto build test ERROR on b401b621758e46812da61fa58a67c3fd8d91de0d] url: https://github.com/intel-lab-lkp/linux/commits/Maxwell-Bland/mm-vmalloc-allow-arch-specific-vmalloc_node-overrides/20240221-043458 base: b401b621758e46812da61fa58a67c3fd8d91de0d patch link: https://lore.kernel.org/r/20240220203256.31153-3-mbland%40motorola.com patch subject: [PATCH 2/4] mm: pgalloc: support address-conditional pmd allocation config: um-allmodconfig (https://download.01.org/0day-ci/archive/20240222/202402220052.S3IUgmez-lkp@intel.com/config) compiler: clang version 19.0.0git (https://github.com/llvm/llvm-project 36adfec155de366d722f2bac8ff9162289dcf06c) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240222/202402220052.S3IUgmez-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202402220052.S3IUgmez-lkp@intel.com/ All error/warnings (new ones prefixed by >>): In file included from kernel/fork.c:34: In file included from include/linux/mempolicy.h:15: In file included from include/linux/pagemap.h:11: In file included from include/linux/highmem.h:12: In file included from include/linux/hardirq.h:11: In file included from arch/um/include/asm/hardirq.h:5: In file included from include/asm-generic/hardirq.h:17: In file included from include/linux/irq.h:20: In file included from include/linux/io.h:13: In file included from arch/um/include/asm/io.h:24: include/asm-generic/io.h:547:31: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 547 | val = __raw_readb(PCI_IOBASE + addr); | ~~~~~~~~~~ ^ include/asm-generic/io.h:560:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 560 | val = __le16_to_cpu((__le16 __force)__raw_readw(PCI_IOBASE + addr)); | ~~~~~~~~~~ ^ include/uapi/linux/byteorder/little_endian.h:37:51: note: expanded from macro '__le16_to_cpu' 37 | #define __le16_to_cpu(x) ((__force __u16)(__le16)(x)) | ^ In file included from kernel/fork.c:34: In file included from include/linux/mempolicy.h:15: In file included from include/linux/pagemap.h:11: In file included from include/linux/highmem.h:12: In file included from include/linux/hardirq.h:11: In file included from arch/um/include/asm/hardirq.h:5: In file included from include/asm-generic/hardirq.h:17: In file included from include/linux/irq.h:20: In file included from include/linux/io.h:13: In file included from arch/um/include/asm/io.h:24: include/asm-generic/io.h:573:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 573 | val = __le32_to_cpu((__le32 __force)__raw_readl(PCI_IOBASE + addr)); | ~~~~~~~~~~ ^ include/uapi/linux/byteorder/little_endian.h:35:51: note: expanded from macro '__le32_to_cpu' 35 | #define __le32_to_cpu(x) ((__force __u32)(__le32)(x)) | ^ In file included from kernel/fork.c:34: In file included from include/linux/mempolicy.h:15: In file included from include/linux/pagemap.h:11: In file included from include/linux/highmem.h:12: In file included from include/linux/hardirq.h:11: In file included from arch/um/include/asm/hardirq.h:5: In file included from include/asm-generic/hardirq.h:17: In file included from include/linux/irq.h:20: In file included from include/linux/io.h:13: In file included from arch/um/include/asm/io.h:24: include/asm-generic/io.h:584:33: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 584 | __raw_writeb(value, PCI_IOBASE + addr); | ~~~~~~~~~~ ^ include/asm-generic/io.h:594:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 594 | __raw_writew((u16 __force)cpu_to_le16(value), PCI_IOBASE + addr); | ~~~~~~~~~~ ^ include/asm-generic/io.h:604:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 604 | __raw_writel((u32 __force)cpu_to_le32(value), PCI_IOBASE + addr); | ~~~~~~~~~~ ^ include/asm-generic/io.h:692:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 692 | readsb(PCI_IOBASE + addr, buffer, count); | ~~~~~~~~~~ ^ include/asm-generic/io.h:700:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 700 | readsw(PCI_IOBASE + addr, buffer, count); | ~~~~~~~~~~ ^ include/asm-generic/io.h:708:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 708 | readsl(PCI_IOBASE + addr, buffer, count); | ~~~~~~~~~~ ^ include/asm-generic/io.h:717:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 717 | writesb(PCI_IOBASE + addr, buffer, count); | ~~~~~~~~~~ ^ include/asm-generic/io.h:726:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 726 | writesw(PCI_IOBASE + addr, buffer, count); | ~~~~~~~~~~ ^ include/asm-generic/io.h:735:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 735 | writesl(PCI_IOBASE + addr, buffer, count); | ~~~~~~~~~~ ^ In file included from kernel/fork.c:105: In file included from arch/um/include/asm/pgalloc.h:13: >> include/asm-generic/pgalloc.h:149:20: warning: function 'pmd_populate_kernel' has internal linkage but is not defined [-Wundefined-internal] 149 | static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, | ^ include/asm-generic/pgalloc.h:159:2: note: used here 159 | pmd_populate_kernel(mm, pmdp, ptep); | ^ 13 warnings generated. -- In file included from mm/mremap.c:12: In file included from include/linux/mm_inline.h:8: In file included from include/linux/swap.h:9: In file included from include/linux/memcontrol.h:13: In file included from include/linux/cgroup.h:26: In file included from include/linux/kernel_stat.h:9: In file included from include/linux/interrupt.h:11: In file included from include/linux/hardirq.h:11: In file included from arch/um/include/asm/hardirq.h:5: In file included from include/asm-generic/hardirq.h:17: In file included from include/linux/irq.h:20: In file included from include/linux/io.h:13: In file included from arch/um/include/asm/io.h:24: include/asm-generic/io.h:547:31: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 547 | val = __raw_readb(PCI_IOBASE + addr); | ~~~~~~~~~~ ^ include/asm-generic/io.h:560:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 560 | val = __le16_to_cpu((__le16 __force)__raw_readw(PCI_IOBASE + addr)); | ~~~~~~~~~~ ^ include/uapi/linux/byteorder/little_endian.h:37:51: note: expanded from macro '__le16_to_cpu' 37 | #define __le16_to_cpu(x) ((__force __u16)(__le16)(x)) | ^ In file included from mm/mremap.c:12: In file included from include/linux/mm_inline.h:8: In file included from include/linux/swap.h:9: In file included from include/linux/memcontrol.h:13: In file included from include/linux/cgroup.h:26: In file included from include/linux/kernel_stat.h:9: In file included from include/linux/interrupt.h:11: In file included from include/linux/hardirq.h:11: In file included from arch/um/include/asm/hardirq.h:5: In file included from include/asm-generic/hardirq.h:17: In file included from include/linux/irq.h:20: In file included from include/linux/io.h:13: In file included from arch/um/include/asm/io.h:24: include/asm-generic/io.h:573:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 573 | val = __le32_to_cpu((__le32 __force)__raw_readl(PCI_IOBASE + addr)); | ~~~~~~~~~~ ^ include/uapi/linux/byteorder/little_endian.h:35:51: note: expanded from macro '__le32_to_cpu' 35 | #define __le32_to_cpu(x) ((__force __u32)(__le32)(x)) | ^ In file included from mm/mremap.c:12: In file included from include/linux/mm_inline.h:8: In file included from include/linux/swap.h:9: In file included from include/linux/memcontrol.h:13: In file included from include/linux/cgroup.h:26: In file included from include/linux/kernel_stat.h:9: In file included from include/linux/interrupt.h:11: In file included from include/linux/hardirq.h:11: In file included from arch/um/include/asm/hardirq.h:5: In file included from include/asm-generic/hardirq.h:17: In file included from include/linux/irq.h:20: In file included from include/linux/io.h:13: In file included from arch/um/include/asm/io.h:24: include/asm-generic/io.h:584:33: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 584 | __raw_writeb(value, PCI_IOBASE + addr); | ~~~~~~~~~~ ^ include/asm-generic/io.h:594:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 594 | __raw_writew((u16 __force)cpu_to_le16(value), PCI_IOBASE + addr); | ~~~~~~~~~~ ^ include/asm-generic/io.h:604:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 604 | __raw_writel((u32 __force)cpu_to_le32(value), PCI_IOBASE + addr); | ~~~~~~~~~~ ^ include/asm-generic/io.h:692:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 692 | readsb(PCI_IOBASE + addr, buffer, count); | ~~~~~~~~~~ ^ include/asm-generic/io.h:700:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 700 | readsw(PCI_IOBASE + addr, buffer, count); | ~~~~~~~~~~ ^ include/asm-generic/io.h:708:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 708 | readsl(PCI_IOBASE + addr, buffer, count); | ~~~~~~~~~~ ^ include/asm-generic/io.h:717:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 717 | writesb(PCI_IOBASE + addr, buffer, count); | ~~~~~~~~~~ ^ include/asm-generic/io.h:726:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 726 | writesw(PCI_IOBASE + addr, buffer, count); | ~~~~~~~~~~ ^ include/asm-generic/io.h:735:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 735 | writesl(PCI_IOBASE + addr, buffer, count); | ~~~~~~~~~~ ^ In file included from mm/mremap.c:31: In file included from arch/um/include/asm/pgalloc.h:13: >> include/asm-generic/pgalloc.h:149:20: warning: function 'pmd_populate_kernel' has internal linkage but is not defined [-Wundefined-internal] 149 | static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, | ^ include/asm-generic/pgalloc.h:159:2: note: used here 159 | pmd_populate_kernel(mm, pmdp, ptep); | ^ mm/mremap.c:228:20: warning: unused function 'arch_supports_page_table_move' [-Wunused-function] 228 | static inline bool arch_supports_page_table_move(void) | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ mm/mremap.c:227:39: note: expanded from macro 'arch_supports_page_table_move' 227 | #define arch_supports_page_table_move arch_supports_page_table_move | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 14 warnings generated. -- arch/um/kernel/skas/mmu.c:17:5: warning: no previous prototype for function 'init_new_context' [-Wmissing-prototypes] 17 | int init_new_context(struct task_struct *task, struct mm_struct *mm) | ^ arch/um/kernel/skas/mmu.c:17:1: note: declare 'static' if the function is not intended to be used outside of this translation unit 17 | int init_new_context(struct task_struct *task, struct mm_struct *mm) | ^ | static arch/um/kernel/skas/mmu.c:60:6: warning: no previous prototype for function 'destroy_context' [-Wmissing-prototypes] 60 | void destroy_context(struct mm_struct *mm) | ^ arch/um/kernel/skas/mmu.c:60:1: note: declare 'static' if the function is not intended to be used outside of this translation unit 60 | void destroy_context(struct mm_struct *mm) | ^ | static In file included from arch/um/kernel/skas/mmu.c:11: In file included from arch/um/include/asm/pgalloc.h:13: >> include/asm-generic/pgalloc.h:149:20: warning: function 'pmd_populate_kernel' has internal linkage but is not defined [-Wundefined-internal] 149 | static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, | ^ include/asm-generic/pgalloc.h:159:2: note: used here 159 | pmd_populate_kernel(mm, pmdp, ptep); | ^ 3 warnings generated. -- /usr/bin/ld: warning: .tmp_vmlinux.kallsyms1 has a LOAD segment with RWX permissions /usr/bin/ld: mm/memory.o: in function `pmd_populate_kernel_at': >> include/asm-generic/pgalloc.h:159: undefined reference to `pmd_populate_kernel' clang: error: linker command failed with exit code 1 (use -v to see invocation) vim +159 include/asm-generic/pgalloc.h 144 145 #ifdef __HAVE_ARCH_ADDR_COND_PMD 146 static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, 147 pte_t *ptep, unsigned long address); 148 #else > 149 static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, 150 pte_t *ptep); 151 #endif 152 153 static inline void pmd_populate_kernel_at(struct mm_struct *mm, pmd_t *pmdp, 154 pte_t *ptep, unsigned long address) 155 { 156 #ifdef __HAVE_ARCH_ADDR_COND_PMD 157 pmd_populate_kernel(mm, pmdp, ptep, address); 158 #else > 159 pmd_populate_kernel(mm, pmdp, ptep); 160 #endif 161 } 162
diff --git a/include/asm-generic/pgalloc.h b/include/asm-generic/pgalloc.h index 879e5f8aa5e9..e5cdce77c6e4 100644 --- a/include/asm-generic/pgalloc.h +++ b/include/asm-generic/pgalloc.h @@ -142,6 +142,24 @@ static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr) } #endif +#ifdef __HAVE_ARCH_ADDR_COND_PMD +static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, + pte_t *ptep, unsigned long address); +#else +static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, + pte_t *ptep); +#endif + +static inline void pmd_populate_kernel_at(struct mm_struct *mm, pmd_t *pmdp, + pte_t *ptep, unsigned long address) +{ +#ifdef __HAVE_ARCH_ADDR_COND_PMD + pmd_populate_kernel(mm, pmdp, ptep, address); +#else + pmd_populate_kernel(mm, pmdp, ptep); +#endif +} + #ifndef __HAVE_ARCH_PMD_FREE static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) { diff --git a/include/linux/mm.h b/include/linux/mm.h index f5a97dec5169..6a9d5ded428d 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -2782,7 +2782,7 @@ static inline void mm_dec_nr_ptes(struct mm_struct *mm) {} #endif int __pte_alloc(struct mm_struct *mm, pmd_t *pmd); -int __pte_alloc_kernel(pmd_t *pmd); +int __pte_alloc_kernel(pmd_t *pmd, unsigned long address); #if defined(CONFIG_MMU) @@ -2977,7 +2977,7 @@ pte_t *pte_offset_map_nolock(struct mm_struct *mm, pmd_t *pmd, NULL : pte_offset_map_lock(mm, pmd, address, ptlp)) #define pte_alloc_kernel(pmd, address) \ - ((unlikely(pmd_none(*(pmd))) && __pte_alloc_kernel(pmd))? \ + ((unlikely(pmd_none(*(pmd))) && __pte_alloc_kernel(pmd, address)) ? \ NULL: pte_offset_kernel(pmd, address)) #if USE_SPLIT_PMD_PTLOCKS diff --git a/mm/hugetlb_vmemmap.c b/mm/hugetlb_vmemmap.c index da177e49d956..1f5664b656f1 100644 --- a/mm/hugetlb_vmemmap.c +++ b/mm/hugetlb_vmemmap.c @@ -58,7 +58,7 @@ static int vmemmap_split_pmd(pmd_t *pmd, struct page *head, unsigned long start, if (!pgtable) return -ENOMEM; - pmd_populate_kernel(&init_mm, &__pmd, pgtable); + pmd_populate_kernel_at(&init_mm, &__pmd, pgtable, addr); for (i = 0; i < PTRS_PER_PTE; i++, addr += PAGE_SIZE) { pte_t entry, *pte; @@ -81,7 +81,7 @@ static int vmemmap_split_pmd(pmd_t *pmd, struct page *head, unsigned long start, /* Make pte visible before pmd. See comment in pmd_install(). */ smp_wmb(); - pmd_populate_kernel(&init_mm, pmd, pgtable); + pmd_populate_kernel_at(&init_mm, pmd, pgtable, addr); if (!(walk->flags & VMEMMAP_SPLIT_NO_TLB_FLUSH)) flush_tlb_kernel_range(start, start + PMD_SIZE); } else { diff --git a/mm/kasan/init.c b/mm/kasan/init.c index 89895f38f722..1e31d965a14e 100644 --- a/mm/kasan/init.c +++ b/mm/kasan/init.c @@ -116,8 +116,9 @@ static int __ref zero_pmd_populate(pud_t *pud, unsigned long addr, next = pmd_addr_end(addr, end); if (IS_ALIGNED(addr, PMD_SIZE) && end - addr >= PMD_SIZE) { - pmd_populate_kernel(&init_mm, pmd, - lm_alias(kasan_early_shadow_pte)); + pmd_populate_kernel_at(&init_mm, pmd, + lm_alias(kasan_early_shadow_pte), + addr); continue; } @@ -131,7 +132,7 @@ static int __ref zero_pmd_populate(pud_t *pud, unsigned long addr, if (!p) return -ENOMEM; - pmd_populate_kernel(&init_mm, pmd, p); + pmd_populate_kernel_at(&init_mm, pmd, p, addr); } zero_pte_populate(pmd, addr, next); } while (pmd++, addr = next, addr != end); @@ -157,8 +158,9 @@ static int __ref zero_pud_populate(p4d_t *p4d, unsigned long addr, pud_populate(&init_mm, pud, lm_alias(kasan_early_shadow_pmd)); pmd = pmd_offset(pud, addr); - pmd_populate_kernel(&init_mm, pmd, - lm_alias(kasan_early_shadow_pte)); + pmd_populate_kernel_at(&init_mm, pmd, + lm_alias(kasan_early_shadow_pte), + addr); continue; } @@ -203,8 +205,9 @@ static int __ref zero_p4d_populate(pgd_t *pgd, unsigned long addr, pud_populate(&init_mm, pud, lm_alias(kasan_early_shadow_pmd)); pmd = pmd_offset(pud, addr); - pmd_populate_kernel(&init_mm, pmd, - lm_alias(kasan_early_shadow_pte)); + pmd_populate_kernel_at(&init_mm, pmd, + lm_alias(kasan_early_shadow_pte), + addr); continue; } @@ -266,8 +269,9 @@ int __ref kasan_populate_early_shadow(const void *shadow_start, pud_populate(&init_mm, pud, lm_alias(kasan_early_shadow_pmd)); pmd = pmd_offset(pud, addr); - pmd_populate_kernel(&init_mm, pmd, - lm_alias(kasan_early_shadow_pte)); + pmd_populate_kernel_at(&init_mm, pmd, + lm_alias(kasan_early_shadow_pte), + addr); continue; } diff --git a/mm/memory.c b/mm/memory.c index 15f8b10ea17c..15702822d904 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -447,7 +447,7 @@ int __pte_alloc(struct mm_struct *mm, pmd_t *pmd) return 0; } -int __pte_alloc_kernel(pmd_t *pmd) +int __pte_alloc_kernel(pmd_t *pmd, unsigned long address) { pte_t *new = pte_alloc_one_kernel(&init_mm); if (!new) @@ -456,7 +456,7 @@ int __pte_alloc_kernel(pmd_t *pmd) spin_lock(&init_mm.page_table_lock); if (likely(pmd_none(*pmd))) { /* Has another populated it ? */ smp_wmb(); /* See comment in pmd_install() */ - pmd_populate_kernel(&init_mm, pmd, new); + pmd_populate_kernel_at(&init_mm, pmd, new, address); new = NULL; } spin_unlock(&init_mm.page_table_lock); diff --git a/mm/percpu.c b/mm/percpu.c index 4e11fc1e6def..7312e584c1b5 100644 --- a/mm/percpu.c +++ b/mm/percpu.c @@ -3238,7 +3238,7 @@ void __init __weak pcpu_populate_pte(unsigned long addr) new = memblock_alloc(PTE_TABLE_SIZE, PTE_TABLE_SIZE); if (!new) goto err_alloc; - pmd_populate_kernel(&init_mm, pmd, new); + pmd_populate_kernel_at(&init_mm, pmd, new, addr); } return; diff --git a/mm/pgalloc-track.h b/mm/pgalloc-track.h index e9e879de8649..0984681c03d4 100644 --- a/mm/pgalloc-track.h +++ b/mm/pgalloc-track.h @@ -45,7 +45,8 @@ static inline pmd_t *pmd_alloc_track(struct mm_struct *mm, pud_t *pud, #define pte_alloc_kernel_track(pmd, address, mask) \ ((unlikely(pmd_none(*(pmd))) && \ - (__pte_alloc_kernel(pmd) || ({*(mask)|=PGTBL_PMD_MODIFIED;0;})))?\ + (__pte_alloc_kernel(pmd, address) || \ + ({*(mask) |= PGTBL_PMD_MODIFIED; 0; }))) ? \ NULL: pte_offset_kernel(pmd, address)) #endif /* _LINUX_PGALLOC_TRACK_H */ diff --git a/mm/sparse-vmemmap.c b/mm/sparse-vmemmap.c index a2cbe44c48e1..d876cc4dc700 100644 --- a/mm/sparse-vmemmap.c +++ b/mm/sparse-vmemmap.c @@ -191,7 +191,7 @@ pmd_t * __meminit vmemmap_pmd_populate(pud_t *pud, unsigned long addr, int node) void *p = vmemmap_alloc_block_zero(PAGE_SIZE, node); if (!p) return NULL; - pmd_populate_kernel(&init_mm, pmd, p); + pmd_populate_kernel_at(&init_mm, pmd, p, addr); } return pmd; }
While other descriptors (e.g. pud) allow allocations conditional on which virtual address is allocated, pmd descriptor allocations do not. However, adding support for this is straightforward and is beneficial to future kernel development targeting the PMD memory granularity. As many architectures already implement pmd_populate_kernel in an address-generic manner, it is necessary to roll out support incrementally. For this purpose a preprocessor flag, __HAVE_ARCH_ADDR_COND_PMD is introduced to capture whether the architecture supports some feature requiring PMD allocation conditional on virtual address. Some microarchitectures (e.g. arm64) support configurations for table descriptors, for example to enforce Privilege eXecute Never, which benefit from knowing the virtual memory addresses referenced by PMDs. Thus two major arguments in favor of this change are (1) unformity of allocation between PMD and other table descriptor types and (2) the capability of address-specific PMD allocation. Signed-off-by: Maxwell Bland <mbland@motorola.com> --- include/asm-generic/pgalloc.h | 18 ++++++++++++++++++ include/linux/mm.h | 4 ++-- mm/hugetlb_vmemmap.c | 4 ++-- mm/kasan/init.c | 22 +++++++++++++--------- mm/memory.c | 4 ++-- mm/percpu.c | 2 +- mm/pgalloc-track.h | 3 ++- mm/sparse-vmemmap.c | 2 +- 8 files changed, 41 insertions(+), 18 deletions(-)