From bf529e5f4056d80f49d351e14a9786a47f07efca Mon Sep 17 00:00:00 2001 From: Om Prakash Tripathi Date: Thu, 11 Apr 2019 17:23:57 +0530 Subject: [PATCH] qcacmn: Fix deadlock due to vdev_list_lock and scn_lock Deadlock happens when control path takes scn_lock and calls cdp_peer_delete() which in turn tries to acquire vdev_list_lock. If other core starts handling peer_unmap and holds vdev_list_lock and tries to releases reference of control peer, which in turn tries to acquire scn_lock leading to deadlock. Pass vdev object intead of vdev id to dp_reset_and_release_peer_mem which will avoid need for vdev_list_lock and fix thhis deadlock. Change-Id: I805bb4958b9b5ec4b29d70ba67e7410572201a60 CRs-Fixed: 2426717 --- dp/wifi3.0/dp_main.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index bff9a4412800..1d80e7fe83ec 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -5495,17 +5495,11 @@ static void dp_peer_authorize(struct cdp_peer *peer_handle, uint32_t authorize) static void dp_reset_and_release_peer_mem(struct dp_soc *soc, struct dp_pdev *pdev, struct dp_peer *peer, - uint32_t vdev_id) + struct dp_vdev *vdev) { - struct dp_vdev *vdev = NULL; struct dp_peer *bss_peer = NULL; uint8_t *m_addr = NULL; - qdf_spin_lock_bh(&pdev->vdev_list_lock); - TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { - if (vdev->vdev_id == vdev_id) - break; - } if (!vdev) { QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, "vdev is NULL"); @@ -5523,8 +5517,6 @@ static void dp_reset_and_release_peer_mem(struct dp_soc *soc, DP_UPDATE_STATS(vdev, peer); } } - qdf_spin_unlock_bh(&pdev->vdev_list_lock); - /* * Peer AST list hast to be empty here */ @@ -5662,6 +5654,7 @@ void dp_peer_unref_delete(void *peer_handle) /* cleanup the peer data */ dp_peer_cleanup(vdev, peer); + dp_reset_and_release_peer_mem(soc, pdev, peer, vdev); /* check whether the parent vdev has no peers left */ if (TAILQ_EMPTY(&vdev->peer_list)) { @@ -5684,7 +5677,6 @@ void dp_peer_unref_delete(void *peer_handle) } else { qdf_spin_unlock_bh(&soc->peer_ref_mutex); } - dp_reset_and_release_peer_mem(soc, pdev, peer, vdev_id); } else { qdf_spin_unlock_bh(&soc->peer_ref_mutex);