Commit d5343f06 authored by Amitkumar Karwar's avatar Amitkumar Karwar Committed by John W. Linville

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: default avatarAmitkumar Karwar <akarwar@marvell.com>
Signed-off-by: default avatarBing Zhao <bzhao@marvell.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 2d702830
...@@ -33,6 +33,7 @@ static void scan_delay_timer_fn(unsigned long data) ...@@ -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) ...@@ -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) ...@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment