From: Jason Xing <[email protected]>

commit 7b2b55da1db10a5525460633ae4b6fb0be060c41 upstream.

Only when calling the poll syscall the first time can user receive
POLLPRI correctly.  After that, user always fails to acquire the event
signal.

Reproduce case:
 1. Get the monitor code in Documentation/accounting/psi.txt
 2. Run it, and wait for the event triggered.
 3. Kill and restart the process.

The question is why we can end up with poll_scheduled = 1 but the work
not running (which would reset it to 0).  And the answer is because the
scheduling side sees group->poll_kworker under RCU protection and then
schedules it, but here we cancel the work and destroy the worker.  The
cancel needs to pair with resetting the poll_scheduled flag.

Link: 
http://lkml.kernel.org/r/[email protected]
Signed-off-by: Jason Xing <[email protected]>
Signed-off-by: Joseph Qi <[email protected]>
Reviewed-by: Caspar Zhang <[email protected]>
Reviewed-by: Suren Baghdasaryan <[email protected]>
Acked-by: Johannes Weiner <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>

---
 kernel/sched/psi.c |    8 ++++++++
 1 file changed, 8 insertions(+)

--- a/kernel/sched/psi.c
+++ b/kernel/sched/psi.c
@@ -1131,7 +1131,15 @@ static void psi_trigger_destroy(struct k
         * deadlock while waiting for psi_poll_work to acquire trigger_lock
         */
        if (kworker_to_destroy) {
+               /*
+                * After the RCU grace period has expired, the worker
+                * can no longer be found through group->poll_kworker.
+                * But it might have been already scheduled before
+                * that - deschedule it cleanly before destroying it.
+                */
                kthread_cancel_delayed_work_sync(&group->poll_work);
+               atomic_set(&group->poll_scheduled, 0);
+
                kthread_destroy_worker(kworker_to_destroy);
        }
        kfree(t);


Reply via email to