[PATCH v7 2/7] arm64/vmalloc: Allow arch_vmap_pte_range_map_size to batch multiple CONT_PTE

Barry Song baohua at kernel.org
Tue Jul 28 20:57:45 PDT 2026


On Wed, Jul 29, 2026 at 11:45 AM Barry Song <baohua at kernel.org> wrote:
>
> On Wed, Jul 22, 2026 at 2:17 AM David Carlier <devnexen at gmail.com> wrote:
> >
> > Barry, Wen - the returned span is capped at PMD_SIZE >> 1 but only
> > checked for CONT_PTE_SIZE alignment. In the batched vmap() path pages
> > are only contiguous within a naturally aligned block, so when a PMD
> > boundary splits a batch the next region starts mid block and the span
> > runs past the contiguous run - set_huge_pte_at() maps the wrong pages,
> > tail of the array left unmapped, no warning.
> >
> > What do you think of clamping the span to the pfn physical alignment,
> > like 8xx does:
> >
> >         while (!IS_ALIGNED(PFN_PHYS(pfn), size))
> >                 size >>= 1;
>
> Thanks, David.
>
> I noticed that 8xx has simplified this to a simple
>
>     if (!IS_ALIGNED(PFN_PHYS(pfn), size))
>
> Could we do the same here?
>
> diff --git a/arch/arm64/include/asm/vmalloc.h b/arch/arm64/include/asm/vmalloc.h
> index d665f9d68742..a27101e24f76 100644
> --- a/arch/arm64/include/asm/vmalloc.h
> +++ b/arch/arm64/include/asm/vmalloc.h
> @@ -46,6 +46,8 @@ static inline unsigned long
> arch_vmap_pte_range_map_size(unsigned long addr,
>
>         size = min3(end - addr, 1UL << max_page_shift, PMD_SIZE >> 1);
>         size = rounddown_pow_of_two(size);
> +       if (!IS_ALIGNED(PFN_PHYS(pfn), size) || size < CONT_PTE_SIZE)
> +               return PAGE_SIZE;
>         return size;
>  }

On second thought, the caller is walking the PUD, PMD, and PTE
page tables, so it won't pass anything that crosses a PMD
boundary here.
otherwise, the caller has been wrong. for example:

static int vmap_pmd_range(pud_t *pud, unsigned long addr, unsigned long end,
                        phys_addr_t phys_addr, pgprot_t prot,
                        unsigned int max_page_shift, pgtbl_mod_mask *mask)
{
        pmd_t *pmd;
        unsigned long next;
        int err = 0;

        ...
        do {
                next = pmd_addr_end(addr, end);

                if (vmap_try_huge_pmd(pmd, addr, next, phys_addr, prot,
                                        max_page_shift)) {
                        *mask |= PGTBL_PMD_MODIFIED;
                        continue;
                }

                err = vmap_pte_range(pmd, addr, next, phys_addr, prot,
max_page_shift, mask);
                if (err)
                        break;
        } while (pmd++, phys_addr += (next - addr), addr = next, addr != end);
        return err;
}

I guess we don't need to do anything here, David?

Barry



More information about the linux-arm-kernel mailing list