diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 1e1373b..01fe8ee 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -709,6 +709,18 @@ void wq_worker_waking_up(struct task_struct *task, unsigned int cpu) atomic_inc(get_pool_nr_running(worker->pool)); } +struct wq_bug_info { + bool valid; + pid_t cur_pid, target_pid; + int cpu, cur_cpu, target_cpu; + char cur_comm[TASK_COMM_LEN]; + char target_comm[TASK_COMM_LEN]; + cpumask_t cur_cpumask, target_cpumask; + void *fn; +}; + +static struct wq_bug_info wq_bi; + /** * wq_worker_sleeping - a worker is going to sleep * @task: task going to sleep @@ -750,7 +762,45 @@ struct task_struct *wq_worker_sleeping(struct task_struct *task, */ if (atomic_dec_and_test(nr_running) && !list_empty(&pool->worklist)) to_wakeup = first_worker(pool); - return to_wakeup ? to_wakeup->task : NULL; + if (to_wakeup && to_wakeup->task) { + if (task_cpu(to_wakeup->task) != task_cpu(current)) { + wq_bi.cur_pid = task_pid_nr(current); + wq_bi.target_pid = task_pid_nr(to_wakeup->task); + wq_bi.cpu = cpu; + wq_bi.cur_cpu = task_cpu(current); + wq_bi.target_cpu = task_cpu(to_wakeup->task); + memcpy(wq_bi.cur_comm, current->comm, sizeof(wq_bi.cur_comm)); + memcpy(wq_bi.target_comm, to_wakeup->task->comm, sizeof(wq_bi.target_comm)); + cpumask_copy(&wq_bi.cur_cpumask, ¤t->cpus_allowed); + cpumask_copy(&wq_bi.target_cpumask, &to_wakeup->task->cpus_allowed); + wq_bi.fn = worker->current_work ? worker->current_work->func : NULL; + smp_wmb(); + wq_bi.valid = true; + return NULL; + } + return to_wakeup->task; + } + return NULL; +} + +static void wq_bi_timer_fn(unsigned long arg); +static DEFINE_TIMER(wq_bi_timer, wq_bi_timer_fn, 0, 0); + +static void wq_bi_timer_fn(unsigned long arg) +{ + if (wq_bi.valid) { + static char buf0[1024], buf1[1024]; + + smp_rmb(); + cpumask_scnprintf(buf0, sizeof(buf0), &wq_bi.cur_cpumask); + cpumask_scnprintf(buf1, sizeof(buf1), &wq_bi.target_cpumask); + printk("XXX workqueue: foreign wakeup bug: current = %d (%s) on cpu %d/%s, target = %d (%s) on cpu %d/%s, cpu=%d current_fn=%pf\n", + wq_bi.cur_pid, wq_bi.cur_comm, wq_bi.cur_cpu, buf0, + wq_bi.target_pid, wq_bi.target_comm, wq_bi.target_cpu, buf1, + wq_bi.cpu, wq_bi.fn); + wq_bi.valid = false; + } + mod_timer(&wq_bi_timer, jiffies + HZ); } /** @@ -3825,6 +3875,7 @@ static int __init init_workqueues(void) BUG_ON(!system_wq || !system_long_wq || !system_nrt_wq || !system_unbound_wq || !system_freezable_wq || !system_nrt_freezable_wq); + mod_timer(&wq_bi_timer, jiffies + HZ); return 0; } early_initcall(init_workqueues);