Re: [PATCH 02/12] mm: hugetlb_vmemmap: unify VMEMMAP_{SPLIT,REMAP}_NO_TLB_FLUSH

From: Muchun Song

Date: Sun Nov 01 2026 - 01:56:42 EST




> On Nov 1, 2026, at 14:22, Qi Zheng <qi.zheng@xxxxxxxxx> wrote:
>
>
>
> On 10/20/26 7:58 PM, Muchun Song wrote:
>> VMEMMAP_SPLIT_NO_TLB_FLUSH and VMEMMAP_REMAP_NO_TLB_FLUSH do not
>> describe fully independent choices. A split-only walk can defer the
>> PMD-split flush to a later global flush, and a remap-only walk can
>> defer the final remap flush. However, when a PMD split is followed
>> by PTE remapping, the split flush must happen before the PTEs are
>> changed, because stale large-page translations must not overlap with
>> new small-page translations that map different physical pages.
>> Replace the two flags with a single VMEMMAP_REMAP_NO_TLB_FLUSH flag.
>> Keep split-only walks able to defer the flush, but force the split
>> flush whenever a remap_pte callback is present. Callers that batch
>> HVO work can still defer the final remap flush and issue their own
>> global flush.
>> Current callers keep the same flushing behavior.
>> Signed-off-by: Muchun Song <songmuchun@xxxxxxxxxxxxx>
>> ---
>> mm/hugetlb_vmemmap.c | 15 +++++++++------
>> 1 file changed, 9 insertions(+), 6 deletions(-)
>> diff --git a/mm/hugetlb_vmemmap.c b/mm/hugetlb_vmemmap.c
>> index 1105aa925acc..8b3abb562599 100644
>> --- a/mm/hugetlb_vmemmap.c
>> +++ b/mm/hugetlb_vmemmap.c
>> @@ -42,10 +42,8 @@ struct vmemmap_remap_walk {
>> struct list_head *vmemmap_pages;
>> -/* Skip the TLB flush when we split the PMD */
>> -#define VMEMMAP_SPLIT_NO_TLB_FLUSH BIT(0)
>> -/* Skip the TLB flush when we remap the PTE */
>> -#define VMEMMAP_REMAP_NO_TLB_FLUSH BIT(1)
>> +/* Skip the TLB flush while updating the vmemmap page tables. */
>> +#define VMEMMAP_REMAP_NO_TLB_FLUSH BIT(0)
>
> Since this flag is now also used by the split-only path, the
> VMEMMAP_REMAP_NO_TLB_FLUSH name is somewhat misleading. Moreover, the
> flag does not suppress every TLB flush, as the PMD-split flush is still
> mandatory when remapping follows.

Yeah, good point.

>
> Would VMEMMAP_DEFER_TLB_FLUSH better describe its semantics? It

I think so.

> indicates that flushes which can be safely batched are deferred, without
> implying that all TLB flushes are skipped.

I'll change it along side with the comment to:

/* Defer safely batchable TLB flushes to the caller. */
#define VMEMMAP_DEFER_TLB_FLUSH BIT(0)

Thanks.

>
> Thanks,
> Qi
>
>> unsigned long flags;
>> };
>> @@ -85,7 +83,12 @@ 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);
>> - if (!(walk->flags & VMEMMAP_SPLIT_NO_TLB_FLUSH))
>> + /*
>> + * Modern MMUs allow overlapping TLB entries with different mapping
>> + * granularities only if they map the same physical address. So
>> + * remapping must not proceed without first flushing the TLB.
>> + */
>> + if (walk->remap_pte || !(walk->flags & VMEMMAP_REMAP_NO_TLB_FLUSH))
>> flush_tlb_kernel_range(start, start + PMD_SIZE);
>> } else {
>> pte_free_kernel(&init_mm, pgtable);
>> @@ -272,7 +275,7 @@ static int vmemmap_remap_split(unsigned long start, unsigned long end)
>> {
>> struct vmemmap_remap_walk walk = {
>> .remap_pte = NULL,
>> - .flags = VMEMMAP_SPLIT_NO_TLB_FLUSH,
>> + .flags = VMEMMAP_REMAP_NO_TLB_FLUSH,
>> };
>> return vmemmap_remap_range(start, end, &walk);
>