drm/i915/gvt: fix nested sleeping issue
authorDu, Changbin <changbin.du@intel.com>
Thu, 27 Oct 2016 03:10:31 +0000 (11:10 +0800)
committerZhenyu Wang <zhenyuw@linux.intel.com>
Thu, 27 Oct 2016 03:20:42 +0000 (11:20 +0800)
We cannot use blocking method mutex_lock inside a wait loop.
Here we invoke pick_next_workload() which needs acquire a
mutex in our "condition" experssion. Then we go into a another
of the going-to-sleep sequence and changing the task state.
This is a dangerous. Let's rewrite the wait sequence to avoid
nested sleeping.

v2: fix do...while loop exit condition (zhenyu)
v3: rebase to gvt-staging branch

Signed-off-by: Du, Changbin <changbin.du@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
drivers/gpu/drm/i915/gvt/scheduler.c

index e96eaeebeb0a4f41a6ce6acfe670748a292621f0..f7e320b9b17a3178c0d93040aac186a720427635 100644 (file)
@@ -402,19 +402,24 @@ static int workload_thread(void *priv)
        struct intel_vgpu_workload *workload = NULL;
        int ret;
        bool need_force_wake = IS_SKYLAKE(gvt->dev_priv);
+       DEFINE_WAIT_FUNC(wait, woken_wake_function);
 
        kfree(p);
 
        gvt_dbg_core("workload thread for ring %d started\n", ring_id);
 
        while (!kthread_should_stop()) {
-               ret = wait_event_interruptible(scheduler->waitq[ring_id],
-                               kthread_should_stop() ||
-                               (workload = pick_next_workload(gvt, ring_id)));
-
-               WARN_ON_ONCE(ret);
-
-               if (kthread_should_stop())
+               add_wait_queue(&scheduler->waitq[ring_id], &wait);
+               do {
+                       workload = pick_next_workload(gvt, ring_id);
+                       if (workload)
+                               break;
+                       wait_woken(&wait, TASK_INTERRUPTIBLE,
+                                  MAX_SCHEDULE_TIMEOUT);
+               } while (!kthread_should_stop());
+               remove_wait_queue(&scheduler->waitq[ring_id], &wait);
+
+               if (!workload)
                        break;
 
                mutex_lock(&scheduler_mutex);