Merge remote-tracking branch 'driver-core/driver-core-next'
[linux] / kernel / workqueue.c
index d5a26e4..8cecbe3 100644 (file)
@@ -909,6 +909,26 @@ struct task_struct *wq_worker_sleeping(struct task_struct *task)
        return to_wakeup ? to_wakeup->task : NULL;
 }
 
+/**
+ * wq_worker_last_func - retrieve worker's last work function
+ *
+ * Determine the last function a worker executed. This is called from
+ * the scheduler to get a worker's last known identity.
+ *
+ * CONTEXT:
+ * spin_lock_irq(rq->lock)
+ *
+ * Return:
+ * The last work function %current executed as a worker, NULL if it
+ * hasn't executed any work yet.
+ */
+work_func_t wq_worker_last_func(struct task_struct *task)
+{
+       struct worker *worker = kthread_data(task);
+
+       return worker->last_func;
+}
+
 /**
  * worker_set_flags - set worker flags and adjust nr_running accordingly
  * @worker: self
@@ -2268,6 +2288,9 @@ __acquires(&pool->lock)
        if (unlikely(cpu_intensive))
                worker_clr_flags(worker, WORKER_CPU_INTENSIVE);
 
+       /* tag the worker for identification in schedule() */
+       worker->last_func = worker->current_func;
+
        /* we're done with it, release */
        hash_del(&worker->hentry);
        worker->current_work = NULL;
@@ -2992,6 +3015,9 @@ static bool __flush_work(struct work_struct *work, bool from_cancel)
        if (WARN_ON(!wq_online))
                return false;
 
+       if (WARN_ON(!work->func))
+               return false;
+
        if (!from_cancel) {
                lock_map_acquire(&work->lockdep_map);
                lock_map_release(&work->lockdep_map);