소스 검색

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 년 전
부모
커밋
aaa3f8871c
1개의 변경된 파일26개의 추가작업 그리고 0개의 파일을 삭제
  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),