Re: [PATCH 11/18] hugetlb_vmemmap: Use try_populate_vmemmap_pmd for replacing in-use PMDs

James Houghton <[email protected]>
Newsgroups org.infradead.lists.linux-arm-kernel,org.kernel.vger.linux-kernel,org.kvack.linux-mm
Message-ID <CADrL8HXpA7D3UAScj0+TpuqEPcQvLGA6htABnwYnOBXorBQrNw@mail.gmail.com>
On Tue, Aug 18, 2026 at 8:53 AM Catalin Marinas <[email protected]> wrote:
>
> On Wed, Jul 08, 2026 at 03:11:21AM +0000, James Houghton wrote:
> > diff --git a/arch/arm64/include/asm/pgalloc.h b/arch/arm64/include/asm/pgalloc.h
> > index 1b4509d3382c..c8946250d431 100644
> > --- a/arch/arm64/include/asm/pgalloc.h
> > +++ b/arch/arm64/include/asm/pgalloc.h
> > @@ -121,4 +121,13 @@ pmd_populate(struct mm_struct *mm, pmd_t *pmdp, pgtable_t ptep)
> >                      PMD_TYPE_TABLE | PMD_TABLE_AF | PMD_TABLE_PXN);
> >  }
> >
> > +#define __HAVE_ARCH_TRY_POPULATE_VMEMMAP_PMD
> > +static inline int try_populate_vmemmap_pmd(pmd_t *pmdp, pte_t *pgtable,
> > +                                        unsigned long addr)
> > +{
> > +     /* BBML2_NOABORT is required. Its presence has been checked. */
> > +     pmd_populate_kernel(&init_mm, pmdp, pgtable);
> > +     return 0;
> > +}
>
> This patch adds the same function in 4 different arch files. Can we not
> have a single generic implementation in linux/pgalloc.h, bracketed by
> some ARCH_WANTS_* (macro or config)?
>
> I think the same goes for patch 4 with try_update_vmemmap_pte(), we can
> reduce the code duplication.

Yeah putting the generic version behind an ARCH_WANTS ifdef is so much
better. Then I can just nix the EOPNOTSUPP branch; a compile error is
always better.

> > diff --git a/include/linux/pgalloc.h b/include/linux/pgalloc.h
> > index 9174fa59bbc5..ed446d95ca37 100644
> > --- a/include/linux/pgalloc.h
> > +++ b/include/linux/pgalloc.h
> > @@ -26,4 +26,24 @@
> >                       arch_sync_kernel_mappings(addr, addr);          \
> >       } while (0)
> >
> > +#ifndef __HAVE_ARCH_TRY_POPULATE_VMEMMAP_PMD
> > +/*
> > + * try_populate_vmemmap_pmd - Populate a PMD that is in use by the vmemmap.
> > + * @addr: Base address of the remapped PMD.
> > + * @pmdp: Page table pointer to be overwritten.
> > + * @pgtable: Pointer to the page table that the new PMD will point to.
> > + *
> > + * This function is only to be used to update PMDs that map the vmemmap to
> > + * point to a page of already-populated PTEs that map the same pages.
> > + *
> > + * Implementations of this function must ensure that, while the update is taking
> > + * place, CPUs will not fault on the remapped virtual address range.
> > + */
> > +static inline int try_populate_vmemmap_pmd(pmd_t *pmdp, pte_t *pgtable,
> > +                                        unsigned long addr)
>
> Nit: if we follow try_update_vmemmap_pte(), we could place 'addr' first.
> It matches pgd_populate_kernel() as well in this file.

Will do.

> > +{
> > +     return -EOPNOTSUPP;
> > +}
> > +#endif
> > +
> >  #endif /* _LINUX_PGALLOC_H */
> > diff --git a/mm/hugetlb_vmemmap.c b/mm/hugetlb_vmemmap.c
> > index 977249e22ed0..b445febac0d2 100644
> > --- a/mm/hugetlb_vmemmap.c
> > +++ b/mm/hugetlb_vmemmap.c
> > @@ -55,6 +55,7 @@ static int vmemmap_split_pmd(pmd_t *pmd, struct page *head, unsigned long start,
> >                            struct vmemmap_remap_walk *walk)
> >  {
> >       pmd_t __pmd;
> > +     int ret;
> >       int i;
> >       unsigned long addr = start;
> >       pte_t *pgtable;
> > @@ -74,8 +75,15 @@ static int vmemmap_split_pmd(pmd_t *pmd, struct page *head, unsigned long start,
> >               set_pte_at(&init_mm, addr, pte, entry);
> >       }
> >
> > +     ret = 0;
> >       spin_lock(&init_mm.page_table_lock);
> >       if (likely(pmd_leaf(*pmd))) {
> > +             /* Make pte visible before pmd. See comment in pmd_install(). */
> > +             smp_wmb();
> > +             ret = try_populate_vmemmap_pmd(pmd, pgtable, start);
> > +             if (ret)
> > +                     goto free;
> > +
> >               /*
> >                * Higher order allocations from buddy allocator must be able to
> >                * be treated as independent small pages (as they can be freed
> > @@ -84,21 +92,17 @@ static int vmemmap_split_pmd(pmd_t *pmd, struct page *head, unsigned long start,
> >               if (!PageReserved(head))
> >                       split_page(head, get_order(PMD_SIZE));
> >
> > -             /* Make pte visible before pmd. See comment in pmd_install(). */
> > -             smp_wmb();
> > -             /*
> > -              * On arm64, this requires BBML2_NOABORT. Its support has
> > -              * already been checked.
> > -              */
> > -             pmd_populate_kernel(&init_mm, pmd, pgtable);
> >               if (!(walk->flags & VMEMMAP_SPLIT_NO_TLB_FLUSH))
> >                       flush_tlb_kernel_range(start, start + PMD_SIZE);
> > -     } else {
> > -             pte_free_kernel(&init_mm, pgtable);
> > -     }
> > -     spin_unlock(&init_mm.page_table_lock);
> > +     } else
> > +             goto free;
> >
> > -     return 0;
> > +out:
> > +     spin_unlock(&init_mm.page_table_lock);
> > +     return ret;
> > +free:
> > +     pte_free_kernel(&init_mm, pgtable);
> > +     goto out;
> >  }
>
> Would 'free' first with fall through 'out' read better?

Yes, yes it would. I think the current ordering is just a holdover
from earlier attempts at writing this function.

Thanks!
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.