qcacmn: fix dp_tx_desc invalid accessing due to race condition
crash scenario: a. dp_tx_vdev_detach will reset the vdev of TX desc to NULL by dp_tx_desc_flush. b. in the meantime, if TX completion is coming and when all TX desc is recycled, the pool will be freed if pool status is invalid before. c. invalid TX desc accessing will happen in (a). add TX desc pool lock protection in dp_tx_desc_flush. Change-Id: I65c570aa6a3044a478dbe51bbf396cf24612f675 CRs-Fixed: 2595755
此提交包含在:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for
|
||||
* any purpose with or without fee is hereby granted, provided that the
|
||||
@@ -3809,26 +3809,6 @@ dp_is_tx_desc_flush_match(struct dp_pdev *pdev,
|
||||
}
|
||||
|
||||
#ifdef QCA_LL_TX_FLOW_CONTROL_V2
|
||||
/**
|
||||
* dp_tx_desc_reset_vdev() - reset vdev to NULL in TX Desc
|
||||
*
|
||||
* @soc: Handle to DP SoC structure
|
||||
* @tx_desc: pointer of one TX desc
|
||||
* @desc_pool_id: TX Desc pool id
|
||||
*/
|
||||
static inline void
|
||||
dp_tx_desc_reset_vdev(struct dp_soc *soc, struct dp_tx_desc_s *tx_desc,
|
||||
uint8_t desc_pool_id)
|
||||
{
|
||||
struct dp_tx_desc_pool_s *pool = &soc->tx_desc[desc_pool_id];
|
||||
|
||||
qdf_spin_lock_bh(&pool->flow_pool_lock);
|
||||
|
||||
tx_desc->vdev = NULL;
|
||||
|
||||
qdf_spin_unlock_bh(&pool->flow_pool_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* dp_tx_desc_flush() - release resources associated
|
||||
* to TX Desc
|
||||
@@ -3872,6 +3852,17 @@ static void dp_tx_desc_flush(struct dp_pdev *pdev,
|
||||
!(tx_desc_pool->desc_pages.cacheable_pages))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Add flow pool lock protection in case pool is freed
|
||||
* due to all tx_desc is recycled when handle TX completion.
|
||||
* this is not necessary when do force flush as:
|
||||
* a. double lock will happen if dp_tx_desc_release is
|
||||
* also trying to acquire it.
|
||||
* b. dp interrupt has been disabled before do force TX desc
|
||||
* flush in dp_pdev_deinit().
|
||||
*/
|
||||
if (!force_free)
|
||||
qdf_spin_lock_bh(&tx_desc_pool->flow_pool_lock);
|
||||
num_desc = tx_desc_pool->pool_size;
|
||||
num_desc_per_page =
|
||||
tx_desc_pool->desc_pages.num_element_per_page;
|
||||
@@ -3895,15 +3886,22 @@ static void dp_tx_desc_flush(struct dp_pdev *pdev,
|
||||
dp_tx_comp_free_buf(soc, tx_desc);
|
||||
dp_tx_desc_release(tx_desc, i);
|
||||
} else {
|
||||
dp_tx_desc_reset_vdev(soc, tx_desc,
|
||||
i);
|
||||
tx_desc->vdev = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!force_free)
|
||||
qdf_spin_unlock_bh(&tx_desc_pool->flow_pool_lock);
|
||||
}
|
||||
}
|
||||
#else /* QCA_LL_TX_FLOW_CONTROL_V2! */
|
||||
|
||||
/**
|
||||
* dp_tx_desc_reset_vdev() - reset vdev to NULL in TX Desc
|
||||
*
|
||||
* @soc: Handle to DP soc structure
|
||||
* @tx_desc: pointer of one TX desc
|
||||
* @desc_pool_id: TX Desc pool id
|
||||
*/
|
||||
static inline void
|
||||
dp_tx_desc_reset_vdev(struct dp_soc *soc, struct dp_tx_desc_s *tx_desc,
|
||||
uint8_t desc_pool_id)
|
||||
|
新增問題並參考
封鎖使用者