qcacmn: Protect pktlog under mutex to avoid possible race conditions
Protect pktlog funcitonality under given mutex to avoid possible race condition between pktlog_release/pktlog_open and pktlogmod_exit. Also call pktlogmod_exit before calling wdi_event_detach to avoid accessing freed memory in pktlog release. Change-Id: I5ca4b304d0f4dc1af289daa167958d5b773d9a6e CRs-Fixed: 2578623
This commit is contained in:
@@ -132,6 +132,9 @@ void pktlog_callback(void *pdev, enum WDI_EVENT event, void *log_data,
|
|||||||
void pktlog_init(struct hif_opaque_softc *scn);
|
void pktlog_init(struct hif_opaque_softc *scn);
|
||||||
int pktlog_enable(struct hif_opaque_softc *scn, int32_t log_state,
|
int pktlog_enable(struct hif_opaque_softc *scn, int32_t log_state,
|
||||||
bool, uint8_t, uint32_t);
|
bool, uint8_t, uint32_t);
|
||||||
|
int __pktlog_enable(struct hif_opaque_softc *scn, int32_t log_state,
|
||||||
|
bool ini_triggered, uint8_t user_triggered,
|
||||||
|
uint32_t is_iwpriv_command);
|
||||||
int pktlog_setsize(struct hif_opaque_softc *scn, int32_t log_state);
|
int pktlog_setsize(struct hif_opaque_softc *scn, int32_t log_state);
|
||||||
int pktlog_clearbuff(struct hif_opaque_softc *scn, bool clear_buff);
|
int pktlog_clearbuff(struct hif_opaque_softc *scn, bool clear_buff);
|
||||||
int pktlog_disable(struct hif_opaque_softc *scn);
|
int pktlog_disable(struct hif_opaque_softc *scn);
|
||||||
@@ -171,6 +174,14 @@ static inline int pktlog_enable(struct hif_opaque_softc *scn, int32_t log_state,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
int __pktlog_enable(struct hif_opaque_softc *scn, int32_t log_state,
|
||||||
|
bool ini_triggered, uint8_t user_triggered,
|
||||||
|
uint32_t is_iwpriv_command)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int pktlog_setsize(struct hif_opaque_softc *scn,
|
static inline int pktlog_setsize(struct hif_opaque_softc *scn,
|
||||||
int32_t log_state)
|
int32_t log_state)
|
||||||
{
|
{
|
||||||
|
@@ -506,6 +506,12 @@ static void pktlog_detach(struct hif_opaque_softc *scn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pl_info = pl_dev->pl_info;
|
pl_info = pl_dev->pl_info;
|
||||||
|
if (!pl_info) {
|
||||||
|
qdf_print("%s: Invalid pktlog handle", __func__);
|
||||||
|
ASSERT(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mutex_lock(&pl_info->pktlog_mutex);
|
||||||
remove_proc_entry(WLANDEV_BASENAME, g_pktlog_pde);
|
remove_proc_entry(WLANDEV_BASENAME, g_pktlog_pde);
|
||||||
pktlog_sysctl_unregister(pl_dev);
|
pktlog_sysctl_unregister(pl_dev);
|
||||||
|
|
||||||
@@ -516,6 +522,7 @@ static void pktlog_detach(struct hif_opaque_softc *scn)
|
|||||||
pl_dev->tgt_pktlog_alloced = false;
|
pl_dev->tgt_pktlog_alloced = false;
|
||||||
}
|
}
|
||||||
qdf_spin_unlock_bh(&pl_info->log_lock);
|
qdf_spin_unlock_bh(&pl_info->log_lock);
|
||||||
|
mutex_unlock(&pl_info->pktlog_mutex);
|
||||||
pktlog_cleanup(pl_info);
|
pktlog_cleanup(pl_info);
|
||||||
|
|
||||||
if (pl_dev) {
|
if (pl_dev) {
|
||||||
@@ -529,25 +536,12 @@ static int __pktlog_open(struct inode *i, struct file *f)
|
|||||||
struct hif_opaque_softc *scn;
|
struct hif_opaque_softc *scn;
|
||||||
struct pktlog_dev_t *pl_dev;
|
struct pktlog_dev_t *pl_dev;
|
||||||
struct ath_pktlog_info *pl_info;
|
struct ath_pktlog_info *pl_info;
|
||||||
|
struct ath_pktlog_info_lnx *pl_info_lnx;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
PKTLOG_MOD_INC_USE_COUNT;
|
PKTLOG_MOD_INC_USE_COUNT;
|
||||||
pl_info = PDE_DATA(f->f_path.dentry->d_inode);
|
|
||||||
if (!pl_info) {
|
|
||||||
qdf_nofl_err("%s: pl_info NULL", __func__);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pl_info->curr_pkt_state != PKTLOG_OPR_NOT_IN_PROGRESS) {
|
|
||||||
qdf_nofl_info("%s: plinfo state (%d) != PKTLOG_OPR_NOT_IN_PROGRESS",
|
|
||||||
__func__, pl_info->curr_pkt_state);
|
|
||||||
return -EBUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
pl_info->curr_pkt_state = PKTLOG_OPR_IN_PROGRESS_READ_START;
|
|
||||||
scn = cds_get_context(QDF_MODULE_ID_HIF);
|
scn = cds_get_context(QDF_MODULE_ID_HIF);
|
||||||
if (!scn) {
|
if (!scn) {
|
||||||
pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
|
|
||||||
qdf_print("%s: Invalid scn context", __func__);
|
qdf_print("%s: Invalid scn context", __func__);
|
||||||
ASSERT(0);
|
ASSERT(0);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -556,12 +550,38 @@ static int __pktlog_open(struct inode *i, struct file *f)
|
|||||||
pl_dev = get_pktlog_handle();
|
pl_dev = get_pktlog_handle();
|
||||||
|
|
||||||
if (!pl_dev) {
|
if (!pl_dev) {
|
||||||
pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
|
|
||||||
qdf_print("%s: Invalid pktlog handle", __func__);
|
qdf_print("%s: Invalid pktlog handle", __func__);
|
||||||
ASSERT(0);
|
ASSERT(0);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pl_info = pl_dev->pl_info;
|
||||||
|
|
||||||
|
if (!pl_info) {
|
||||||
|
qdf_nofl_err("%s: pl_info NULL", __func__);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&pl_info->pktlog_mutex);
|
||||||
|
pl_info_lnx = (pl_dev) ? PL_INFO_LNX(pl_dev->pl_info) :
|
||||||
|
PL_INFO_LNX(g_pktlog_info);
|
||||||
|
|
||||||
|
if (!pl_info_lnx->sysctl_header) {
|
||||||
|
mutex_unlock(&pl_info->pktlog_mutex);
|
||||||
|
qdf_print("%s: pktlog sysctl is unergistered.", __func__);
|
||||||
|
ASSERT(0);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pl_info->curr_pkt_state != PKTLOG_OPR_NOT_IN_PROGRESS) {
|
||||||
|
mutex_unlock(&pl_info->pktlog_mutex);
|
||||||
|
qdf_print("%s: plinfo state (%d) != PKTLOG_OPR_NOT_IN_PROGRESS",
|
||||||
|
__func__, pl_info->curr_pkt_state);
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
pl_info->curr_pkt_state = PKTLOG_OPR_IN_PROGRESS_READ_START;
|
||||||
|
|
||||||
pl_info->init_saved_state = pl_info->log_state;
|
pl_info->init_saved_state = pl_info->log_state;
|
||||||
if (!pl_info->log_state) {
|
if (!pl_info->log_state) {
|
||||||
/* Pktlog is already disabled.
|
/* Pktlog is already disabled.
|
||||||
@@ -569,6 +589,7 @@ static int __pktlog_open(struct inode *i, struct file *f)
|
|||||||
*/
|
*/
|
||||||
pl_info->curr_pkt_state =
|
pl_info->curr_pkt_state =
|
||||||
PKTLOG_OPR_IN_PROGRESS_READ_START_PKTLOG_DISABLED;
|
PKTLOG_OPR_IN_PROGRESS_READ_START_PKTLOG_DISABLED;
|
||||||
|
mutex_unlock(&pl_info->pktlog_mutex);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
/* Disbable the pktlog internally. */
|
/* Disbable the pktlog internally. */
|
||||||
@@ -576,6 +597,7 @@ static int __pktlog_open(struct inode *i, struct file *f)
|
|||||||
pl_info->log_state = 0;
|
pl_info->log_state = 0;
|
||||||
pl_info->curr_pkt_state =
|
pl_info->curr_pkt_state =
|
||||||
PKTLOG_OPR_IN_PROGRESS_READ_START_PKTLOG_DISABLED;
|
PKTLOG_OPR_IN_PROGRESS_READ_START_PKTLOG_DISABLED;
|
||||||
|
mutex_unlock(&pl_info->pktlog_mutex);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -600,17 +622,12 @@ static int __pktlog_release(struct inode *i, struct file *f)
|
|||||||
struct hif_opaque_softc *scn;
|
struct hif_opaque_softc *scn;
|
||||||
struct pktlog_dev_t *pl_dev;
|
struct pktlog_dev_t *pl_dev;
|
||||||
struct ath_pktlog_info *pl_info;
|
struct ath_pktlog_info *pl_info;
|
||||||
|
struct ath_pktlog_info_lnx *pl_info_lnx;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
PKTLOG_MOD_DEC_USE_COUNT;
|
PKTLOG_MOD_DEC_USE_COUNT;
|
||||||
|
|
||||||
pl_info = PDE_DATA(f->f_path.dentry->d_inode);
|
|
||||||
if (!pl_info)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
scn = cds_get_context(QDF_MODULE_ID_HIF);
|
scn = cds_get_context(QDF_MODULE_ID_HIF);
|
||||||
if (!scn) {
|
if (!scn) {
|
||||||
pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
|
|
||||||
qdf_print("%s: Invalid scn context", __func__);
|
qdf_print("%s: Invalid scn context", __func__);
|
||||||
ASSERT(0);
|
ASSERT(0);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -619,12 +636,30 @@ static int __pktlog_release(struct inode *i, struct file *f)
|
|||||||
pl_dev = get_pktlog_handle();
|
pl_dev = get_pktlog_handle();
|
||||||
|
|
||||||
if (!pl_dev) {
|
if (!pl_dev) {
|
||||||
pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
|
|
||||||
qdf_print("%s: Invalid pktlog handle", __func__);
|
qdf_print("%s: Invalid pktlog handle", __func__);
|
||||||
ASSERT(0);
|
ASSERT(0);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pl_info = pl_dev->pl_info;
|
||||||
|
|
||||||
|
if (!pl_info) {
|
||||||
|
qdf_print("%s: Invalid pktlog info", __func__);
|
||||||
|
ASSERT(0);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&pl_info->pktlog_mutex);
|
||||||
|
pl_info_lnx = (pl_dev) ? PL_INFO_LNX(pl_dev->pl_info) :
|
||||||
|
PL_INFO_LNX(g_pktlog_info);
|
||||||
|
|
||||||
|
if (!pl_info_lnx->sysctl_header) {
|
||||||
|
pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
|
||||||
|
mutex_unlock(&pl_info->pktlog_mutex);
|
||||||
|
qdf_print("%s: pktlog sysctl is unergistered.", __func__);
|
||||||
|
ASSERT(0);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
pl_info->curr_pkt_state = PKTLOG_OPR_IN_PROGRESS_READ_COMPLETE;
|
pl_info->curr_pkt_state = PKTLOG_OPR_IN_PROGRESS_READ_COMPLETE;
|
||||||
/*clear pktlog buffer.*/
|
/*clear pktlog buffer.*/
|
||||||
pktlog_clearbuff(scn, true);
|
pktlog_clearbuff(scn, true);
|
||||||
@@ -632,15 +667,16 @@ static int __pktlog_release(struct inode *i, struct file *f)
|
|||||||
pl_info->init_saved_state = 0;
|
pl_info->init_saved_state = 0;
|
||||||
|
|
||||||
/*Enable pktlog again*/
|
/*Enable pktlog again*/
|
||||||
ret = pl_dev->pl_funcs->pktlog_enable(
|
ret = __pktlog_enable(
|
||||||
(struct hif_opaque_softc *)scn, pl_info->log_state,
|
(struct hif_opaque_softc *)scn, pl_info->log_state,
|
||||||
cds_is_packet_log_enabled(), 0, 1);
|
cds_is_packet_log_enabled(), 0, 1);
|
||||||
|
|
||||||
if (ret != 0)
|
|
||||||
qdf_nofl_warn("%s: pktlog cannot be enabled. ret value %d",
|
|
||||||
__func__, ret);
|
|
||||||
|
|
||||||
pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
|
pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
|
||||||
|
mutex_unlock(&pl_info->pktlog_mutex);
|
||||||
|
if (ret != 0)
|
||||||
|
qdf_print("%s: pktlog cannot be enabled. ret value %d",
|
||||||
|
__func__, ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -625,9 +625,9 @@ void pktlog_init(struct hif_opaque_softc *scn)
|
|||||||
pktlog_callback_registration(pl_dev->callback_type);
|
pktlog_callback_registration(pl_dev->callback_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __pktlog_enable(struct hif_opaque_softc *scn, int32_t log_state,
|
int __pktlog_enable(struct hif_opaque_softc *scn, int32_t log_state,
|
||||||
bool ini_triggered, uint8_t user_triggered,
|
bool ini_triggered, uint8_t user_triggered,
|
||||||
uint32_t is_iwpriv_command)
|
uint32_t is_iwpriv_command)
|
||||||
{
|
{
|
||||||
struct pktlog_dev_t *pl_dev;
|
struct pktlog_dev_t *pl_dev;
|
||||||
struct ath_pktlog_info *pl_info;
|
struct ath_pktlog_info *pl_info;
|
||||||
|
Reference in New Issue
Block a user