| From 77668c8b559e4fe2acf2a0749c7c83cde49a5025 Mon Sep 17 00:00:00 2001 |
| From: Lai Jiangshan <laijs@cn.fujitsu.com> |
| Date: Fri, 18 Apr 2014 11:04:16 -0400 |
| Subject: workqueue: fix a possible race condition between rescuer and pwq-release |
| |
| From: Lai Jiangshan <laijs@cn.fujitsu.com> |
| |
| commit 77668c8b559e4fe2acf2a0749c7c83cde49a5025 upstream. |
| |
| There is a race condition between rescuer_thread() and |
| pwq_unbound_release_workfn(). |
| |
| Even after a pwq is scheduled for rescue, the associated work items |
| may be consumed by any worker. If all of them are consumed before the |
| rescuer gets to them and the pwq's base ref was put due to attribute |
| change, the pwq may be released while still being linked on |
| @wq->maydays list making the rescuer dereference already freed pwq |
| later. |
| |
| Make send_mayday() pin the target pwq until the rescuer is done with |
| it. |
| |
| tj: Updated comment and patch description. |
| |
| Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com> |
| Signed-off-by: Tejun Heo <tj@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| kernel/workqueue.c | 12 ++++++++++++ |
| 1 file changed, 12 insertions(+) |
| |
| --- a/kernel/workqueue.c |
| +++ b/kernel/workqueue.c |
| @@ -1881,6 +1881,12 @@ static void send_mayday(struct work_stru |
| |
| /* mayday mayday mayday */ |
| if (list_empty(&pwq->mayday_node)) { |
| + /* |
| + * If @pwq is for an unbound wq, its base ref may be put at |
| + * any time due to an attribute change. Pin @pwq until the |
| + * rescuer is done with it. |
| + */ |
| + get_pwq(pwq); |
| list_add_tail(&pwq->mayday_node, &wq->maydays); |
| wake_up_process(wq->rescuer->task); |
| } |
| @@ -2403,6 +2409,12 @@ repeat: |
| process_scheduled_works(rescuer); |
| |
| /* |
| + * Put the reference grabbed by send_mayday(). @pool won't |
| + * go away while we're holding its lock. |
| + */ |
| + put_pwq(pwq); |
| + |
| + /* |
| * Leave this pool. If keep_working() is %true, notify a |
| * regular worker; otherwise, we end up with 0 concurrency |
| * and stalling the execution. |