[RAMEN9610-21029]rtlwifi: Fix potential overflow on P2P code
[GitHub/MotorolaMobilityLLC/kernel-slsi.git] / kernel / workqueue.c
index a2dccfe1acec34bbda97a292344b997055e56d9a..62ac1e5e4bb76ec0034f01eb0935d8472d77a52f 100644 (file)
@@ -48,6 +48,8 @@
 #include <linux/nodemask.h>
 #include <linux/moduleparam.h>
 #include <linux/uaccess.h>
+#include <linux/nmi.h>
+#include <linux/debug-snapshot.h>
 
 #include "workqueue_internal.h"
 
@@ -910,6 +912,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
@@ -2110,7 +2132,9 @@ __acquires(&pool->lock)
         */
        lockdep_invariant_state(true);
        trace_workqueue_execute_start(work);
+       dbg_snapshot_work(worker, worker->task, worker->current_func, DSS_FLAG_IN);
        worker->current_func(work);
+       dbg_snapshot_work(worker, worker->task, worker->current_func, DSS_FLAG_OUT);
        /*
         * While we must be careful to not use "work" after this, the trace
         * point will only record its address.
@@ -2144,6 +2168,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;
@@ -4183,6 +4210,22 @@ void workqueue_set_max_active(struct workqueue_struct *wq, int max_active)
 }
 EXPORT_SYMBOL_GPL(workqueue_set_max_active);
 
+/**
+ * current_work - retrieve %current task's work struct
+ *
+ * Determine if %current task is a workqueue worker and what it's working on.
+ * Useful to find out the context that the %current task is running in.
+ *
+ * Return: work struct if %current task is a workqueue worker, %NULL otherwise.
+ */
+struct work_struct *current_work(void)
+{
+       struct worker *worker = current_wq_worker();
+
+       return worker ? worker->current_work : NULL;
+}
+EXPORT_SYMBOL(current_work);
+
 /**
  * current_is_workqueue_rescuer - is %current workqueue rescuer?
  *
@@ -4479,6 +4522,12 @@ void show_workqueue_state(void)
                        if (pwq->nr_active || !list_empty(&pwq->delayed_works))
                                show_pwq(pwq);
                        spin_unlock_irqrestore(&pwq->pool->lock, flags);
+                       /*
+                        * We could be printing a lot from atomic context, e.g.
+                        * sysrq-t -> show_workqueue_state(). Avoid triggering
+                        * hard lockup.
+                        */
+                       touch_nmi_watchdog();
                }
        }
 
@@ -4506,6 +4555,12 @@ void show_workqueue_state(void)
                pr_cont("\n");
        next_pool:
                spin_unlock_irqrestore(&pool->lock, flags);
+               /*
+                * We could be printing a lot from atomic context, e.g.
+                * sysrq-t -> show_workqueue_state(). Avoid triggering
+                * hard lockup.
+                */
+               touch_nmi_watchdog();
        }
 
        rcu_read_unlock_sched();
@@ -5321,7 +5376,7 @@ int workqueue_sysfs_register(struct workqueue_struct *wq)
 
        ret = device_register(&wq_dev->dev);
        if (ret) {
-               kfree(wq_dev);
+               put_device(&wq_dev->dev);
                wq->wq_dev = NULL;
                return ret;
        }
@@ -5455,7 +5510,7 @@ static void wq_watchdog_timer_fn(unsigned long data)
        mod_timer(&wq_watchdog_timer, jiffies + thresh);
 }
 
-void wq_watchdog_touch(int cpu)
+notrace void wq_watchdog_touch(int cpu)
 {
        if (cpu >= 0)
                per_cpu(wq_watchdog_touched_cpu, cpu) = jiffies;