summaryrefslogtreecommitdiffstats
path: root/drivers/staging
diff options
context:
space:
mode:
authorBryan O'Donoghue <bryan.odonoghue@linaro.org>2016-06-16 13:42:14 +0100
committerGreg Kroah-Hartman <gregkh@google.com>2016-06-16 09:07:41 -0700
commitc9e8f893eeef4f0e2d10333aed2d175e50a56dab (patch)
tree16b39f62e3df322bccd91dbc349bd579a66c44cf /drivers/staging
parentdf124299d1d3e64175c79f83b4ecf2710d202e49 (diff)
greybus: timesync: Do not hold mutex on cancel_delayed_work_sync
There is a scenario where gb_timesync_svc_remove() can run, attain a mutex and call cancel_delayed_work_sync(). In the meantime a worker may already be running and trying to attain the same mutex but will never do so as the gb_timesync_svc_remove() path is holding the mutex and waiting on the delayed_work_sync() to complete - leading to deadlock. This patch addresses by calling the cancel_delayed_work_sync() before locking the relevant mutex. Reported-by: Vaibhav Agarwal <vaibhav.agarwal@linaro.org> Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> Reviewed-by: Vaibhav Hiremath <vaibhav.hiremath@linaro.org> Tested-by: Vaibhav Hiremath <vaibhav.hiremath@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Diffstat (limited to 'drivers/staging')
-rw-r--r--drivers/staging/greybus/timesync.c3
1 files changed, 2 insertions, 1 deletions
diff --git a/drivers/staging/greybus/timesync.c b/drivers/staging/greybus/timesync.c
index a029fa085af6..a9b62026a201 100644
--- a/drivers/staging/greybus/timesync.c
+++ b/drivers/staging/greybus/timesync.c
@@ -1065,6 +1065,8 @@ void gb_timesync_svc_remove(struct gb_svc *svc)
if (!timesync_svc)
goto done;
+ cancel_delayed_work_sync(&timesync_svc->delayed_work);
+
mutex_lock(&timesync_svc->mutex);
gb_timesync_teardown(timesync_svc);
@@ -1079,7 +1081,6 @@ void gb_timesync_svc_remove(struct gb_svc *svc)
gb_timesync_set_state_atomic(timesync_svc, GB_TIMESYNC_STATE_INVALID);
debugfs_remove(timesync_svc->frame_ktime_dentry);
debugfs_remove(timesync_svc->frame_time_dentry);
- cancel_delayed_work_sync(&timesync_svc->delayed_work);
destroy_workqueue(timesync_svc->work_queue);
list_del(&timesync_svc->list);