mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-14 00:24:41 -04:00
qcacmn: Fix the nol timeout panic
In macro TAILQ_FOREACH_SAFE, var and tvar point to current head and the next element respectively. If we unlock the spinlock inside the for loop and then lock it again, there is a chance (race) that the next element is pointed to by another thread of execution and both of them may try to remove the same element at the same time. This may lead to panic. Instead of using TAILQ_FOREACH_SAFE macro remove the element from the list one by one using a while loop from the head of the list. Do not lock the entire while loop, instead lock only during the removal of element from the list. This is required because we want to wait for the dfs_remove_from_nol timer to complete. But the wait should not be done from inside the lock because the same lock is used by the dfs_remove_from_nol timer. Change-Id: If820dbb1789b7fcfc33c133b3f90968377bfbf3c CRs-Fixed: 2322831
This commit is contained in:
parent
584a187b8d
commit
e3807d4e50
1 changed files with 27 additions and 26 deletions
|
|
@ -116,22 +116,24 @@ static os_timer_func(dfs_nol_timeout)
|
|||
static void dfs_nol_elem_free_work_cb(void *context)
|
||||
{
|
||||
struct wlan_dfs *dfs = (struct wlan_dfs *)context;
|
||||
struct dfs_nolelem *tmp_nol_entry, *nol_entry;
|
||||
struct dfs_nolelem *nol_head;
|
||||
|
||||
WLAN_DFSNOL_LOCK(dfs);
|
||||
if (!TAILQ_EMPTY(&dfs->dfs_nol_free_list))
|
||||
TAILQ_FOREACH_SAFE(nol_entry,
|
||||
&dfs->dfs_nol_free_list,
|
||||
nolelem_list,
|
||||
tmp_nol_entry) {
|
||||
TAILQ_REMOVE(&dfs->dfs_nol_free_list,
|
||||
nol_entry, nolelem_list);
|
||||
while (true) {
|
||||
WLAN_DFSNOL_LOCK(dfs);
|
||||
|
||||
nol_head = TAILQ_FIRST(&dfs->dfs_nol_free_list);
|
||||
if (nol_head) {
|
||||
TAILQ_REMOVE(&dfs->dfs_nol_free_list, nol_head,
|
||||
nolelem_list);
|
||||
WLAN_DFSNOL_UNLOCK(dfs);
|
||||
qdf_timer_free(&nol_entry->nol_timer);
|
||||
WLAN_DFSNOL_LOCK(dfs);
|
||||
qdf_mem_free(nol_entry);
|
||||
|
||||
qdf_timer_free(&nol_head->nol_timer);
|
||||
qdf_mem_free(nol_head);
|
||||
} else {
|
||||
WLAN_DFSNOL_UNLOCK(dfs);
|
||||
break;
|
||||
}
|
||||
WLAN_DFSNOL_UNLOCK(dfs);
|
||||
}
|
||||
}
|
||||
|
||||
void dfs_nol_timer_init(struct wlan_dfs *dfs)
|
||||
|
|
@ -547,23 +549,22 @@ void dfs_nol_timer_cleanup(struct wlan_dfs *dfs)
|
|||
{
|
||||
struct dfs_nolelem *nol;
|
||||
|
||||
WLAN_DFSNOL_LOCK(dfs);
|
||||
nol = dfs->dfs_nol;
|
||||
while (nol) {
|
||||
dfs->dfs_nol = nol->nol_next;
|
||||
dfs->dfs_nol_count--;
|
||||
/*
|
||||
* Unlock is required so that when we sync with the
|
||||
* nol_timeout timer we do not run into deadlock.
|
||||
*/
|
||||
WLAN_DFSNOL_UNLOCK(dfs);
|
||||
qdf_timer_free(&nol->nol_timer);
|
||||
while (true) {
|
||||
WLAN_DFSNOL_LOCK(dfs);
|
||||
|
||||
qdf_mem_free(nol);
|
||||
nol = dfs->dfs_nol;
|
||||
if (nol) {
|
||||
dfs->dfs_nol = nol->nol_next;
|
||||
dfs->dfs_nol_count--;
|
||||
WLAN_DFSNOL_UNLOCK(dfs);
|
||||
|
||||
qdf_timer_free(&nol->nol_timer);
|
||||
qdf_mem_free(nol);
|
||||
} else {
|
||||
WLAN_DFSNOL_UNLOCK(dfs);
|
||||
break;
|
||||
}
|
||||
}
|
||||
WLAN_DFSNOL_UNLOCK(dfs);
|
||||
}
|
||||
|
||||
void dfs_nol_workqueue_cleanup(struct wlan_dfs *dfs)
|
||||
|
|
|
|||
Loading…
Reference in a new issue