Skip to content
  • Peter Zijlstra's avatar
    futex: Drop hb->lock before enqueueing on the rtmutex · 56222b21
    Peter Zijlstra authored
    
    
    When PREEMPT_RT_FULL does the spinlock -> rt_mutex substitution the PI
    chain code will (falsely) report a deadlock and BUG.
    
    The problem is that it hold hb->lock (now an rt_mutex) while doing
    task_blocks_on_rt_mutex on the futex's pi_state::rtmutex. This, when
    interleaved just right with futex_unlock_pi() leads it to believe to see an
    AB-BA deadlock.
    
      Task1 (holds rt_mutex,	Task2 (does FUTEX_LOCK_PI)
             does FUTEX_UNLOCK_PI)
    
    				lock hb->lock
    				lock rt_mutex (as per start_proxy)
      lock hb->lock
    
    Which is a trivial AB-BA.
    
    It is not an actual deadlock, because it won't be holding hb->lock by the
    time it actually blocks on the rt_mutex, but the chainwalk code doesn't
    know that and it would be a nightmare to handle this gracefully.
    
    To avoid this problem, do the same as in futex_unlock_pi() and drop
    hb->lock after acquiring wait_lock. This still fully serializes against
    futex_unlock_pi(), since adding to the wait_list does the very same lock
    dance, and removing it holds both locks.
    
    Aside of solving the RT problem this makes the lock and unlock mechanism
    symetric and reduces the hb->lock held time.
    
    Reported-and-tested-by: default avatarSebastian Andrzej Siewior <bigeasy@linutronix.de>
    Suggested-by: default avatarThomas Gleixner <tglx@linutronix.de>
    Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
    Cc: juri.lelli@arm.com
    Cc: xlpang@redhat.com
    Cc: rostedt@goodmis.org
    Cc: mathieu.desnoyers@efficios.com
    Cc: jdesfossez@efficios.com
    Cc: dvhart@infradead.org
    Cc: bristot@redhat.com
    Link: http://lkml.kernel.org/r/20170322104152.161341537@infradead.org
    
    
    Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
    56222b21