From 016a42e2c7e8048a863a5a26803cc1e9c9428990 Mon Sep 17 00:00:00 2001 From: gbian Date: Wed, 1 Mar 2017 18:49:11 +0800 Subject: [PATCH] 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 --- core/dp/txrx/ol_tx_desc.c | 8 ++++++ core/dp/txrx/ol_tx_send.c | 2 +- core/dp/txrx/ol_txrx.c | 52 +++++++++++++++++++++++++++++++++++- core/dp/txrx/ol_txrx_types.h | 4 +++ 4 files changed, 64 insertions(+), 2 deletions(-) diff --git a/core/dp/txrx/ol_tx_desc.c b/core/dp/txrx/ol_tx_desc.c index a1a2c3bf57f5..d30be107fbdd 100644 --- a/core/dp/txrx/ol_tx_desc.c +++ b/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); } diff --git a/core/dp/txrx/ol_tx_send.c b/core/dp/txrx/ol_tx_send.c index 36d70de8c053..46dd1897ba09 100644 --- a/core/dp/txrx/ol_tx_send.c +++ b/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); diff --git a/core/dp/txrx/ol_txrx.c b/core/dp/txrx/ol_txrx.c index b622ccac6fd0..7f4640e1b940 100644 --- a/core/dp/txrx/ol_txrx.c +++ b/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)" diff --git a/core/dp/txrx/ol_txrx_types.h b/core/dp/txrx/ol_txrx_types.h index ad4492556e31..404695ab46a5 100644 --- a/core/dp/txrx/ol_txrx_types.h +++ b/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;