Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

lazy tlb: introduce lazy tlb mm refcount helper functions

Add explicit _lazy_tlb annotated functions for lazy tlb mm refcounting.
This makes the lazy tlb mm references more obvious, and allows the
refcounting scheme to be modified in later changes. There is no
functional change with this patch.

Link: https://lkml.kernel.org/r/20230203071837.1136453-3-npiggin@gmail.com
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Nadav Amit <nadav.amit@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rik van Riel <riel@redhat.com>
Cc: Will Deacon <will@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Nicholas Piggin and committed by
Andrew Morton
aa464ba9 6cad87b0

+41 -16
+1 -1
arch/arm/mach-rpc/ecard.c
··· 253 253 current->mm = mm; 254 254 current->active_mm = mm; 255 255 activate_mm(active_mm, mm); 256 - mmdrop(active_mm); 256 + mmdrop_lazy_tlb(active_mm); 257 257 ecard_init_pgtables(mm); 258 258 return 0; 259 259 }
+1 -1
arch/powerpc/kernel/smp.c
··· 1611 1611 if (IS_ENABLED(CONFIG_PPC32)) 1612 1612 setup_kup(); 1613 1613 1614 - mmgrab(&init_mm); 1614 + mmgrab_lazy_tlb(&init_mm); 1615 1615 current->active_mm = &init_mm; 1616 1616 1617 1617 smp_store_cpu_info(cpu);
+2 -2
arch/powerpc/mm/book3s64/radix_tlb.c
··· 797 797 if (current->active_mm == mm) { 798 798 WARN_ON_ONCE(current->mm != NULL); 799 799 /* Is a kernel thread and is using mm as the lazy tlb */ 800 - mmgrab(&init_mm); 800 + mmgrab_lazy_tlb(&init_mm); 801 801 current->active_mm = &init_mm; 802 802 switch_mm_irqs_off(mm, &init_mm, current); 803 - mmdrop(mm); 803 + mmdrop_lazy_tlb(mm); 804 804 } 805 805 806 806 /*
+1 -1
fs/exec.c
··· 1034 1034 mmput(old_mm); 1035 1035 return 0; 1036 1036 } 1037 - mmdrop(active_mm); 1037 + mmdrop_lazy_tlb(active_mm); 1038 1038 return 0; 1039 1039 } 1040 1040
+16
include/linux/sched/mm.h
··· 79 79 } 80 80 #endif 81 81 82 + /* Helpers for lazy TLB mm refcounting */ 83 + static inline void mmgrab_lazy_tlb(struct mm_struct *mm) 84 + { 85 + mmgrab(mm); 86 + } 87 + 88 + static inline void mmdrop_lazy_tlb(struct mm_struct *mm) 89 + { 90 + mmdrop(mm); 91 + } 92 + 93 + static inline void mmdrop_lazy_tlb_sched(struct mm_struct *mm) 94 + { 95 + mmdrop_sched(mm); 96 + } 97 + 82 98 /** 83 99 * mmget() - Pin the address space associated with a &struct mm_struct. 84 100 * @mm: The address space to pin.
+1 -1
kernel/cpu.c
··· 623 623 */ 624 624 if (mm != &init_mm) 625 625 idle->active_mm = &init_mm; 626 - mmdrop(mm); 626 + mmdrop_lazy_tlb(mm); 627 627 return 0; 628 628 } 629 629
+1 -1
kernel/exit.c
··· 537 537 return; 538 538 sync_mm_rss(mm); 539 539 mmap_read_lock(mm); 540 - mmgrab(mm); 540 + mmgrab_lazy_tlb(mm); 541 541 BUG_ON(mm != current->active_mm); 542 542 /* more a memory barrier than a real lock */ 543 543 task_lock(current);
+10 -2
kernel/kthread.c
··· 1415 1415 WARN_ON_ONCE(!(tsk->flags & PF_KTHREAD)); 1416 1416 WARN_ON_ONCE(tsk->mm); 1417 1417 1418 + /* 1419 + * It is possible for mm to be the same as tsk->active_mm, but 1420 + * we must still mmgrab(mm) and mmdrop_lazy_tlb(active_mm), 1421 + * because these references are not equivalent. 1422 + */ 1418 1423 mmgrab(mm); 1419 1424 1420 1425 task_lock(tsk); ··· 1443 1438 * memory barrier after storing to tsk->mm, before accessing 1444 1439 * user-space memory. A full memory barrier for membarrier 1445 1440 * {PRIVATE,GLOBAL}_EXPEDITED is implicitly provided by 1446 - * mmdrop(). 1441 + * mmdrop_lazy_tlb(). 1447 1442 */ 1448 - mmdrop(active_mm); 1443 + mmdrop_lazy_tlb(active_mm); 1449 1444 } 1450 1445 EXPORT_SYMBOL_GPL(kthread_use_mm); 1451 1446 ··· 1473 1468 local_irq_disable(); 1474 1469 tsk->mm = NULL; 1475 1470 membarrier_update_current_mm(NULL); 1471 + mmgrab_lazy_tlb(mm); 1476 1472 /* active_mm is still 'mm' */ 1477 1473 enter_lazy_tlb(mm, tsk); 1478 1474 local_irq_enable(); 1479 1475 task_unlock(tsk); 1476 + 1477 + mmdrop(mm); 1480 1478 } 1481 1479 EXPORT_SYMBOL_GPL(kthread_unuse_mm); 1482 1480
+8 -7
kernel/sched/core.c
··· 5203 5203 * rq->curr, before returning to userspace, so provide them here: 5204 5204 * 5205 5205 * - a full memory barrier for {PRIVATE,GLOBAL}_EXPEDITED, implicitly 5206 - * provided by mmdrop(), 5206 + * provided by mmdrop_lazy_tlb(), 5207 5207 * - a sync_core for SYNC_CORE. 5208 5208 */ 5209 5209 if (mm) { 5210 5210 membarrier_mm_sync_core_before_usermode(mm); 5211 - mmdrop_sched(mm); 5211 + mmdrop_lazy_tlb_sched(mm); 5212 5212 } 5213 + 5213 5214 if (unlikely(prev_state == TASK_DEAD)) { 5214 5215 if (prev->sched_class->task_dead) 5215 5216 prev->sched_class->task_dead(prev); ··· 5267 5266 5268 5267 /* 5269 5268 * kernel -> kernel lazy + transfer active 5270 - * user -> kernel lazy + mmgrab() active 5269 + * user -> kernel lazy + mmgrab_lazy_tlb() active 5271 5270 * 5272 - * kernel -> user switch + mmdrop() active 5271 + * kernel -> user switch + mmdrop_lazy_tlb() active 5273 5272 * user -> user switch 5274 5273 */ 5275 5274 if (!next->mm) { // to kernel ··· 5277 5276 5278 5277 next->active_mm = prev->active_mm; 5279 5278 if (prev->mm) // from user 5280 - mmgrab(prev->active_mm); 5279 + mmgrab_lazy_tlb(prev->active_mm); 5281 5280 else 5282 5281 prev->active_mm = NULL; 5283 5282 } else { // to user ··· 5294 5293 lru_gen_use_mm(next->mm); 5295 5294 5296 5295 if (!prev->mm) { // from kernel 5297 - /* will mmdrop() in finish_task_switch(). */ 5296 + /* will mmdrop_lazy_tlb() in finish_task_switch(). */ 5298 5297 rq->prev_mm = prev->active_mm; 5299 5298 prev->active_mm = NULL; 5300 5299 } ··· 9936 9935 /* 9937 9936 * The boot idle thread does lazy MMU switching as well: 9938 9937 */ 9939 - mmgrab(&init_mm); 9938 + mmgrab_lazy_tlb(&init_mm); 9940 9939 enter_lazy_tlb(&init_mm, current); 9941 9940 9942 9941 /*