Re: [PATCH 1/1] x86/mm: fix incomplete page-table invalidation with TCE

From: Lance Yang

Date: Mon Oct 05 2026 - 08:13:50 EST




On 2026/10/5 18:24, Pedro Falcato wrote:
On Mon, Oct 05, 2026 at 03:29:22PM +0800, Lance Yang wrote:


On 2026/10/5 14:09, Pedro Falcato wrote:
On Mon, Oct 05, 2026 at 01:23:02PM +0800, Lance Yang wrote:
pud_free_pmd_page() uses a single-address invalidation to flush the
paging-structure caches before freeing the page tables. With AMD TCE
enabled, this only invalidates upper-level entries associated with the
target address. Cached PMD entries for other addresses in the PUD range can
still reference the PTE pages being freed.

The AMD manual quoted in the commit enabling TCE says these instructions
remove

"only those upper-level entries that lead to the target PTE in the page
table hierarchy, leaving unrelated upper-level entries intact."

Even with all PTEs cleared, speculative page walks can cache present PMD
entries after the earlier TLB purge.

Use a full TLB flush before freeing the page tables on CPUs with TCE. Keep
the single-address invalidation otherwise.

Fixes: 440a65b7d25f ("x86/mm: Enable AMD translation cache extensions")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Lance Yang <lance.yang@xxxxxxxxx>

I'm not sure this is correct. The PUD is clear. We invalidate the TLB, which
invalidates the translation caches for that walk. invlpg will notice the PUD
isn't present. I don't see a case where it can ever not clear the rest
of the translation caches for all leaves. And, in fact, by that point the CPU
can (does?) probably formally treat the PUD as the leaf.

IIUC, clearing the PUD in memory doesn't invalidate cached PMD entries by
itself. With TCE enabled, flushing one address only invalidates the entries
associated with that address ...

(That's how I read the manual, but AMD folks, please correct me if I'm
missing something.)

So couldn't other cached PMDs under the same PUD survive?

I don't read it as that. I read it as "flushing one address only invalidates
the entries on that path". So, if you flush one address, you'll flush the
whole translation cache for that range. And page table zapping agrees; if you
follow the code from zap_pte_range() -> pte_free_tlb(), it will do a single flush
for each PTE table (if the whole table is empty/non-present).

Let's wait for AMD folks to clarify whether a single-address flush is
sufficient :)