Browse Source

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
Om Prakash Tripathi 6 years ago
parent
commit
bf529e5f40
1 changed files with 2 additions and 10 deletions
  1. 2 10
      dp/wifi3.0/dp_main.c

+ 2 - 10
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);