From 39ba8e04818f4071a29d641fa932071efe63bd79 Mon Sep 17 00:00:00 2001 From: "Poddar, Siddarth" Date: Fri, 3 Mar 2017 16:46:39 +0530 Subject: [PATCH] qcacld-3.0: Fix memory leaks of TSO num segments Fix memory leaks of TSO num segments by freeing remaining TSO num segments in ol_tx_ll_fast and ol_tx_ll if somehow allocated tx desc is NULL. Change-Id: I577a95b784c776633cf685cd16b101755a48c521 CRs-Fixed: 2014587 --- core/dp/txrx/ol_tx.c | 83 +++++++++++++++++++++++++++++++++------ core/dp/txrx/ol_tx_desc.h | 7 ++-- 2 files changed, 76 insertions(+), 14 deletions(-) diff --git a/core/dp/txrx/ol_tx.c b/core/dp/txrx/ol_tx.c index 1fdaa3a4d85d..8eec8e5026b1 100644 --- a/core/dp/txrx/ol_tx.c +++ b/core/dp/txrx/ol_tx.c @@ -82,7 +82,7 @@ int ce_send_fast(struct CE_handle *copyeng, qdf_nbuf_t msdu, */ \ if (qdf_nbuf_is_tso(msdu)) \ ol_free_remaining_tso_segs( \ - vdev, msdu_info); \ + vdev, msdu_info, true); \ TXRX_STATS_MSDU_LIST_INCR( \ pdev, tx.dropped.host_reject, msdu); \ return msdu; /* the list of unaccepted MSDUs */ \ @@ -91,17 +91,77 @@ int ce_send_fast(struct CE_handle *copyeng, qdf_nbuf_t msdu, #if defined(FEATURE_TSO) void ol_free_remaining_tso_segs(ol_txrx_vdev_handle vdev, - struct ol_txrx_msdu_info_t *msdu_info) + struct ol_txrx_msdu_info_t *msdu_info, + bool is_tso_seg_mapping_done) { struct qdf_tso_seg_elem_t *next_seg; struct qdf_tso_seg_elem_t *free_seg = msdu_info->tso_info.curr_seg; + struct ol_txrx_pdev_t *pdev; + bool is_last_seg = false; - while (free_seg) { - next_seg = free_seg->next; - ol_tso_free_segment(vdev->pdev, free_seg); - free_seg = next_seg; + if (qdf_unlikely(!vdev)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s:vdev is null", __func__); + return; + } else { + pdev = vdev->pdev; + if (qdf_unlikely(!pdev)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s:pdev is null", __func__); + return; + } + } + + if (is_tso_seg_mapping_done) { + /* + * TSO segment are mapped already, therefore, + * 1. unmap the tso segments, + * 2. free tso num segment if it is a last segment, and + * 3. free the tso segments. + */ + struct qdf_tso_num_seg_elem_t *tso_num_desc = + msdu_info->tso_info.tso_num_seg_list; + + if (qdf_unlikely(tso_num_desc == NULL)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s %d TSO common info is NULL!", + __func__, __LINE__); + return; + } + + while (free_seg) { + qdf_spin_lock_bh(&pdev->tso_seg_pool.tso_mutex); + tso_num_desc->num_seg.tso_cmn_num_seg--; + + is_last_seg = (tso_num_desc->num_seg.tso_cmn_num_seg == + 0) ? true : false; + qdf_nbuf_unmap_tso_segment(pdev->osdev, free_seg, + is_last_seg); + qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex); + + if (is_last_seg) { + ol_tso_num_seg_free(pdev, + msdu_info->tso_info.tso_num_seg_list); + msdu_info->tso_info.tso_num_seg_list = NULL; + } + + next_seg = free_seg->next; + ol_tso_free_segment(pdev, free_seg); + free_seg = next_seg; + } + } else { + /* + * TSO segment are not mapped therefore, + * free the tso segments only. + */ + while (free_seg) { + next_seg = free_seg->next; + ol_tso_free_segment(pdev, free_seg); + free_seg = next_seg; + } } } + /** * ol_tx_prepare_tso() - Given a jumbo msdu, prepare the TSO * related information in the msdu_info meta data @@ -135,7 +195,8 @@ static inline uint8_t ol_tx_prepare_tso(ol_txrx_vdev_handle vdev, /* Free above alocated TSO segements till now */ msdu_info->tso_info.curr_seg = msdu_info->tso_info.tso_seg_list; - ol_free_remaining_tso_segs(vdev, msdu_info); + ol_free_remaining_tso_segs(vdev, msdu_info, + false); return 1; } } @@ -148,7 +209,7 @@ static inline uint8_t ol_tx_prepare_tso(ol_txrx_vdev_handle vdev, /* Free the already allocated num of segments */ msdu_info->tso_info.curr_seg = msdu_info->tso_info.tso_seg_list; - ol_free_remaining_tso_segs(vdev, msdu_info); + ol_free_remaining_tso_segs(vdev, msdu_info, false); return 1; } @@ -157,7 +218,7 @@ static inline uint8_t ol_tx_prepare_tso(ol_txrx_vdev_handle vdev, /* Free the already allocated num of segments */ msdu_info->tso_info.curr_seg = msdu_info->tso_info.tso_seg_list; - ol_free_remaining_tso_segs(vdev, msdu_info); + ol_free_remaining_tso_segs(vdev, msdu_info, false); return 1; } @@ -725,7 +786,7 @@ ol_tx_ll_fast(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list) tso_info->curr_seg = tso_info->curr_seg->next; ol_free_remaining_tso_segs(vdev, - &msdu_info); + &msdu_info, true); } /* @@ -757,7 +818,7 @@ ol_tx_ll_fast(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list) */ if (qdf_nbuf_is_tso(msdu)) ol_free_remaining_tso_segs(vdev, - &msdu_info); + &msdu_info, true); TXRX_STATS_MSDU_LIST_INCR( pdev, tx.dropped.host_reject, msdu); diff --git a/core/dp/txrx/ol_tx_desc.h b/core/dp/txrx/ol_tx_desc.h index a9155d9747c6..7c6f5c2d6ccb 100644 --- a/core/dp/txrx/ol_tx_desc.h +++ b/core/dp/txrx/ol_tx_desc.h @@ -233,15 +233,16 @@ struct qdf_tso_num_seg_elem_t *ol_tso_num_seg_alloc( void ol_tso_num_seg_free(struct ol_txrx_pdev_t *pdev, struct qdf_tso_num_seg_elem_t *tso_num_seg); void ol_free_remaining_tso_segs(ol_txrx_vdev_handle vdev, - struct ol_txrx_msdu_info_t *msdu_info); + struct ol_txrx_msdu_info_t *msdu_info, + bool is_tso_seg_mapping_done); #else #define ol_tso_alloc_segment(pdev) /*no-op*/ #define ol_tso_free_segment(pdev, tso_seg) /*no-op*/ #define ol_tso_num_seg_alloc(pdev) /*no-op*/ #define ol_tso_num_seg_free(pdev, tso_num_seg) /*no-op*/ -#define ol_free_remaining_tso_segs(vdev, msdu_info) /*no-op*/ - +/*no-op*/ +#define ol_free_remaining_tso_segs(vdev, msdu_info, is_tso_seg_mapping_done) #endif /**