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

locking/barriers: Introduce smp_acquire__after_ctrl_dep()

Introduce smp_acquire__after_ctrl_dep(), this construct is not
uncommon, but the lack of this barrier is.

Use it to better express smp_rmb() uses in WRITE_ONCE(), the IPC
semaphore code and the qspinlock code.

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>

authored by

Peter Zijlstra and committed by
Ingo Molnar
33ac2796 1f03e8d2

+15 -18
+12 -5
include/linux/compiler.h
··· 305 305 }) 306 306 307 307 /** 308 + * smp_acquire__after_ctrl_dep() - Provide ACQUIRE ordering after a control dependency 309 + * 310 + * A control dependency provides a LOAD->STORE order, the additional RMB 311 + * provides LOAD->LOAD order, together they provide LOAD->{LOAD,STORE} order, 312 + * aka. (load)-ACQUIRE. 313 + * 314 + * Architectures that do not do load speculation can have this be barrier(). 315 + */ 316 + #define smp_acquire__after_ctrl_dep() smp_rmb() 317 + 318 + /** 308 319 * smp_cond_load_acquire() - (Spin) wait for cond with ACQUIRE ordering 309 320 * @ptr: pointer to the variable to wait on 310 321 * @cond: boolean expression to wait for ··· 325 314 * 326 315 * Due to C lacking lambda expressions we load the value of *ptr into a 327 316 * pre-named variable @VAL to be used in @cond. 328 - * 329 - * The control dependency provides a LOAD->STORE order, the additional RMB 330 - * provides LOAD->LOAD order, together they provide LOAD->{LOAD,STORE} order, 331 - * aka. ACQUIRE. 332 317 */ 333 318 #ifndef smp_cond_load_acquire 334 319 #define smp_cond_load_acquire(ptr, cond_expr) ({ \ ··· 336 329 break; \ 337 330 cpu_relax(); \ 338 331 } \ 339 - smp_rmb(); /* ctrl + rmb := acquire */ \ 332 + smp_acquire__after_ctrl_dep(); \ 340 333 VAL; \ 341 334 }) 342 335 #endif
+2 -12
ipc/sem.c
··· 260 260 } 261 261 262 262 /* 263 - * spin_unlock_wait() and !spin_is_locked() are not memory barriers, they 264 - * are only control barriers. 265 - * The code must pair with spin_unlock(&sem->lock) or 266 - * spin_unlock(&sem_perm.lock), thus just the control barrier is insufficient. 267 - * 268 - * smp_rmb() is sufficient, as writes cannot pass the control barrier. 269 - */ 270 - #define ipc_smp_acquire__after_spin_is_unlocked() smp_rmb() 271 - 272 - /* 273 263 * Wait until all currently ongoing simple ops have completed. 274 264 * Caller must own sem_perm.lock. 275 265 * New simple ops cannot start, because simple ops first check ··· 282 292 sem = sma->sem_base + i; 283 293 spin_unlock_wait(&sem->lock); 284 294 } 285 - ipc_smp_acquire__after_spin_is_unlocked(); 295 + smp_acquire__after_ctrl_dep(); 286 296 } 287 297 288 298 /* ··· 340 350 * complex_count++; 341 351 * spin_unlock(sem_perm.lock); 342 352 */ 343 - ipc_smp_acquire__after_spin_is_unlocked(); 353 + smp_acquire__after_ctrl_dep(); 344 354 345 355 /* 346 356 * Now repeat the test of complex_count:
+1 -1
kernel/locking/qspinlock.c
··· 379 379 cpu_relax(); 380 380 381 381 done: 382 - smp_rmb(); /* CTRL + RMB -> ACQUIRE */ 382 + smp_acquire__after_ctrl_dep(); 383 383 } 384 384 EXPORT_SYMBOL(queued_spin_unlock_wait); 385 385 #endif