If this thread is preempted at(or before) location a, and the other thread
set the condition followed with wake_up_process. After that
when this thread is re-scheduled, calling set_current_state to set itself as
state TASK_INTERRUPTIBLE, if it is preempted again after that and before
__set_current_state(TASK_RUNNING), it triggers the invalid wakeup problem.
----------------
kauditd_thread()
----------------
while (!kthread_should_stop()) {
        ...
                //location a
                set_current_state(TASK_INTERRUPTIBLE);
        ...

                if (!skb_queue_len(&audit_skb_queue)) {
                        //location b
                        try_to_freeze();
                        schedule();
                        //location c
                }

        __set_current_state(TASK_RUNNING);
        //location d
        ...
}

To solve this problem, using preempt_disable() to bound the operaion that
setting the task state and the conditions(set by the wake thread) validation.
----------------
kauditd_thread()
----------------
while (!kthread_should_stop()) {
        ...
                preempt_disable();
        set_current_state(TASK_INTERRUPTIBLE);
        ...

                if (!skb_queue_len(&audit_skb_queue)) {
                        preempt_enable();
                        try_to_freeze();
                        schedule();
                        preempt_disable();
                }

        __set_current_state(TASK_RUNNING);
        preempt_enable();
        ...
}

Signed-off-by: Libin <huawei.li...@huawei.com>
---
 kernel/audit.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/kernel/audit.c b/kernel/audit.c
index 91e53d0..a7d1346 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -455,15 +455,19 @@ static int kauditd_thread(void *dummy)
                                audit_printk_skb(skb);
                        continue;
                }
+               preempt_disable();
                set_current_state(TASK_INTERRUPTIBLE);
                add_wait_queue(&kauditd_wait, &wait);
 
                if (!skb_queue_len(&audit_skb_queue)) {
+                       preempt_enable();
                        try_to_freeze();
                        schedule();
+                       preempt_disable();
                }
 
                __set_current_state(TASK_RUNNING);
+               preempt_enable();
                remove_wait_queue(&kauditd_wait, &wait);
        }
        return 0;
-- 
1.8.2.1


--
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