Browse Source

qcacld-3.0: Fix CPU soft lock up during workqueue cancellation

Propagation from qcacld-2.0 to qcacld-3.0

ipv4 and ipv6 workqueues are initialized in open adapter for STA
and P2P modes but not for AP mode. The workqueues are cancelled
in stop adapter. The cancel_work_sync may be called on AP adapter
workqueue also, if just in time, the AP adapter mode has changed
to STA mode, for example during hostapd stop etc. This can cause
the cancel_work_sync to continuously loop since INIT_WORK has not
been called, finally raising CPU stuck. There is no harm in calling
INIT_WORK on any workqueue since it only makes sure that in cases
as above there is no undeterministic behaviour.

Fix cancel_work_sync issues by initializing ipv4 and ipv6 workqueues.

CRs-Fixed: 2121723
Change-Id: Ief8dd0c797dd1492fa30ca4e41da9e583548e21d
Hanumanth Reddy Pothula 7 years ago
parent
commit
aaa3f8871c
1 changed files with 26 additions and 0 deletions
  1. 26 0
      core/hdd/src/wlan_hdd_main.c

+ 26 - 0
core/hdd/src/wlan_hdd_main.c

@@ -4074,6 +4074,22 @@ struct hdd_adapter *hdd_open_adapter(struct hdd_context *hdd_ctx, uint8_t sessio
 		wlan_hdd_netif_queue_control(adapter,
 					WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER,
 					WLAN_CONTROL_PATH);
+
+		/*
+		 * Workqueue which gets scheduled in IPv4 notification
+		 * callback
+		 */
+		INIT_WORK(&adapter->ipv4NotifierWorkQueue,
+			  hdd_ipv4_notifier_work_queue);
+
+#ifdef WLAN_NS_OFFLOAD
+		/*
+		 * Workqueue which gets scheduled in IPv6
+		 * notification callback.
+		 */
+		INIT_WORK(&adapter->ipv6NotifierWorkQueue,
+			  hdd_ipv6_notifier_work_queue);
+#endif
 		break;
 	case QDF_FTM_MODE:
 		adapter = hdd_alloc_station_adapter(hdd_ctx, macAddr,
@@ -4485,6 +4501,16 @@ QDF_STATUS hdd_stop_adapter(struct hdd_context *hdd_ctx, struct hdd_adapter *ada
 		if (true == bCloseSession)
 			hdd_vdev_destroy(adapter);
 		mutex_unlock(&hdd_ctx->sap_lock);
+
+#ifdef WLAN_OPEN_SOURCE
+		cancel_work_sync(&adapter->ipv4NotifierWorkQueue);
+#endif
+
+#ifdef WLAN_NS_OFFLOAD
+#ifdef WLAN_OPEN_SOURCE
+		cancel_work_sync(&adapter->ipv6NotifierWorkQueue);
+#endif
+#endif
 		break;
 	case QDF_OCB_MODE:
 		cdp_clear_peer(cds_get_context(QDF_MODULE_ID_SOC),