qcacld-3.0: Add debug for TSO seg double-free
Add TSO segment debug code, in a featurized way, so that when disabled it will tolerate redundant returns to the internal pool and when enabled will check sanity on free, and record a history of last 16 actions on the segment in the object. Goes with the corresponding cmn component counterpart. Change-Id: Ifab52fc2032da4d53b708b3c6716d5270c0690c1 CRs-Fixed: 2031485
This commit is contained in:

committed by
snandini

parent
a953ca7543
commit
e062f35889
@@ -186,6 +186,8 @@ static inline uint8_t ol_tx_prepare_tso(ol_txrx_vdev_handle vdev,
|
|||||||
struct qdf_tso_seg_elem_t *tso_seg =
|
struct qdf_tso_seg_elem_t *tso_seg =
|
||||||
ol_tso_alloc_segment(vdev->pdev);
|
ol_tso_alloc_segment(vdev->pdev);
|
||||||
if (tso_seg) {
|
if (tso_seg) {
|
||||||
|
qdf_tso_seg_dbg_record(tso_seg,
|
||||||
|
TSOSEG_LOC_PREPARETSO);
|
||||||
tso_seg->next =
|
tso_seg->next =
|
||||||
msdu_info->tso_info.tso_seg_list;
|
msdu_info->tso_info.tso_seg_list;
|
||||||
msdu_info->tso_info.tso_seg_list
|
msdu_info->tso_info.tso_seg_list
|
||||||
@@ -534,6 +536,9 @@ ol_tx_prepare_ll_fast(struct ol_txrx_pdev_t *pdev,
|
|||||||
tx_desc->netbuf = msdu;
|
tx_desc->netbuf = msdu;
|
||||||
if (msdu_info->tso_info.is_tso) {
|
if (msdu_info->tso_info.is_tso) {
|
||||||
tx_desc->tso_desc = msdu_info->tso_info.curr_seg;
|
tx_desc->tso_desc = msdu_info->tso_info.curr_seg;
|
||||||
|
qdf_tso_seg_dbg_setowner(tx_desc->tso_desc, tx_desc);
|
||||||
|
qdf_tso_seg_dbg_record(tx_desc->tso_desc,
|
||||||
|
TSOSEG_LOC_TXPREPLLFAST);
|
||||||
tx_desc->tso_num_desc = msdu_info->tso_info.tso_num_seg_list;
|
tx_desc->tso_num_desc = msdu_info->tso_info.tso_num_seg_list;
|
||||||
tx_desc->pkt_type = OL_TX_FRM_TSO;
|
tx_desc->pkt_type = OL_TX_FRM_TSO;
|
||||||
TXRX_STATS_MSDU_INCR(pdev, tx.tso.tso_pkts, msdu);
|
TXRX_STATS_MSDU_INCR(pdev, tx.tso.tso_pkts, msdu);
|
||||||
@@ -2013,6 +2018,11 @@ void ol_tso_seg_list_init(struct ol_txrx_pdev_t *pdev, uint32_t num_seg)
|
|||||||
/* set the freelist bit and magic cookie*/
|
/* set the freelist bit and magic cookie*/
|
||||||
c_element->on_freelist = 1;
|
c_element->on_freelist = 1;
|
||||||
c_element->cookie = TSO_SEG_MAGIC_COOKIE;
|
c_element->cookie = TSO_SEG_MAGIC_COOKIE;
|
||||||
|
#ifdef TSOSEG_DEBUG
|
||||||
|
c_element->dbg.txdesc = NULL;
|
||||||
|
c_element->dbg.cur = -1; /* history empty */
|
||||||
|
qdf_tso_seg_dbg_record(c_element, TSOSEG_LOC_INIT1);
|
||||||
|
#endif /* TSOSEG_DEBUG */
|
||||||
c_element->next =
|
c_element->next =
|
||||||
qdf_mem_malloc(sizeof(struct qdf_tso_seg_elem_t));
|
qdf_mem_malloc(sizeof(struct qdf_tso_seg_elem_t));
|
||||||
c_element = c_element->next;
|
c_element = c_element->next;
|
||||||
@@ -2032,6 +2042,11 @@ void ol_tso_seg_list_init(struct ol_txrx_pdev_t *pdev, uint32_t num_seg)
|
|||||||
}
|
}
|
||||||
c_element->on_freelist = 1;
|
c_element->on_freelist = 1;
|
||||||
c_element->cookie = TSO_SEG_MAGIC_COOKIE;
|
c_element->cookie = TSO_SEG_MAGIC_COOKIE;
|
||||||
|
#ifdef TSOSEG_DEBUG
|
||||||
|
c_element->dbg.txdesc = NULL;
|
||||||
|
c_element->dbg.cur = -1; /* history empty */
|
||||||
|
qdf_tso_seg_dbg_record(c_element, TSOSEG_LOC_INIT2);
|
||||||
|
#endif /* TSOSEG_DEBUG */
|
||||||
c_element->next = NULL;
|
c_element->next = NULL;
|
||||||
pdev->tso_seg_pool.pool_size = num_seg;
|
pdev->tso_seg_pool.pool_size = num_seg;
|
||||||
pdev->tso_seg_pool.num_free = num_seg;
|
pdev->tso_seg_pool.num_free = num_seg;
|
||||||
@@ -2069,8 +2084,7 @@ void ol_tso_seg_list_deinit(struct ol_txrx_pdev_t *pdev)
|
|||||||
while (i-- > 0 && c_element) {
|
while (i-- > 0 && c_element) {
|
||||||
temp = c_element->next;
|
temp = c_element->next;
|
||||||
if (c_element->on_freelist != 1) {
|
if (c_element->on_freelist != 1) {
|
||||||
qdf_print("this seg memory is already freed (double free?)");
|
qdf_tso_seg_dbg_bug("this seg already freed (double?)");
|
||||||
QDF_BUG(0);
|
|
||||||
return;
|
return;
|
||||||
} else if (c_element->cookie != TSO_SEG_MAGIC_COOKIE) {
|
} else if (c_element->cookie != TSO_SEG_MAGIC_COOKIE) {
|
||||||
qdf_print("this seg cookie is bad (memory corruption?)");
|
qdf_print("this seg cookie is bad (memory corruption?)");
|
||||||
|
@@ -29,6 +29,7 @@
|
|||||||
#include <qdf_nbuf.h> /* qdf_nbuf_t, etc. */
|
#include <qdf_nbuf.h> /* qdf_nbuf_t, etc. */
|
||||||
#include <qdf_util.h> /* qdf_assert */
|
#include <qdf_util.h> /* qdf_assert */
|
||||||
#include <qdf_lock.h> /* qdf_spinlock */
|
#include <qdf_lock.h> /* qdf_spinlock */
|
||||||
|
#include <qdf_trace.h> /* qdf_tso_seg_dbg stuff */
|
||||||
#ifdef QCA_COMPUTE_TX_DELAY
|
#ifdef QCA_COMPUTE_TX_DELAY
|
||||||
#include <qdf_time.h> /* qdf_system_ticks */
|
#include <qdf_time.h> /* qdf_system_ticks */
|
||||||
#endif
|
#endif
|
||||||
@@ -761,6 +762,31 @@ free_tx_desc:
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined(FEATURE_TSO)
|
#if defined(FEATURE_TSO)
|
||||||
|
#ifdef TSOSEG_DEBUG
|
||||||
|
static int
|
||||||
|
ol_tso_seg_dbg_sanitize(struct qdf_tso_seg_elem_t *tsoseg)
|
||||||
|
{
|
||||||
|
int rc = -1;
|
||||||
|
struct ol_tx_desc_t *txdesc;
|
||||||
|
|
||||||
|
if (tsoseg != NULL) {
|
||||||
|
txdesc = tsoseg->dbg.txdesc;
|
||||||
|
if (txdesc->tso_desc != tsoseg)
|
||||||
|
qdf_tso_seg_dbg_bug("Owner sanity failed");
|
||||||
|
else
|
||||||
|
rc = 0;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
static int
|
||||||
|
ol_tso_seg_dbg_sanitize(struct qdf_tso_seg_elem_t *tsoseg)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* TSOSEG_DEBUG */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ol_tso_alloc_segment() - function to allocate a TSO segment
|
* ol_tso_alloc_segment() - function to allocate a TSO segment
|
||||||
* element
|
* element
|
||||||
@@ -792,6 +818,7 @@ struct qdf_tso_seg_elem_t *ol_tso_alloc_segment(struct ol_txrx_pdev_t *pdev)
|
|||||||
}
|
}
|
||||||
/*this tso seg is not a part of freelist now.*/
|
/*this tso seg is not a part of freelist now.*/
|
||||||
tso_seg->on_freelist = 0;
|
tso_seg->on_freelist = 0;
|
||||||
|
qdf_tso_seg_dbg_record(tso_seg, TSOSEG_LOC_ALLOC);
|
||||||
pdev->tso_seg_pool.freelist = pdev->tso_seg_pool.freelist->next;
|
pdev->tso_seg_pool.freelist = pdev->tso_seg_pool.freelist->next;
|
||||||
}
|
}
|
||||||
qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex);
|
qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex);
|
||||||
@@ -815,9 +842,8 @@ void ol_tso_free_segment(struct ol_txrx_pdev_t *pdev,
|
|||||||
{
|
{
|
||||||
qdf_spin_lock_bh(&pdev->tso_seg_pool.tso_mutex);
|
qdf_spin_lock_bh(&pdev->tso_seg_pool.tso_mutex);
|
||||||
if (tso_seg->on_freelist != 0) {
|
if (tso_seg->on_freelist != 0) {
|
||||||
qdf_print("Do not free the tso seg as this seg is already freed");
|
|
||||||
qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex);
|
qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex);
|
||||||
QDF_BUG(0);
|
qdf_tso_seg_dbg_bug("Do not free tso seg, already freed");
|
||||||
return;
|
return;
|
||||||
} else if (tso_seg->cookie != TSO_SEG_MAGIC_COOKIE) {
|
} else if (tso_seg->cookie != TSO_SEG_MAGIC_COOKIE) {
|
||||||
qdf_print("Do not free the tso seg as cookie is not good. Looks like memory corruption");
|
qdf_print("Do not free the tso seg as cookie is not good. Looks like memory corruption");
|
||||||
@@ -825,11 +851,15 @@ void ol_tso_free_segment(struct ol_txrx_pdev_t *pdev,
|
|||||||
QDF_BUG(0);
|
QDF_BUG(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
/* sanitize before free */
|
||||||
|
ol_tso_seg_dbg_sanitize(tso_seg);
|
||||||
/*this tso seg is now a part of freelist*/
|
/*this tso seg is now a part of freelist*/
|
||||||
qdf_mem_zero(tso_seg, sizeof(*tso_seg));
|
/* retain segment history, if debug is enabled */
|
||||||
|
qdf_tso_seg_dbg_zero(tso_seg);
|
||||||
tso_seg->next = pdev->tso_seg_pool.freelist;
|
tso_seg->next = pdev->tso_seg_pool.freelist;
|
||||||
tso_seg->on_freelist = 1;
|
tso_seg->on_freelist = 1;
|
||||||
tso_seg->cookie = TSO_SEG_MAGIC_COOKIE;
|
tso_seg->cookie = TSO_SEG_MAGIC_COOKIE;
|
||||||
|
qdf_tso_seg_dbg_record(tso_seg, TSOSEG_LOC_FREE);
|
||||||
pdev->tso_seg_pool.freelist = tso_seg;
|
pdev->tso_seg_pool.freelist = tso_seg;
|
||||||
pdev->tso_seg_pool.num_free++;
|
pdev->tso_seg_pool.num_free++;
|
||||||
qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex);
|
qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex);
|
||||||
|
Reference in New Issue
Block a user