On 7/14/26 07:04, Kevin Brodsky wrote:
...
> @@ -188,7 +188,7 @@ DECLARE_PER_CPU_SHARED_ALIGNED(struct tlb_state_shared,
> cpu_tlbstate_shared);
> #define enter_lazy_tlb enter_lazy_tlb
> static __always_inline void enter_lazy_tlb(struct mm_struct *mm, struct
> task_struct *tsk)
> {
> - if (this_cpu_read(cpu_tlbstate.loaded_mm) == &init_mm)
> + if (mm_is_kernel(this_cpu_read(cpu_tlbstate.loaded_mm)))
> return;
>
> this_cpu_write(cpu_tlbstate_shared.is_lazy, true);
This one makes me nervous, especially combined with the efi_mm changes
later in the series. init_mm really is special. Before this patch,
running on init_mm qualifies as being in lazy tlb mode. After this
patch, efi_mm qualifies too.
Is that OK?
> diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c
> index f32facdb3035..91d2a6f2ac5a 100644
> --- a/arch/x86/mm/pgtable.c
> +++ b/arch/x86/mm/pgtable.c
> @@ -168,7 +168,7 @@ static int preallocate_pmds(struct mm_struct *mm, pmd_t
> *pmds[], int count)
> bool failed = false;
> gfp_t gfp = GFP_PGTABLE_USER;
>
> - if (mm == &init_mm)
> + if (mm_is_kernel(mm))
> gfp &= ~__GFP_ACCOUNT;
> gfp &= ~__GFP_HIGHMEM;
This hunk is probably fine.
> diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
> index 1023acadd8f8..5517cab8ad00 100644
> --- a/arch/x86/mm/tlb.c
> +++ b/arch/x86/mm/tlb.c
> @@ -594,7 +594,7 @@ void leave_mm(void)
> * This needs to happen before any other sanity checks due to
> * intel_idle's shenanigans.
> */
> - if (loaded_mm == &init_mm)
> + if (mm_is_kernel(loaded_mm))
> return;
This one is almost *certainly* buggy.
The efi_mm stuff uses leave_mm(). In fact, I think it's what's
responsible for switching the hardware back over to use the init_mm page
tables. If this check trips for init_mm, then the kernel will stay
running on efi_mm when it's not intended to.
Remember when I asked about whether there was going to be *a* kernel mm
or lots? This is where it starts to matter. It's outside the diff
context but the code here is basically:
if (loaded_mm == &init_mm)
return;
switch_mm(NULL, &init_mm, NULL);
So either all kernel mm's are equivalent or this code doesn't quite work.
> /* Warn if we're not lazy. */
> @@ -855,7 +855,7 @@ void switch_mm_irqs_off(struct mm_struct *unused, struct
> mm_struct *next,
> * cpu_tlbstate_shared.is_lazy whether or not to send an IPI.
> */
> if (IS_ENABLED(CONFIG_DEBUG_VM) &&
> - WARN_ON_ONCE(prev != &init_mm && !is_notrack_mm(prev) &&
> + WARN_ON_ONCE(!mm_is_kernel(prev) && !is_notrack_mm(prev) &&
> !cpumask_test_cpu(cpu, mm_cpumask(next))))
> cpumask_set_cpu(cpu, mm_cpumask(next));
>
> @@ -932,7 +932,8 @@ void switch_mm_irqs_off(struct mm_struct *unused, struct
> mm_struct *next,
> * This way switch_mm() must see the new tlb_gen or
> * flush_tlb_mm_range() must see the new loaded_mm, or both.
> */
> - if (next != &init_mm && !cpumask_test_cpu(cpu,
> mm_cpumask(next)))
> + if (!mm_is_kernel(next) &&
> + !cpumask_test_cpu(cpu, mm_cpumask(next)))
> cpumask_set_cpu(cpu, mm_cpumask(next));
> else
> smp_mb();
This one is interesting. It's basically saying that init_mm doesn't get
mm_cpumask() updates. That makes sense since it has special TLB flushing
rules. But what does this mean for efi_mm? Does it needs mm_cpumask()
updates?