forked from Minki/linux
mwifiex: fix corner case system hang issue
Sometimes pending internal scan commands are delayed to give preference to Tx traffic. 'scan_processing' flag has been checked at the beginning of delay timer routine to know if in the meantime scan operation has been cancelled. There is a corner case where pending scan commands are emptied after scan_processing flag check is passed. In this case wrong pointer returned by list_first_entry() is passed to list_del() which causes system hang. This patch fixes the issue by adding list_empty() check. Signed-off-by: Amitkumar Karwar <akarwar@marvell.com> Signed-off-by: Bing Zhao <bzhao@marvell.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
2d702830e0
commit
d5343f0690
@ -33,6 +33,7 @@ static void scan_delay_timer_fn(unsigned long data)
|
|||||||
struct mwifiex_private *priv = (struct mwifiex_private *)data;
|
struct mwifiex_private *priv = (struct mwifiex_private *)data;
|
||||||
struct mwifiex_adapter *adapter = priv->adapter;
|
struct mwifiex_adapter *adapter = priv->adapter;
|
||||||
struct cmd_ctrl_node *cmd_node, *tmp_node;
|
struct cmd_ctrl_node *cmd_node, *tmp_node;
|
||||||
|
spinlock_t *scan_q_lock = &adapter->scan_pending_q_lock;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
if (adapter->surprise_removed)
|
if (adapter->surprise_removed)
|
||||||
@ -44,13 +45,13 @@ static void scan_delay_timer_fn(unsigned long data)
|
|||||||
* Abort scan operation by cancelling all pending scan
|
* Abort scan operation by cancelling all pending scan
|
||||||
* commands
|
* commands
|
||||||
*/
|
*/
|
||||||
spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
|
spin_lock_irqsave(scan_q_lock, flags);
|
||||||
list_for_each_entry_safe(cmd_node, tmp_node,
|
list_for_each_entry_safe(cmd_node, tmp_node,
|
||||||
&adapter->scan_pending_q, list) {
|
&adapter->scan_pending_q, list) {
|
||||||
list_del(&cmd_node->list);
|
list_del(&cmd_node->list);
|
||||||
mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
|
mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
|
spin_unlock_irqrestore(scan_q_lock, flags);
|
||||||
|
|
||||||
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
|
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
|
||||||
adapter->scan_processing = false;
|
adapter->scan_processing = false;
|
||||||
@ -79,12 +80,17 @@ static void scan_delay_timer_fn(unsigned long data)
|
|||||||
*/
|
*/
|
||||||
adapter->scan_delay_cnt = 0;
|
adapter->scan_delay_cnt = 0;
|
||||||
adapter->empty_tx_q_cnt = 0;
|
adapter->empty_tx_q_cnt = 0;
|
||||||
spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
|
spin_lock_irqsave(scan_q_lock, flags);
|
||||||
|
|
||||||
|
if (list_empty(&adapter->scan_pending_q)) {
|
||||||
|
spin_unlock_irqrestore(scan_q_lock, flags);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
cmd_node = list_first_entry(&adapter->scan_pending_q,
|
cmd_node = list_first_entry(&adapter->scan_pending_q,
|
||||||
struct cmd_ctrl_node, list);
|
struct cmd_ctrl_node, list);
|
||||||
list_del(&cmd_node->list);
|
list_del(&cmd_node->list);
|
||||||
spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
|
spin_unlock_irqrestore(scan_q_lock, flags);
|
||||||
flags);
|
|
||||||
|
|
||||||
mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
|
mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
|
||||||
true);
|
true);
|
||||||
|
Loading…
Reference in New Issue
Block a user