@@ -205,6 +205,8 @@ impl ActivePageTableGuard {
205205 }
206206 if num_pages < usize:: from ( invlpgb. invlpgb_count_max ( ) ) {
207207 builder = builder. pages ( Page :: range ( * pages. start ( ) , * pages. end ( ) + 1 ) ) ;
208+ } else {
209+ state. needs_flush = ApBitmap :: empty ( ) ;
208210 }
209211 builder. flush ( ) ;
210212 invlpgb. tlbsync ( ) ;
@@ -298,18 +300,30 @@ impl FlushGuard for GlobalFlushGuard {
298300 // IPI, so the other thread thinks that the bit was never cleared and
299301 // it won't get cleared again because we didn't set another IPI.
300302 let active_aps = ACTIVE_APS . get_all ( ) ;
301- let other_active_aps = active_aps & all_other_aps;
302303 let inactive_aps = !active_aps & all_other_aps;
303- PENDING_GLOBAL_TLB_SHOOTDOWN . set_all ( other_active_aps) ;
304304 LAZY_PENDING_GLOBAL_TLB_SHOOTDOWN . set_all ( inactive_aps) ;
305+ // Re-fetch `ACTIVE_APS` after setting `LAZY_PENDING_GLOBAL_TLB_SHOOTDOWN`.
306+ // If we don't do this, there's a race condition:
307+ // +----------------------------------------------------------------------------------+
308+ // | this AP | other AP |
309+ // | ... | inactive |
310+ // | read ACTIVE_APS | |
311+ // | | wake up |
312+ // | | set ACTIVE_APS |
313+ // | | read LAZY_PENDING_GLOBAL_TLB_SHOOTDOWN |
314+ // | write LAZY_PENDING_GLOBAL_TLB_SHOOTDOWN | |
315+ // +----------------------------------------------------------------------------------+
316+ let active_aps = active_aps | ACTIVE_APS . get_all ( ) ;
317+ let other_active_aps = active_aps & all_other_aps;
318+ PENDING_GLOBAL_TLB_SHOOTDOWN . set_all ( other_active_aps) ;
305319
306320 // Send IPIs to all other currently active APs.
307321 send_tlb_ipis ( other_active_aps) ;
308322
309323 // Flush the local TLB entry.
310324 tlb:: flush ( page. start_address ( ) ) ;
311325
312- // Wait for the APS to acknowledge the IPI.
326+ // Wait for the APs to acknowledge the IPI.
313327 let mut remaining_aps = other_active_aps;
314328 while !remaining_aps. is_empty ( ) {
315329 remaining_aps &= PENDING_GLOBAL_TLB_SHOOTDOWN . get_all ( ) ;
0 commit comments