Pārlūkot izejas kodu

qcacld-3.0: Add vdev checking in the ol_tx_desc_free to avoid crash

qcacld-2.0 to qcacld-3.0 propagation

The ol_tx_desc_free might access the invalid content of vdev referred by tx
desc, since this vdev might be detached in another thread asynchronous.

Go through tx desc pool to set corresponding tx desc's vdev to NULL
when detach this vdev, and add vdev checking in the ol_tx_desc_free to
avoid crash.

Change-Id: I3afa63659e047bbbf008440335fb71c8295ca353
CRs-Fixed: 1087690
gbian 8 gadi atpakaļ
vecāks
revīzija
016a42e2c7

+ 8 - 0
core/dp/txrx/ol_tx_desc.c

@@ -156,6 +156,8 @@ struct ol_tx_desc_t *ol_tx_desc_alloc(struct ol_txrx_pdev_t *pdev,
 	if (!tx_desc)
 		return NULL;
 
+	tx_desc->vdev_id = vdev->vdev_id;
+
 	ol_tx_desc_vdev_update(tx_desc, vdev);
 	ol_tx_desc_count_inc(vdev);
 	qdf_atomic_inc(&tx_desc->ref_cnt);
@@ -222,6 +224,8 @@ struct ol_tx_desc_t *ol_tx_desc_alloc(struct ol_txrx_pdev_t *pdev,
 		pdev->pool_stats.pkt_drop_no_pool++;
 	}
 
+	tx_desc->vdev_id = vdev->vdev_id;
+
 	return tx_desc;
 }
 
@@ -365,6 +369,7 @@ void ol_tx_desc_free(struct ol_txrx_pdev_t *pdev, struct ol_tx_desc_t *tx_desc)
 
 	ol_tx_put_desc_global_pool(pdev, tx_desc);
 	ol_tx_desc_vdev_rm(tx_desc);
+	tx_desc->vdev_id = OL_TXRX_INVALID_VDEV_ID;
 
 	qdf_spin_unlock_bh(&pdev->tx_mutex);
 }
@@ -415,6 +420,9 @@ void ol_tx_desc_free(struct ol_txrx_pdev_t *pdev, struct ol_tx_desc_t *tx_desc)
 				 __func__, __LINE__);
 		break;
 	};
+
+	tx_desc->vdev_id = OL_TXRX_INVALID_VDEV_ID;
+
 	qdf_spin_unlock_bh(&pool->flow_pool_lock);
 
 }

+ 1 - 1
core/dp/txrx/ol_tx_send.c

@@ -649,7 +649,7 @@ void ol_tx_desc_update_group_credit(ol_txrx_pdev_handle pdev,
 			OL_TXQ_GROUP_VDEV_ID_MASK_GET(
 					pdev->txq_grps[i].membership);
 		is_member = OL_TXQ_GROUP_VDEV_ID_BIT_MASK_GET(vdev_id_mask,
-				tx_desc->vdev->vdev_id);
+				tx_desc->vdev_id);
 		if (is_member) {
 			ol_txrx_update_group_credit(&pdev->txq_grps[i],
 						    credit, absolute);

+ 51 - 1
core/dp/txrx/ol_txrx.c

@@ -2061,6 +2061,34 @@ void ol_txrx_set_drop_unenc(ol_txrx_vdev_handle vdev, uint32_t val)
 	vdev->drop_unenc = val;
 }
 
+#if defined(CONFIG_HL_SUPPORT)
+
+static void
+ol_txrx_tx_desc_reset_vdev(ol_txrx_vdev_handle vdev)
+{
+	struct ol_txrx_pdev_t *pdev = vdev->pdev;
+	int i;
+	struct ol_tx_desc_t *tx_desc;
+
+	qdf_spin_lock_bh(&pdev->tx_mutex);
+	for (i = 0; i < pdev->tx_desc.pool_size; i++) {
+		tx_desc = ol_tx_desc_find(pdev, i);
+		if (tx_desc->vdev == vdev)
+			tx_desc->vdev = NULL;
+	}
+	qdf_spin_unlock_bh(&pdev->tx_mutex);
+}
+
+#else
+
+static void
+ol_txrx_tx_desc_reset_vdev(ol_txrx_vdev_handle vdev)
+{
+
+}
+
+#endif
+
 /**
  * ol_txrx_vdev_detach - Deallocate the specified data virtual
  * device object.
@@ -2153,6 +2181,18 @@ ol_txrx_vdev_detach(struct cdp_vdev *pvdev,
 
 	htt_vdev_detach(pdev->htt_pdev, vdev->vdev_id);
 
+	/*
+	* The ol_tx_desc_free might access the invalid content of vdev referred
+	* by tx desc, since this vdev might be detached in another thread
+	* asynchronous.
+	*
+	* Go through tx desc pool to set corresponding tx desc's vdev to NULL
+	* when detach this vdev, and add vdev checking in the ol_tx_desc_free
+	* to avoid crash.
+	*
+	*/
+	ol_txrx_tx_desc_reset_vdev(vdev);
+
 	/*
 	 * Doesn't matter if there are outstanding tx frames -
 	 * they will be freed once the target sends a tx completion
@@ -3035,13 +3075,23 @@ void ol_txrx_peer_unref_delete(ol_txrx_peer_handle peer)
 					vdev->delete.callback;
 				void *vdev_delete_context =
 					vdev->delete.context;
-
 				/*
 				 * Now that there are no references to the peer,
 				 * we can release the peer reference lock.
 				 */
 				qdf_spin_unlock_bh(&pdev->peer_ref_mutex);
 
+				/*
+				* The ol_tx_desc_free might access the invalid content of vdev
+				* referred by tx desc, since this vdev might be detached in
+				* another thread asynchronous.
+				*
+				* Go through tx desc pool to set corresponding tx desc's vdev
+				* to NULL when detach this vdev, and add vdev checking in the
+				* ol_tx_desc_free to avoid crash.
+				*
+				*/
+				ol_txrx_tx_desc_reset_vdev(vdev);
 				TXRX_PRINT(TXRX_PRINT_LEVEL_ERR,
 					   "%s: deleting vdev object %p "
 					   "(%02x:%02x:%02x:%02x:%02x:%02x)"

+ 4 - 0
core/dp/txrx/ol_txrx_types.h

@@ -85,6 +85,8 @@
 #define TXRX_DATA_HISTROGRAM_GRANULARITY      1000
 #define TXRX_DATA_HISTROGRAM_NUM_INTERVALS    100
 
+#define OL_TXRX_INVALID_VDEV_ID		(-1)
+
 struct ol_txrx_pdev_t;
 struct ol_txrx_vdev_t;
 struct ol_txrx_peer_t;
@@ -185,6 +187,8 @@ struct ol_tx_desc_t {
 	 */
 	uint8_t pkt_type;
 
+	u_int8_t vdev_id;
+
 	struct ol_txrx_vdev_t *vdev;
 
 	void *txq;