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
This commit is contained in:
Om Prakash Tripathi
2019-04-11 17:23:57 +05:30
committed by nshrivas
parent 5cac6f52ae
commit bf529e5f40

View File

@@ -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);