qcacmn: Fix DFS nol memory leak
Problem:- If the driver is unloaded before a nol timer fires, the unload function frees the NOl element. But the memory associated with the nol timer argument which has a one-to-one mapping with nol still remains in the system since the nol timer argument memory is freed in the timer function. Solution:- 1)Instead of allocating a separate structure as input to the timer function use the NOL element itself as input since NOL element already has the information needed by the timer function. 2)A NOL element for which the timer is yet to fire is freed by the driver unload (dfs_nol_timer_cleanup). 3)When dfs_nol_timer_cleanup is about to free a NOL element the corresponding timer may be already running. Therefore, it is required to sync/wait for the timer to finish before the NOL element can be freed. If we do not wait and free the NOL element the timer may access an invalid memory location. Change-Id: I4f37b66777491d92a51ff1ffc2651af1ccf5de29 CRs-Fixed: 2045993
Цей коміт міститься в:
@@ -475,6 +475,7 @@ struct dfs_state {
|
||||
|
||||
/**
|
||||
* struct dfs_nolelem - DFS NOL element.
|
||||
* @nol_dfs Back pointer to dfs object.
|
||||
* @nol_freq: Centre frequency.
|
||||
* @nol_chwidth: Event width (MHz).
|
||||
* @nol_start_ticks: NOL start time in OS ticks.
|
||||
@@ -483,6 +484,7 @@ struct dfs_state {
|
||||
* @nol_next: Next element pointer.
|
||||
*/
|
||||
struct dfs_nolelem {
|
||||
struct wlan_dfs *nol_dfs;
|
||||
uint32_t nol_freq;
|
||||
uint32_t nol_chwidth;
|
||||
unsigned long nol_start_ticks;
|
||||
@@ -491,17 +493,6 @@ struct dfs_nolelem {
|
||||
struct dfs_nolelem *nol_next;
|
||||
} qdf_packed;
|
||||
|
||||
/**
|
||||
* struct dfs_nol_timer_arg - DFS NOL timer arguments.
|
||||
* @dfs: Object of wlan_dfs structure.
|
||||
* @delfreq: Freq to delete.
|
||||
* @delchwidth: Channel width to delete.
|
||||
*/
|
||||
struct dfs_nol_timer_arg {
|
||||
struct wlan_dfs *dfs;
|
||||
uint16_t delfreq;
|
||||
uint16_t delchwidth;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dfs_info - DFS Info.
|
||||
|
@@ -101,17 +101,17 @@ static void dfs_nol_delete(struct wlan_dfs *dfs,
|
||||
*/
|
||||
static os_timer_func(dfs_remove_from_nol)
|
||||
{
|
||||
struct dfs_nol_timer_arg *nol_arg;
|
||||
struct dfs_nolelem *nol_arg;
|
||||
struct wlan_dfs *dfs;
|
||||
uint16_t delfreq;
|
||||
uint16_t delchwidth;
|
||||
uint8_t chan;
|
||||
|
||||
OS_GET_TIMER_ARG(nol_arg, struct dfs_nol_timer_arg *);
|
||||
OS_GET_TIMER_ARG(nol_arg, struct dfs_nolelem *);
|
||||
|
||||
dfs = nol_arg->dfs;
|
||||
delfreq = nol_arg->delfreq;
|
||||
delchwidth = nol_arg->delchwidth;
|
||||
dfs = nol_arg->nol_dfs;
|
||||
delfreq = nol_arg->nol_freq;
|
||||
delchwidth = nol_arg->nol_chwidth;
|
||||
|
||||
/* Delete the given NOL entry. */
|
||||
dfs_nol_delete(dfs, delfreq, delchwidth);
|
||||
@@ -126,7 +126,6 @@ static os_timer_func(dfs_remove_from_nol)
|
||||
utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
|
||||
(uint8_t *)&chan, 1, DFS_NOL_RESET);
|
||||
dfs_save_nol(dfs->dfs_pdev_obj);
|
||||
qdf_mem_free(nol_arg);
|
||||
}
|
||||
|
||||
void dfs_print_nol(struct wlan_dfs *dfs)
|
||||
@@ -256,7 +255,6 @@ void dfs_nol_addchan(struct wlan_dfs *dfs,
|
||||
#define TIME_IN_MS 1000
|
||||
#define TIME_IN_US (TIME_IN_MS * 1000)
|
||||
struct dfs_nolelem *nol, *elem, *prev;
|
||||
struct dfs_nol_timer_arg *dfs_nol_arg;
|
||||
/* For now, assume all events are 20MHz wide. */
|
||||
int ch_width = 20;
|
||||
|
||||
@@ -292,12 +290,7 @@ void dfs_nol_addchan(struct wlan_dfs *dfs,
|
||||
if (elem == NULL)
|
||||
goto bad;
|
||||
|
||||
dfs_nol_arg = (struct dfs_nol_timer_arg *)qdf_mem_malloc(
|
||||
sizeof(struct dfs_nol_timer_arg));
|
||||
if (dfs_nol_arg == NULL) {
|
||||
qdf_mem_free(elem);
|
||||
goto bad;
|
||||
}
|
||||
elem->nol_dfs = dfs;
|
||||
elem->nol_freq = freq;
|
||||
elem->nol_chwidth = ch_width;
|
||||
elem->nol_start_ticks = qdf_system_ticks();
|
||||
@@ -309,13 +302,10 @@ void dfs_nol_addchan(struct wlan_dfs *dfs,
|
||||
/* This is the first element in the NOL. */
|
||||
dfs->dfs_nol = elem;
|
||||
}
|
||||
dfs_nol_arg->dfs = dfs;
|
||||
dfs_nol_arg->delfreq = elem->nol_freq;
|
||||
dfs_nol_arg->delchwidth = elem->nol_chwidth;
|
||||
|
||||
qdf_timer_init(NULL,
|
||||
&elem->nol_timer, dfs_remove_from_nol,
|
||||
dfs_nol_arg, QDF_TIMER_TYPE_WAKE_APPS);
|
||||
elem, QDF_TIMER_TYPE_WAKE_APPS);
|
||||
OS_SET_TIMER(&elem->nol_timer, dfs_nol_timeout * TIME_IN_MS);
|
||||
|
||||
/* Update the NOL counter. */
|
||||
@@ -414,7 +404,7 @@ void dfs_nol_timer_cleanup(struct wlan_dfs *dfs)
|
||||
struct dfs_nolelem *nol = dfs->dfs_nol, *prev;
|
||||
|
||||
while (nol) {
|
||||
qdf_timer_stop(&nol->nol_timer);
|
||||
qdf_timer_sync_cancel(&nol->nol_timer);
|
||||
nol = nol->nol_next;
|
||||
}
|
||||
|
||||
|
Посилання в новій задачі
Заблокувати користувача