TLB Shootdowns Extend Page-Table Changes Across CPUs

Changing a page-table entry in memory does not by itself retire every translation derived from that entry. A CPU that previously used the mapping can retain it in a translation lookaside buffer, or TLB. On a multiprocessor system, other CPUs may hold their own cached copies, so a mapping change can require coordination beyond the CPU that modified the page table.

Linux exposes this distinction through its TLB-flush interfaces. After page-table state changes, architecture code must make the affected translations unusable on every relevant CPU before software relies on the new mapping or releases memory that the old mapping could reach.

Page tables and TLBs are separate state

A page table is memory-resident translation state managed by the operating system. A TLB is processor-local cache state derived from those tables. A page-table write changes the authoritative mapping, but an existing TLB entry can continue supplying the earlier translation until the architecture-defined invalidation takes effect.

The logical state can look like this:

page table:
virtual page V -> physical page B

CPU 0 TLB:
V -> B

CPU 1 TLB:
V -> A   <- stale

CPU 2 TLB:
no entry

CPU 2 will obtain a translation through the normal translation mechanism when it next accesses V. CPU 1 is different: if its stale entry remains valid, it can continue reaching page A even though memory now records page B.

This is a translation-coherency problem. It is separate from data-cache coherency. A cache-coherent machine can keep ordinary loads and stores coherent while still requiring explicit architectural operations to retire stale address translations.

Local invalidation does not cover a remote TLB

An invalidation instruction normally acts on translation state associated with the logical processor executing it, subject to the architecture’s defined scope. On x86, for example, INVLPG invalidates entries for the page containing its operand on the executing logical processor, with details involving PCIDs and global mappings defined by the architecture.

That local action is insufficient when the same address space has run on another CPU that can still retain a matching entry. The operating system must arrange for relevant remote processors to perform the required invalidation or use another architecture-supported mechanism with equivalent scope.

The coordination is commonly called a TLB shootdown:

CPU 0 changes mapping
        |
        v
identify CPUs that may cache it
        |
        v
send invalidation requests
        |
        +------> CPU 1 invalidates
        |
        +------> CPU 3 invalidates
        |
        v
wait for required completion
        |
        v
old translation is no longer usable

The exact mechanism is architecture- and kernel-specific. Inter-processor interrupts are a common implementation technique, but the correctness property is broader than any single signaling method: CPUs that may use stale translation state must be brought past the required invalidation point.

CPU tracking limits the shootdown scope

Sending an invalidation request to every CPU would be correct in many situations but unnecessarily broad. Kernels track which processors can have translation state for an address space and use that information to restrict remote work.

This tracking is an operating-system policy layered over architectural invalidation primitives. It can exploit facts such as whether an address space has executed on a CPU, whether a CPU is currently using it, and whether previously cached state has already been retired.

The optimization cannot weaken the lifetime rule. A CPU omitted from a shootdown must be unable to use a stale entry that conflicts with the page-table change. The kernel’s bookkeeping therefore participates directly in correctness, even though the processor architecture does not prescribe Linux’s data structures or scheduling policy.

Flush range changes the cost profile

Linux provides TLB interfaces with different scopes, including whole-address-space, range, and page-level flushing. Architecture code maps those interfaces onto available processor mechanisms.

A narrow invalidation can preserve unrelated TLB entries, reducing collateral loss of cached translations. A broad flush can require fewer invalidation operations when a large region changes. Linux x86 documentation explicitly describes this trade-off: individual page invalidation avoids discarding unrelated entries, while a full flush can be cheaper than issuing many page-specific invalidations.

No fixed threshold is portable. TLB organization, invalidation instructions, PCID or address-space tagging, kernel heuristics, and the size of the changed range all affect the decision. A measured result on one processor model is not an architectural guarantee for another.

The performance cost also has two parts. There is direct coordination work, such as requesting and completing remote invalidation, and there is refill work after useful TLB entries have been discarded. These costs depend on workload and implementation, so the existence of a shootdown does not imply a specific latency penalty.

Address-space tags reduce unrelated invalidation

Modern processors can associate cached translations with an address-space identifier. On x86, PCIDs allow TLB entries from different address spaces to coexist across some page-table switches. Other architectures provide comparable tagging mechanisms under different names and rules.

Tags reduce the need to discard translations merely because execution switches between address spaces. They do not remove the need to invalidate an entry whose mapping has actually changed. Instead, they make invalidation scope more precise: software can target translation state associated with a particular address space when the architecture provides the necessary operation.

Linux can also defer some invalidation work until a CPU next returns to an affected address space. Such deferral is safe only when the CPU cannot consume the stale translation before the deferred flush occurs. This is an implementation strategy built around the same architectural boundary, not an exemption from it.

Memory reuse makes completion a lifetime requirement

The strongest correctness requirement appears when an old physical page is about to be reused. Suppose virtual page V once mapped page A. Software removes that mapping, returns page A to an allocator, and another subsystem assigns page A to unrelated data.

If a remote CPU can still translate V to page A, the stale mapping has crossed an ownership boundary. A later load or store through V can access memory that no longer belongs to the old mapping.

For that reason, page-table removal, TLB invalidation, and memory reclamation form an ordered lifetime sequence:

remove or replace mapping
        |
retire affected cached translations
        |
establish required completion
        |
release or repurpose old backing memory

Kernel implementations can batch or defer portions of this work when their invariants allow it, but they must preserve the point at which reuse becomes safe.

Translation invalidation is not a generic memory barrier

A CPU memory barrier constrains ordering or visibility according to the architecture’s memory model. It does not generically invalidate TLB entries. Likewise, invalidating a TLB entry does not substitute for data-cache maintenance on systems that require explicit cache operations.

These mechanisms protect different forms of state. Page-table synchronization governs address translation. Memory barriers govern ordering relationships. Cache maintenance governs data visibility where hardware coherency does not provide it automatically.

Keeping those boundaries separate matters in low-level code. A page-table store can be globally visible as data while another CPU still has a valid cached translation derived from the old entry. The mapping transition is complete only after the architecture and operating system have satisfied the required translation invalidation contract.