Skip to content

Commit 3342aa8

Browse files
jognesspmladek
authored andcommitted
printk: fix cpu lock ordering
The cpu lock implementation uses a full memory barrier to take the lock, but no memory barriers when releasing the lock. This means that changes performed by a lock owner may not be seen by the next lock owner. This may have been "good enough" for use by dump_stack() as a serialization mechanism, but it is not enough to provide proper protection for a critical section. Correct this problem by using acquire/release memory barriers for lock/unlock, respectively. Signed-off-by: John Ogness <[email protected]> Reviewed-by: Sergey Senozhatsky <[email protected]> Reviewed-by: Petr Mladek <[email protected]> Signed-off-by: Petr Mladek <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 766c268 commit 3342aa8

File tree

1 file changed

+50
-3
lines changed

1 file changed

+50
-3
lines changed

kernel/printk/printk.c

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3568,10 +3568,33 @@ int __printk_cpu_trylock(void)
35683568

35693569
cpu = smp_processor_id();
35703570

3571-
old = atomic_cmpxchg(&printk_cpulock_owner, -1, cpu);
3571+
/*
3572+
* Guarantee loads and stores from this CPU when it is the lock owner
3573+
* are _not_ visible to the previous lock owner. This pairs with
3574+
* __printk_cpu_unlock:B.
3575+
*
3576+
* Memory barrier involvement:
3577+
*
3578+
* If __printk_cpu_trylock:A reads from __printk_cpu_unlock:B, then
3579+
* __printk_cpu_unlock:A can never read from __printk_cpu_trylock:B.
3580+
*
3581+
* Relies on:
3582+
*
3583+
* RELEASE from __printk_cpu_unlock:A to __printk_cpu_unlock:B
3584+
* of the previous CPU
3585+
* matching
3586+
* ACQUIRE from __printk_cpu_trylock:A to __printk_cpu_trylock:B
3587+
* of this CPU
3588+
*/
3589+
old = atomic_cmpxchg_acquire(&printk_cpulock_owner, -1,
3590+
cpu); /* LMM(__printk_cpu_trylock:A) */
35723591
if (old == -1) {
3573-
/* This CPU is now the owner. */
3592+
/*
3593+
* This CPU is now the owner and begins loading/storing
3594+
* data: LMM(__printk_cpu_trylock:B)
3595+
*/
35743596
return 1;
3597+
35753598
} else if (old == cpu) {
35763599
/* This CPU is already the owner. */
35773600
atomic_inc(&printk_cpulock_nested);
@@ -3596,7 +3619,31 @@ void __printk_cpu_unlock(void)
35963619
return;
35973620
}
35983621

3599-
atomic_set(&printk_cpulock_owner, -1);
3622+
/*
3623+
* This CPU is finished loading/storing data:
3624+
* LMM(__printk_cpu_unlock:A)
3625+
*/
3626+
3627+
/*
3628+
* Guarantee loads and stores from this CPU when it was the
3629+
* lock owner are visible to the next lock owner. This pairs
3630+
* with __printk_cpu_trylock:A.
3631+
*
3632+
* Memory barrier involvement:
3633+
*
3634+
* If __printk_cpu_trylock:A reads from __printk_cpu_unlock:B,
3635+
* then __printk_cpu_trylock:B reads from __printk_cpu_unlock:A.
3636+
*
3637+
* Relies on:
3638+
*
3639+
* RELEASE from __printk_cpu_unlock:A to __printk_cpu_unlock:B
3640+
* of this CPU
3641+
* matching
3642+
* ACQUIRE from __printk_cpu_trylock:A to __printk_cpu_trylock:B
3643+
* of the next CPU
3644+
*/
3645+
atomic_set_release(&printk_cpulock_owner,
3646+
-1); /* LMM(__printk_cpu_unlock:B) */
36003647
}
36013648
EXPORT_SYMBOL(__printk_cpu_unlock);
36023649
#endif /* CONFIG_SMP */

0 commit comments

Comments
 (0)