Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c9e8f893 authored by Bryan O'Donoghue's avatar Bryan O'Donoghue Committed by Greg Kroah-Hartman
Browse files

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: default avatarVaibhav Agarwal <vaibhav.agarwal@linaro.org>
Signed-off-by: default avatarBryan O'Donoghue <bryan.odonoghue@linaro.org>
Reviewed-by: default avatarVaibhav Hiremath <vaibhav.hiremath@linaro.org>
Tested-by: default avatarVaibhav Hiremath <vaibhav.hiremath@linaro.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@google.com>
parent df124299
Loading
Loading
Loading
Loading
+2 −1
Original line number Original line Diff line number Diff line
@@ -1065,6 +1065,8 @@ void gb_timesync_svc_remove(struct gb_svc *svc)
	if (!timesync_svc)
	if (!timesync_svc)
		goto done;
		goto done;


	cancel_delayed_work_sync(&timesync_svc->delayed_work);

	mutex_lock(&timesync_svc->mutex);
	mutex_lock(&timesync_svc->mutex);


	gb_timesync_teardown(timesync_svc);
	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);
	gb_timesync_set_state_atomic(timesync_svc, GB_TIMESYNC_STATE_INVALID);
	debugfs_remove(timesync_svc->frame_ktime_dentry);
	debugfs_remove(timesync_svc->frame_ktime_dentry);
	debugfs_remove(timesync_svc->frame_time_dentry);
	debugfs_remove(timesync_svc->frame_time_dentry);
	cancel_delayed_work_sync(&timesync_svc->delayed_work);
	destroy_workqueue(timesync_svc->work_queue);
	destroy_workqueue(timesync_svc->work_queue);
	list_del(&timesync_svc->list);
	list_del(&timesync_svc->list);