From d5343f06902bf6635734d1e72aa2100dd63a6f4b Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Fri, 11 Jul 2014 20:53:14 -0700 Subject: [PATCH] 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 Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/main.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 3e5194fb0b0f..dfa37eadc4db 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -33,6 +33,7 @@ static void scan_delay_timer_fn(unsigned long data) struct mwifiex_private *priv = (struct mwifiex_private *)data; struct mwifiex_adapter *adapter = priv->adapter; struct cmd_ctrl_node *cmd_node, *tmp_node; + spinlock_t *scan_q_lock = &adapter->scan_pending_q_lock; unsigned long flags; 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 * 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, &adapter->scan_pending_q, list) { list_del(&cmd_node->list); 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); adapter->scan_processing = false; @@ -79,12 +80,17 @@ static void scan_delay_timer_fn(unsigned long data) */ adapter->scan_delay_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, struct cmd_ctrl_node, list); list_del(&cmd_node->list); - spin_unlock_irqrestore(&adapter->scan_pending_q_lock, - flags); + spin_unlock_irqrestore(scan_q_lock, flags); mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); -- 2.34.1