On Wed, May 24, 2023 at 1:18 PM Nicholas Piggin <npiggin@xxxxxxxxx> wrote: > > mm_cpumask is a map of the CPUs which must be IPIed to flush TLBs, > and/or IPIed to shootdown lazy TLB mms at exit time. > > When flushing TLBs on the CPU, trim it from mm_cpumask if the mm is not > currently active on the CPU. TLBs will have been flush, and the mm is > not active, so there is no more reason to get IPIs. > > Signed-off-by: Nicholas Piggin <npiggin@xxxxxxxxx> > --- > arch/alpha/include/asm/tlbflush.h | 3 +++ > arch/alpha/kernel/smp.c | 29 +++++++++++++++++++++++++++-- > 2 files changed, 30 insertions(+), 2 deletions(-) > > diff --git a/arch/alpha/include/asm/tlbflush.h b/arch/alpha/include/asm/tlbflush.h > index 94dc37cf873a..7c4e719ac9e7 100644 > --- a/arch/alpha/include/asm/tlbflush.h > +++ b/arch/alpha/include/asm/tlbflush.h > @@ -12,6 +12,7 @@ > #endif > > extern void __load_new_mm_context(struct mm_struct *); > +extern void try_clear_mm_cpumask(struct mm_struct *); > > > /* Use a few helper functions to hide the ugly broken ASN > @@ -106,6 +107,7 @@ static inline void flush_tlb_all(void) > static inline void > flush_tlb_mm(struct mm_struct *mm) > { > + try_clear_mm_cpumask(mm); > if (mm == current->active_mm) > flush_tlb_current(mm); > else > @@ -118,6 +120,7 @@ flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) > { > struct mm_struct *mm = vma->vm_mm; > > + try_clear_mm_cpumask(mm); > if (mm == current->active_mm) > flush_tlb_current_page(mm, vma, addr); > else > diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c > index e436c056267d..d668b9d319af 100644 > --- a/arch/alpha/kernel/smp.c > +++ b/arch/alpha/kernel/smp.c > @@ -610,6 +610,28 @@ smp_imb(void) > } > EXPORT_SYMBOL(smp_imb); > > +#define asn_locked() (cpu_data[smp_processor_id()].asn_lock) > + > +/* > + * If the mm_cpumask bit is cleared, the caller *must* flush the TLB for the > + * mm on this CPU. It is only cleared when the mm is not active, in which > + * case the flushing always performs flush_tlb_other that flushes everything. > + * If that changes in callers, they will have to arrange to always do a full > + * flush if mm_cpumask is cleared by this function. > + */ > +void > +try_clear_mm_cpumask(struct mm_struct *mm) > +{ > + int cpu; > + > + if (current->active_mm == mm || asn_locked()) > + return; > + > + cpu = smp_processor_id(); > + if (cpumask_test_cpu(cpu, mm_cpumask(mm))) > + cpumask_clear_cpu(cpu, mm_cpumask(mm)); > +} Since this is implemented in smp.c, the function is not available in !CONFIG_SMP: ld: kernel/fork.o: in function `dup_mmap': (.text+0x1734): undefined reference to `try_clear_mm_cpumask' ld: (.text+0x1738): undefined reference to `try_clear_mm_cpumask' ld: mm/memory.o: in function `unmap_page_range': (.text+0x1934): undefined reference to `try_clear_mm_cpumask' ld: (.text+0x193c): undefined reference to `try_clear_mm_cpumask' ld: (.text+0x1a28): undefined reference to `try_clear_mm_cpumask' ld: mm/memory.o:(.text+0x1a30): more undefined references to `try_clear_mm_cpumask' follow make[1]: *** [scripts/Makefile.vmlinux:35: vmlinux] Error 1 make: *** [Makefile:1249: vmlinux] Error 2