| From 27d4ee03078aba88c5e07dcc4917e8d01d046f38 Mon Sep 17 00:00:00 2001 |
| From: Lukas Wunner <lukas@wunner.de> |
| Date: Sun, 11 Feb 2018 10:38:28 +0100 |
| Subject: workqueue: Allow retrieval of current task's work struct |
| |
| From: Lukas Wunner <lukas@wunner.de> |
| |
| commit 27d4ee03078aba88c5e07dcc4917e8d01d046f38 upstream. |
| |
| Introduce a helper to retrieve the current task's work struct if it is |
| a workqueue worker. |
| |
| This allows us to fix a long-standing deadlock in several DRM drivers |
| wherein the ->runtime_suspend callback waits for a specific worker to |
| finish and that worker in turn calls a function which waits for runtime |
| suspend to finish. That function is invoked from multiple call sites |
| and waiting for runtime suspend to finish is the correct thing to do |
| except if it's executing in the context of the worker. |
| |
| Cc: Lai Jiangshan <jiangshanlai@gmail.com> |
| Cc: Dave Airlie <airlied@redhat.com> |
| Cc: Ben Skeggs <bskeggs@redhat.com> |
| Cc: Alex Deucher <alexander.deucher@amd.com> |
| Acked-by: Tejun Heo <tj@kernel.org> |
| Reviewed-by: Lyude Paul <lyude@redhat.com> |
| Signed-off-by: Lukas Wunner <lukas@wunner.de> |
| Link: https://patchwork.freedesktop.org/patch/msgid/2d8f603074131eb87e588d2b803a71765bd3a2fd.1518338788.git.lukas@wunner.de |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| include/linux/workqueue.h | 1 + |
| kernel/workqueue.c | 16 ++++++++++++++++ |
| 2 files changed, 17 insertions(+) |
| |
| --- a/include/linux/workqueue.h |
| +++ b/include/linux/workqueue.h |
| @@ -467,6 +467,7 @@ extern bool cancel_delayed_work_sync(str |
| |
| extern void workqueue_set_max_active(struct workqueue_struct *wq, |
| int max_active); |
| +extern struct work_struct *current_work(void); |
| extern bool current_is_workqueue_rescuer(void); |
| extern bool workqueue_congested(int cpu, struct workqueue_struct *wq); |
| extern unsigned int work_busy(struct work_struct *work); |
| --- a/kernel/workqueue.c |
| +++ b/kernel/workqueue.c |
| @@ -4185,6 +4185,22 @@ void workqueue_set_max_active(struct wor |
| 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? |
| * |
| * Determine whether %current is a workqueue rescuer. Can be used from |