Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

workqueue: Allow retrieval of current task's work struct

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

+17
+1
include/linux/workqueue.h
··· 465 465 466 466 extern void workqueue_set_max_active(struct workqueue_struct *wq, 467 467 int max_active); 468 + extern struct work_struct *current_work(void); 468 469 extern bool current_is_workqueue_rescuer(void); 469 470 extern bool workqueue_congested(int cpu, struct workqueue_struct *wq); 470 471 extern unsigned int work_busy(struct work_struct *work);
+16
kernel/workqueue.c
··· 4168 4168 EXPORT_SYMBOL_GPL(workqueue_set_max_active); 4169 4169 4170 4170 /** 4171 + * current_work - retrieve %current task's work struct 4172 + * 4173 + * Determine if %current task is a workqueue worker and what it's working on. 4174 + * Useful to find out the context that the %current task is running in. 4175 + * 4176 + * Return: work struct if %current task is a workqueue worker, %NULL otherwise. 4177 + */ 4178 + struct work_struct *current_work(void) 4179 + { 4180 + struct worker *worker = current_wq_worker(); 4181 + 4182 + return worker ? worker->current_work : NULL; 4183 + } 4184 + EXPORT_SYMBOL(current_work); 4185 + 4186 + /** 4171 4187 * current_is_workqueue_rescuer - is %current workqueue rescuer? 4172 4188 * 4173 4189 * Determine whether %current is a workqueue rescuer. Can be used from