diff options
author | Amitkumar Karwar <akarwar@marvell.com> | 2013-03-15 21:47:05 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-03-18 15:20:36 -0400 |
commit | 00d7ea11ff0783e24fe70778f3141270b561aaa1 (patch) | |
tree | 7b1275391f76d2202dc884c9a2b53e0715127c3b /drivers/net/wireless/mwifiex/scan.c | |
parent | 01d4ab96d2e7fceaad204e5a8710ce34e229b8c5 (diff) |
mwifiex: fix race when queuing commands
Running the following script repeatedly on XO-4 with SD8787
produces command timeout and system lockup.
insmod mwifiex_sdio.ko
sleep 1
ifconfig eth0 up
iwlist eth0 scan &
sleep 0.5
rmmod mwifiex_sdio
mwifiex_send_cmd_async() is called for sync as well as async
commands. (mwifiex_send_cmd_sync() internally calls it for
sync command.)
"adapter->cmd_queued" gets filled inside mwifiex_send_cmd_async()
routine for both types of commands. But it is used only for sync
commands in mwifiex_wait_queue_complete(). This could lead to a
race when two threads try to queue a sync command with another
sync/async command simultaneously.
Get rid of global variable and pass command node as a parameter
to mwifiex_wait_queue_complete() to fix the problem.
Cc: <stable@vger.kernel.org> # 3.8
Reported-by: Daniel Drake <dsd@laptop.org>
Tested-by: Daniel Drake <dsd@laptop.org>
Tested-by: Marco Cesarano <marco@marvell.com>
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>
Diffstat (limited to 'drivers/net/wireless/mwifiex/scan.c')
-rw-r--r-- | drivers/net/wireless/mwifiex/scan.c | 8 |
1 files changed, 4 insertions, 4 deletions
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index bb60c2754a97..d215b4d3c51b 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c | |||
@@ -1388,10 +1388,13 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, | |||
1388 | list_del(&cmd_node->list); | 1388 | list_del(&cmd_node->list); |
1389 | spin_unlock_irqrestore(&adapter->scan_pending_q_lock, | 1389 | spin_unlock_irqrestore(&adapter->scan_pending_q_lock, |
1390 | flags); | 1390 | flags); |
1391 | adapter->cmd_queued = cmd_node; | ||
1392 | mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, | 1391 | mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, |
1393 | true); | 1392 | true); |
1394 | queue_work(adapter->workqueue, &adapter->main_work); | 1393 | queue_work(adapter->workqueue, &adapter->main_work); |
1394 | |||
1395 | /* Perform internal scan synchronously */ | ||
1396 | if (!priv->scan_request) | ||
1397 | mwifiex_wait_queue_complete(adapter, cmd_node); | ||
1395 | } else { | 1398 | } else { |
1396 | spin_unlock_irqrestore(&adapter->scan_pending_q_lock, | 1399 | spin_unlock_irqrestore(&adapter->scan_pending_q_lock, |
1397 | flags); | 1400 | flags); |
@@ -1946,9 +1949,6 @@ int mwifiex_request_scan(struct mwifiex_private *priv, | |||
1946 | /* Normal scan */ | 1949 | /* Normal scan */ |
1947 | ret = mwifiex_scan_networks(priv, NULL); | 1950 | ret = mwifiex_scan_networks(priv, NULL); |
1948 | 1951 | ||
1949 | if (!ret) | ||
1950 | ret = mwifiex_wait_queue_complete(priv->adapter); | ||
1951 | |||
1952 | up(&priv->async_sem); | 1952 | up(&priv->async_sem); |
1953 | 1953 | ||
1954 | return ret; | 1954 | return ret; |