• Chuansheng Liu's avatar
    genirq: Remove racy waitqueue_active check · b46741f2
    Chuansheng Liu authored
    commit c685689f upstream.
    
    We hit one rare case below:
    
    T1 calling disable_irq(), but hanging at synchronize_irq()
    always;
    The corresponding irq thread is in sleeping state;
    And all CPUs are in idle state;
    
    After analysis, we found there is one possible scenerio which
    causes T1 is waiting there forever:
    CPU0                                       CPU1
     synchronize_irq()
      wait_event()
        spin_lock()
                                               atomic_dec_and_test(&threads_active)
          insert the __wait into queue
        spin_unlock()
                                               if(waitqueue_active)
        atomic_read(&threads_active)
                                                 wake_up()
    
    Here after inserted the __wait into queue on CPU0, and before
    test if queue is empty on CPU1, there is no barrier, it maybe
    cause it is not visible for CPU1 immediately, although CPU0 has
    updated the queue list.
    It is similar for CPU0 atomic_read() threads_active also.
    
    So we'd need one smp_mb() before waitqueue_active.that, but removing
    the waitqueue_active() check solves it as wel l and it makes
    things simple and clear.
    Signed-off-by: default avatarChuansheng Liu <chuansheng.liu@intel.com>
    Cc: Xiaoming Wang <xiaoming.wang@intel.com>
    Link: http://lkml.kernel.org/r/1393212590-32543-1-git-send-email-chuansheng.liu@intel.comSigned-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    b46741f2
manage.c 41.8 KB