kernel - Fix SMP tsleep_interlock() vs wakeup() race
authorMatthew Dillon <dillon@apollo.backplane.com>
Wed, 23 Aug 2017 16:28:50 +0000 (09:28 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Wed, 23 Aug 2017 16:28:50 +0000 (09:28 -0700)
commite676ebdaf2554fecf34b17eb0a0a71a248fdadbf
tree8c1501d62bce32b9f230ee223e4d2c03761853db
parent05e0d9813e4d5e096aa4d619c9df5184ae418201
kernel - Fix SMP tsleep_interlock() vs wakeup() race

* Problem triggered by kern_mutex.c, probably only triggered by mutexes.
  The mutex sets state non-atomically and calls wakeup() with no
  intervening atomic op.  wakeup() loads the cpumask to wakeup
  non-atomically.  This can cause the wakeup() code to miss an
  interaction with the cpumask set by another cpu.

  cpu A:
set state <-- sets state
wakeup() <-- loads cpu mask non-atomically

  cpu B:
tsleep_interlock() <-- sets cpu mask atomically
if (checkstate failed) <-- checks state
tsleep()

* Fix the problem by add a lfence() in the wakeup() code prior to
  loading the cpumask.  Even though I'm fairly sure only the kern_mutex.c
  code can causing this problem, putting the lfence in wakeup() is the
  safest mechanic.
sys/kern/kern_synch.c