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);
|
||||
int pktlog_enable(struct hif_opaque_softc *scn, int32_t log_state,
|
||||
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_clearbuff(struct hif_opaque_softc *scn, bool clear_buff);
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
int32_t log_state)
|
||||
{
|
||||
|
@@ -506,6 +506,12 @@ static void pktlog_detach(struct hif_opaque_softc *scn)
|
||||
}
|
||||
|
||||
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);
|
||||
pktlog_sysctl_unregister(pl_dev);
|
||||
|
||||
@@ -516,6 +522,7 @@ static void pktlog_detach(struct hif_opaque_softc *scn)
|
||||
pl_dev->tgt_pktlog_alloced = false;
|
||||
}
|
||||
qdf_spin_unlock_bh(&pl_info->log_lock);
|
||||
mutex_unlock(&pl_info->pktlog_mutex);
|
||||
pktlog_cleanup(pl_info);
|
||||
|
||||
if (pl_dev) {
|
||||
@@ -529,25 +536,12 @@ static int __pktlog_open(struct inode *i, struct file *f)
|
||||
struct hif_opaque_softc *scn;
|
||||
struct pktlog_dev_t *pl_dev;
|
||||
struct ath_pktlog_info *pl_info;
|
||||
struct ath_pktlog_info_lnx *pl_info_lnx;
|
||||
int ret = 0;
|
||||
|
||||
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);
|
||||
if (!scn) {
|
||||
pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
|
||||
qdf_print("%s: Invalid scn context", __func__);
|
||||
ASSERT(0);
|
||||
return -EINVAL;
|
||||
@@ -556,12 +550,38 @@ static int __pktlog_open(struct inode *i, struct file *f)
|
||||
pl_dev = get_pktlog_handle();
|
||||
|
||||
if (!pl_dev) {
|
||||
pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
|
||||
qdf_print("%s: Invalid pktlog handle", __func__);
|
||||
ASSERT(0);
|
||||
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;
|
||||
if (!pl_info->log_state) {
|
||||
/* Pktlog is already disabled.
|
||||
@@ -569,6 +589,7 @@ static int __pktlog_open(struct inode *i, struct file *f)
|
||||
*/
|
||||
pl_info->curr_pkt_state =
|
||||
PKTLOG_OPR_IN_PROGRESS_READ_START_PKTLOG_DISABLED;
|
||||
mutex_unlock(&pl_info->pktlog_mutex);
|
||||
return ret;
|
||||
}
|
||||
/* 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->curr_pkt_state =
|
||||
PKTLOG_OPR_IN_PROGRESS_READ_START_PKTLOG_DISABLED;
|
||||
mutex_unlock(&pl_info->pktlog_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -600,17 +622,12 @@ static int __pktlog_release(struct inode *i, struct file *f)
|
||||
struct hif_opaque_softc *scn;
|
||||
struct pktlog_dev_t *pl_dev;
|
||||
struct ath_pktlog_info *pl_info;
|
||||
struct ath_pktlog_info_lnx *pl_info_lnx;
|
||||
int ret = 0;
|
||||
|
||||
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);
|
||||
if (!scn) {
|
||||
pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
|
||||
qdf_print("%s: Invalid scn context", __func__);
|
||||
ASSERT(0);
|
||||
return -EINVAL;
|
||||
@@ -619,12 +636,30 @@ static int __pktlog_release(struct inode *i, struct file *f)
|
||||
pl_dev = get_pktlog_handle();
|
||||
|
||||
if (!pl_dev) {
|
||||
pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
|
||||
qdf_print("%s: Invalid pktlog handle", __func__);
|
||||
ASSERT(0);
|
||||
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;
|
||||
/*clear pktlog buffer.*/
|
||||
pktlog_clearbuff(scn, true);
|
||||
@@ -632,15 +667,16 @@ static int __pktlog_release(struct inode *i, struct file *f)
|
||||
pl_info->init_saved_state = 0;
|
||||
|
||||
/*Enable pktlog again*/
|
||||
ret = pl_dev->pl_funcs->pktlog_enable(
|
||||
ret = __pktlog_enable(
|
||||
(struct hif_opaque_softc *)scn, pl_info->log_state,
|
||||
cds_is_packet_log_enabled(), 0, 1);
|
||||
|
||||
pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
|
||||
mutex_unlock(&pl_info->pktlog_mutex);
|
||||
if (ret != 0)
|
||||
qdf_nofl_warn("%s: pktlog cannot be enabled. ret value %d",
|
||||
qdf_print("%s: pktlog cannot be enabled. ret value %d",
|
||||
__func__, ret);
|
||||
|
||||
pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@@ -625,7 +625,7 @@ void pktlog_init(struct hif_opaque_softc *scn)
|
||||
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,
|
||||
uint32_t is_iwpriv_command)
|
||||
{
|
||||
|
Reference in New Issue
Block a user