There is below race between irq handler and irq thread:
irq handler                             irq thread

irq_wake_thread()                       irq_thread()
  set bit RUNTHREAD
  ...                                    clear bit RUNTHREAD
                                         thread_fn()
                                         [A]test_and_decrease
                                               thread_active
  [B]increase thread_active

If action A is before action B, after that the thread_active
will be always > 0, and for synchronize_irq() calling, which
will be waiting there forever.

Here put the increasing thread-active before setting bit
RUNTHREAD, which can resolve such race.

Signed-off-by: xiaoming wang <xiaoming.w...@intel.com>
Signed-off-by: Chuansheng Liu <chuansheng....@intel.com>
---
 kernel/irq/handle.c | 21 ++++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
index 131ca17..5f9fbb7 100644
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -65,7 +65,7 @@ static void irq_wake_thread(struct irq_desc *desc, struct 
irqaction *action)
         * Wake up the handler thread for this action. If the
         * RUNTHREAD bit is already set, nothing to do.
         */
-       if (test_and_set_bit(IRQTF_RUNTHREAD, &action->thread_flags))
+       if (test_bit(IRQTF_RUNTHREAD, &action->thread_flags))
                return;
 
        /*
@@ -126,6 +126,25 @@ static void irq_wake_thread(struct irq_desc *desc, struct 
irqaction *action)
         */
        atomic_inc(&desc->threads_active);
 
+       /*
+        * set the RUNTHREAD bit after increasing the threads_active,
+        * it can avoid the below race:
+        * irq handler                  irq thread in case it is in
+        *                                            running state
+        *
+        *  set RUNTHREAD bit
+        *                              clear the RUNTHREAD bit
+        *...                           thread_fn()
+        *
+        *                              due to threads_active==0,
+        *                              no waking up wait_for_threads
+        *
+        * threads_active ++
+        * After that, the threads_active will be always > 0, which
+        * will block the synchronize_irq().
+        */
+       set_bit(IRQTF_RUNTHREAD, &action->thread_flags);
+
        wake_up_process(action->thread);
 }
 
-- 
1.9.rc0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to