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
This commit is contained in:
Poddar, Siddarth 2017-03-03 16:46:39 +05:30 • committed by snandini
commit 39ba8e0481
2 changed files with 76 additions and 14 deletions

View file

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

View file

@ -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
/**