* [PATCH v3 0/5] x86/mm: Allow preemption while waiting for kernel TLB flushes
@ 2026-10-12 3:41 Chuyi Zhou
2026-10-12 3:41 ` [PATCH v3 1/5] x86/mm: Account for remote kernel TLB flush requests Chuyi Zhou
` (5 more replies)
0 siblings, 6 replies; 7+ messages in thread
From: Chuyi Zhou @ 2026-10-12 3:41 UTC (permalink / raw)
To: tglx, mingo, luto, peterz, paulmck, muchun.song, bp, dave.hansen,
pbonzini, bigeasy, clrkwllms, rostedt, nadav.amit
Cc: linux-kernel, Chuyi Zhou
Changes in v3:
- Patch 4: Retain struct flush_tlb_info in the kernel range helpers and
initialize start/end directly, keeping the shared descriptor for
future consolidation of the kernel and user paths (Nadav).
v2: https://lore.kernel.org/cover.1791179421.git.zhouchuyi@bytedance.com/
Changes in v2:
- Patch 2: Reuse flush_tlb_all() for kernel ranges promoted to a full
flush and remove kernel_tlb_flush_all() (Sebastian).
- Patch 4: Drop the explicit TLB_FLUSH_ALL check on the end argument.
Callers pass actual address ranges and can use flush_tlb_all() for
unconditional full flushes (Sebastian).
v1: https://lore.kernel.org/20260921095359.3784458-1-zhouchuyi@bytedance.com/
This series follows up on the IPI completion preemption work [1] and
addresses the deferred flush_tlb_kernel_range() changes. The generic SMP
completion waits are already preemptible, and commit a5a162fe1ae1
("x86/mm: Re-enable preemption before flush_tlb_multi()") allows the mm
flush paths to use them. The kernel-range change was deferred during
review [2].
Container teardown and BPF map destruction can trigger kernel TLB
flushes through reclamation of unused per-CPU memory. Services that
spawn and reap many workers can also trigger flushes when vmalloc-backed
kernel stacks are reclaimed.
On the IPI backend, flush_tlb_kernel_range() flushes the local CPU,
sends flush requests to all other online CPUs, and waits synchronously
for completion. The target set is system-wide even when the container
or application is confined to a small subset of CPUs.
The synchronous wait can become longer as the number of online CPUs
grows. Completion depends on the slowest participating CPU, so a remote
CPU with interrupts disabled can delay the entire operation.
flush_tlb_kernel_range() keeps preemption disabled throughout that wait,
delaying higher-priority tasks on the initiating CPU.
The kernel path still uses init_flush_tlb_info(), which initializes
initiating_cpu with smp_processor_id(). Simply removing the outer
preemption guard would allow that initialization to run in a preemptible
context and could trigger a CONFIG_DEBUG_PREEMPT warning. An earlier
revision of the IPI preemption work used raw_smp_processor_id() to
suppress that warning, but this also removed the CPU-pinning check from
the shared initializer used by the mm paths.
The kernel callbacks consume only start and end. This series initializes
those fields directly in struct flush_tlb_info and selects full or range
flushes with the shared threshold predicate. This removes the unused
initiating_cpu initialization while retaining the shared descriptor for
future consolidation of the kernel and user TLB invalidation paths.
The smp_processor_id() check remains in the initializer for the mm paths.
Removing the outer preemption guard then lets higher-priority tasks
preempt the final IPI completion wait when the calling context permits
it. Both flush backends remain synchronous, and the INVLPGB helpers
keep their required preemption protection.
The changes are split into five patches:
1. Account for kernel TLB flush requests in NR_TLB_REMOTE_FLUSH,
including ranges promoted to full flushes and both IPI and INVLPGB
backends.
2. Remove kernel_tlb_flush_all() and use flush_tlb_all() for kernel
ranges promoted to a full flush, sharing backend dispatch and
accounting while counting each request once.
3. Extract the range-to-full-flush threshold predicate without changing
its arithmetic or the existing flush policy.
4. Initialize start/end directly in struct flush_tlb_info for kernel
range flushes and use the shared threshold predicate to select full
or range flushes. Keep the outer preemption guard and the existing
kernel helper interfaces.
5. Remove the outer preemption guard from flush_tlb_kernel_range().
Keep the INVLPGB range loop and TLBSYNC protected inside their
backend helper; the full INVLPGB helper already has that protection.
[1] https://lore.kernel.org/lkml/20260709122933.4021501-1-zhouchuyi@bytedance.com/
[2] https://lore.kernel.org/9cd743e8-4d60-4a5b-906f-07e4ae82dafb@bytedance.com/
Chuyi Zhou (5):
x86/mm: Account for remote kernel TLB flush requests
x86/mm: Share the full TLB flush dispatch
x86/mm: Extract the TLB range flush threshold check
x86/mm: Initialize kernel TLB flush requests directly
x86/mm: Re-enable preemption before waiting for kernel TLB flushes
arch/x86/mm/tlb.c | 34 ++++++++++++++++++----------------
1 file changed, 18 insertions(+), 16 deletions(-)
base-commit: e81ee06308379a5f2ededf997bcf17551bce5db7
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 1/5] x86/mm: Account for remote kernel TLB flush requests
2026-10-12 3:41 [PATCH v3 0/5] x86/mm: Allow preemption while waiting for kernel TLB flushes Chuyi Zhou
@ 2026-10-12 3:41 ` Chuyi Zhou
2026-10-12 3:41 ` [PATCH v3 2/5] x86/mm: Share the full TLB flush dispatch Chuyi Zhou
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Chuyi Zhou @ 2026-10-12 3:41 UTC (permalink / raw)
To: tglx, mingo, luto, peterz, paulmck, muchun.song, bp, dave.hansen,
pbonzini, bigeasy, clrkwllms, rostedt, nadav.amit
Cc: linux-kernel, Chuyi Zhou
NR_TLB_REMOTE_FLUSH counts requests to invalidate TLB entries on other
CPUs. flush_tlb_all() and native_flush_tlb_multi() account for these
requests, but flush_tlb_kernel_range() bypasses both functions and does
not update the counter. Kernel range flushes are therefore missing from
the sender-side statistics, including ranges promoted to a full flush.
Count each request in kernel_tlb_flush_all() and
kernel_tlb_flush_range(). Account for both IPI and INVLPGB backends, as
flush_tlb_all() already does, and count once per request regardless of
the number of target CPUs or invalidation instructions.
Signed-off-by: Chuyi Zhou <zhouchuyi@bytedance.com>
---
arch/x86/mm/tlb.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
index 0c4da320831c..da7c408f921c 100644
--- a/arch/x86/mm/tlb.c
+++ b/arch/x86/mm/tlb.c
@@ -1488,6 +1488,8 @@ static void do_kernel_range_flush(void *info)
static void kernel_tlb_flush_all(struct flush_tlb_info *info)
{
+ count_vm_tlb_event(NR_TLB_REMOTE_FLUSH);
+
if (cpu_feature_enabled(X86_FEATURE_INVLPGB))
invlpgb_flush_all();
else
@@ -1496,6 +1498,8 @@ static void kernel_tlb_flush_all(struct flush_tlb_info *info)
static void kernel_tlb_flush_range(struct flush_tlb_info *info)
{
+ count_vm_tlb_event(NR_TLB_REMOTE_FLUSH);
+
if (cpu_feature_enabled(X86_FEATURE_INVLPGB))
invlpgb_kernel_range_flush(info);
else
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 2/5] x86/mm: Share the full TLB flush dispatch
2026-10-12 3:41 [PATCH v3 0/5] x86/mm: Allow preemption while waiting for kernel TLB flushes Chuyi Zhou
2026-10-12 3:41 ` [PATCH v3 1/5] x86/mm: Account for remote kernel TLB flush requests Chuyi Zhou
@ 2026-10-12 3:41 ` Chuyi Zhou
2026-10-12 3:41 ` [PATCH v3 3/5] x86/mm: Extract the TLB range flush threshold check Chuyi Zhou
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Chuyi Zhou @ 2026-10-12 3:41 UTC (permalink / raw)
To: tglx, mingo, luto, peterz, paulmck, muchun.song, bp, dave.hansen,
pbonzini, bigeasy, clrkwllms, rostedt, nadav.amit
Cc: linux-kernel, Chuyi Zhou
flush_tlb_all() and kernel_tlb_flush_all() select the same INVLPGB or
IPI backend and account for the same sender-side event. Keeping two
implementations duplicates the backend selection and accounting.
Use flush_tlb_all() for kernel ranges promoted to a full flush and
remove kernel_tlb_flush_all(). Share the existing backend dispatch and
event accounting so each request is counted once.
Signed-off-by: Chuyi Zhou <zhouchuyi@bytedance.com>
---
arch/x86/mm/tlb.c | 12 +-----------
1 file changed, 1 insertion(+), 11 deletions(-)
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
index da7c408f921c..5a1b96c61050 100644
--- a/arch/x86/mm/tlb.c
+++ b/arch/x86/mm/tlb.c
@@ -1486,16 +1486,6 @@ static void do_kernel_range_flush(void *info)
flush_tlb_one_kernel(addr);
}
-static void kernel_tlb_flush_all(struct flush_tlb_info *info)
-{
- count_vm_tlb_event(NR_TLB_REMOTE_FLUSH);
-
- if (cpu_feature_enabled(X86_FEATURE_INVLPGB))
- invlpgb_flush_all();
- else
- on_each_cpu(do_flush_tlb_all, NULL, 1);
-}
-
static void kernel_tlb_flush_range(struct flush_tlb_info *info)
{
count_vm_tlb_event(NR_TLB_REMOTE_FLUSH);
@@ -1515,7 +1505,7 @@ void flush_tlb_kernel_range(unsigned long start, unsigned long end)
TLB_GENERATION_INVALID);
if (info.end == TLB_FLUSH_ALL)
- kernel_tlb_flush_all(&info);
+ flush_tlb_all();
else
kernel_tlb_flush_range(&info);
}
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 3/5] x86/mm: Extract the TLB range flush threshold check
2026-10-12 3:41 [PATCH v3 0/5] x86/mm: Allow preemption while waiting for kernel TLB flushes Chuyi Zhou
2026-10-12 3:41 ` [PATCH v3 1/5] x86/mm: Account for remote kernel TLB flush requests Chuyi Zhou
2026-10-12 3:41 ` [PATCH v3 2/5] x86/mm: Share the full TLB flush dispatch Chuyi Zhou
@ 2026-10-12 3:41 ` Chuyi Zhou
2026-10-12 3:41 ` [PATCH v3 4/5] x86/mm: Initialize kernel TLB flush requests directly Chuyi Zhou
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Chuyi Zhou @ 2026-10-12 3:41 UTC (permalink / raw)
To: tglx, mingo, luto, peterz, paulmck, muchun.song, bp, dave.hansen,
pbonzini, bigeasy, clrkwllms, rostedt, nadav.amit
Cc: linux-kernel, Chuyi Zhou
The decision to replace a range flush with a full flush is embedded in
init_flush_tlb_info(). Both mm and kernel flushes use this policy, but
the kernel path only needs the range and the decision, without the
mm-specific descriptor initialization.
Extract the threshold predicate into tlb_range_exceeds_ceiling()
and use it in init_flush_tlb_info(). Preserve the unsigned range
arithmetic, right-shift rounding and strict greater-than comparison.
Descriptor initialization and both flush paths remain unchanged.
Signed-off-by: Chuyi Zhou <zhouchuyi@bytedance.com>
---
arch/x86/mm/tlb.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
index 5a1b96c61050..0d03011c6825 100644
--- a/arch/x86/mm/tlb.c
+++ b/arch/x86/mm/tlb.c
@@ -1373,6 +1373,12 @@ void flush_tlb_multi(const struct cpumask *cpumask,
*/
unsigned long tlb_single_page_flush_ceiling __read_mostly = 33;
+static bool tlb_range_exceeds_ceiling(unsigned long start, unsigned long end,
+ unsigned int stride_shift)
+{
+ return ((end - start) >> stride_shift) > tlb_single_page_flush_ceiling;
+}
+
static void init_flush_tlb_info(struct flush_tlb_info *info,
struct mm_struct *mm,
unsigned long start, unsigned long end,
@@ -1383,7 +1389,7 @@ static void init_flush_tlb_info(struct flush_tlb_info *info,
* If the number of flushes is so large that a full flush
* would be faster, do a full flush.
*/
- if ((end - start) >> stride_shift > tlb_single_page_flush_ceiling) {
+ if (tlb_range_exceeds_ceiling(start, end, stride_shift)) {
start = 0;
end = TLB_FLUSH_ALL;
}
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 4/5] x86/mm: Initialize kernel TLB flush requests directly
2026-10-12 3:41 [PATCH v3 0/5] x86/mm: Allow preemption while waiting for kernel TLB flushes Chuyi Zhou
` (2 preceding siblings ...)
2026-10-12 3:41 ` [PATCH v3 3/5] x86/mm: Extract the TLB range flush threshold check Chuyi Zhou
@ 2026-10-12 3:41 ` Chuyi Zhou
2026-10-12 3:41 ` [PATCH v3 5/5] x86/mm: Re-enable preemption before waiting for kernel TLB flushes Chuyi Zhou
2026-10-14 15:38 ` [PATCH v3 0/5] x86/mm: Allow preemption while " Sebastian Andrzej Siewior
5 siblings, 0 replies; 7+ messages in thread
From: Chuyi Zhou @ 2026-10-12 3:41 UTC (permalink / raw)
To: tglx, mingo, luto, peterz, paulmck, muchun.song, bp, dave.hansen,
pbonzini, bigeasy, clrkwllms, rostedt, nadav.amit
Cc: linux-kernel, Chuyi Zhou
flush_tlb_kernel_range() uses init_flush_tlb_info(), which records
initiating_cpu with smp_processor_id(). The kernel flush callbacks do
not use this field, but initializing it in a preemptible context would
trigger the CPU-pinning check.
Prepare for allowing preemption during the IPI completion wait by
initializing start and end directly in struct flush_tlb_info and using
the shared threshold predicate to select full or range flushes. Keep the
outer preemption guard unchanged.
Signed-off-by: Chuyi Zhou <zhouchuyi@bytedance.com>
Link: https://lore.kernel.org/20260522104818.CbT5fyN8@linutronix.de/
---
arch/x86/mm/tlb.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
index 0d03011c6825..2213f1a6f9e1 100644
--- a/arch/x86/mm/tlb.c
+++ b/arch/x86/mm/tlb.c
@@ -1504,13 +1504,14 @@ static void kernel_tlb_flush_range(struct flush_tlb_info *info)
void flush_tlb_kernel_range(unsigned long start, unsigned long end)
{
- struct flush_tlb_info info;
+ struct flush_tlb_info info = {
+ .start = start,
+ .end = end,
+ };
guard(preempt)();
- init_flush_tlb_info(&info, NULL, start, end, PAGE_SHIFT, false,
- TLB_GENERATION_INVALID);
- if (info.end == TLB_FLUSH_ALL)
+ if (tlb_range_exceeds_ceiling(start, end, PAGE_SHIFT))
flush_tlb_all();
else
kernel_tlb_flush_range(&info);
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 5/5] x86/mm: Re-enable preemption before waiting for kernel TLB flushes
2026-10-12 3:41 [PATCH v3 0/5] x86/mm: Allow preemption while waiting for kernel TLB flushes Chuyi Zhou
` (3 preceding siblings ...)
2026-10-12 3:41 ` [PATCH v3 4/5] x86/mm: Initialize kernel TLB flush requests directly Chuyi Zhou
@ 2026-10-12 3:41 ` Chuyi Zhou
2026-10-14 15:38 ` [PATCH v3 0/5] x86/mm: Allow preemption while " Sebastian Andrzej Siewior
5 siblings, 0 replies; 7+ messages in thread
From: Chuyi Zhou @ 2026-10-12 3:41 UTC (permalink / raw)
To: tglx, mingo, luto, peterz, paulmck, muchun.song, bp, dave.hansen,
pbonzini, bigeasy, clrkwllms, rostedt, nadav.amit
Cc: linux-kernel, Chuyi Zhou
flush_tlb_kernel_range() uses on_each_cpu() to synchronously flush
kernel mappings on all online CPUs when using the IPI backend.
The synchronous wait can become longer as the number of online CPUs
grows, and a remote CPU with interrupts disabled can further delay
completion. Preemption remains disabled throughout this wait, delaying
higher-priority tasks on the initiating CPU. The outer guard prevents
the SMP layer from making its final completion wait preemptible.
The flush_tlb_info descriptor is allocated on the caller's stack and
remains valid until on_each_cpu() returns. The SMP layer protects CPU
selection, IPI queueing and local callback execution, so the kernel
flush caller does not need to remain pinned while waiting for remote
completion.
INVLPGB requires separate protection: TLBSYNC only waits for operations
issued on the same CPU. Disable preemption inside
invlpgb_kernel_range_flush() across the broadcast loop and TLBSYNC.
The full-flush helper invlpgb_flush_all() already provides this
protection.
Remove the outer preemption guard from flush_tlb_kernel_range() so the
IPI completion wait can be preempted when the caller's context allows
it. Keep both flush backends synchronous.
Signed-off-by: Chuyi Zhou <zhouchuyi@bytedance.com>
---
arch/x86/mm/tlb.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
index 2213f1a6f9e1..0deec9e664b8 100644
--- a/arch/x86/mm/tlb.c
+++ b/arch/x86/mm/tlb.c
@@ -1468,6 +1468,9 @@ static void invlpgb_kernel_range_flush(struct flush_tlb_info *info)
{
unsigned long addr, nr;
+ /* Keep the INVLPGB operations and TLBSYNC on the same CPU. */
+ guard(preempt)();
+
for (addr = info->start; addr < info->end; addr += nr << PAGE_SHIFT) {
nr = (info->end - addr) >> PAGE_SHIFT;
@@ -1509,8 +1512,6 @@ void flush_tlb_kernel_range(unsigned long start, unsigned long end)
.end = end,
};
- guard(preempt)();
-
if (tlb_range_exceeds_ceiling(start, end, PAGE_SHIFT))
flush_tlb_all();
else
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v3 0/5] x86/mm: Allow preemption while waiting for kernel TLB flushes
2026-10-12 3:41 [PATCH v3 0/5] x86/mm: Allow preemption while waiting for kernel TLB flushes Chuyi Zhou
` (4 preceding siblings ...)
2026-10-12 3:41 ` [PATCH v3 5/5] x86/mm: Re-enable preemption before waiting for kernel TLB flushes Chuyi Zhou
@ 2026-10-14 15:38 ` Sebastian Andrzej Siewior
5 siblings, 0 replies; 7+ messages in thread
From: Sebastian Andrzej Siewior @ 2026-10-14 15:38 UTC (permalink / raw)
To: Chuyi Zhou
Cc: tglx, mingo, luto, peterz, paulmck, muchun.song, bp, dave.hansen,
pbonzini, clrkwllms, rostedt, nadav.amit, linux-kernel
On 2026-10-12 11:41:20 [+0800], Chuyi Zhou wrote:
> Changes in v3:
> - Patch 4: Retain struct flush_tlb_info in the kernel range helpers and
> initialize start/end directly, keeping the shared descriptor for
> future consolidation of the kernel and user paths (Nadav).
>
> v2: https://lore.kernel.org/cover.1791179421.git.zhouchuyi@bytedance.com/
I did prefer the v2 simply because now only ->start and ->end of struct
flush_tlb_info is initialized and the other fields are not. This is not
used by kernel_tlb_flush_range() (and lower) as of today but who knows…
Anyway, I am not calling the shots here. From the clean up point of view
it looks good to me, so
Reviewed-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Sebastian
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-10-14 15:38 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-12 3:41 [PATCH v3 0/5] x86/mm: Allow preemption while waiting for kernel TLB flushes Chuyi Zhou
2026-10-12 3:41 ` [PATCH v3 1/5] x86/mm: Account for remote kernel TLB flush requests Chuyi Zhou
2026-10-12 3:41 ` [PATCH v3 2/5] x86/mm: Share the full TLB flush dispatch Chuyi Zhou
2026-10-12 3:41 ` [PATCH v3 3/5] x86/mm: Extract the TLB range flush threshold check Chuyi Zhou
2026-10-12 3:41 ` [PATCH v3 4/5] x86/mm: Initialize kernel TLB flush requests directly Chuyi Zhou
2026-10-12 3:41 ` [PATCH v3 5/5] x86/mm: Re-enable preemption before waiting for kernel TLB flushes Chuyi Zhou
2026-10-14 15:38 ` [PATCH v3 0/5] x86/mm: Allow preemption while " Sebastian Andrzej Siewior
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®