Browse Source

qcacld-3.0: Register the netdev notifier before the netdevices

Applications in the userspace can sleep on the RTM events from
the driver. One such application waiting of RTM_NEW_LINK indication
does interface up as soon as it recieves the indication, so the
kernel takes rtnl_lock to call the dev_open on the interface.
Load/unload of the driver and dev_open of the interfaces are
synchronized with hdd_init_deinit_lock. So the __hdd_open is waiting
on the hdd_init_deinit_lock which is currently held by the driver
loading context. After registering the interfaces driver goes to
register the netdev notifier which is blocked on the rtnl_lock
currently held by the dev_open resulting in deadlock.

To mitigate the issue register the netdev notifier before the
interfaces are registered.

Change-Id: Ibb0c187a43ad87fa535ff583316af430e1ddf04f
CRs-Fixed: 2078720
Arun Khandavalli 7 years ago
parent
commit
08479ba85b
2 changed files with 10 additions and 16 deletions
  1. 2 1
      Kbuild
  2. 8 15
      core/hdd/src/wlan_hdd_main.c

+ 2 - 1
Kbuild

@@ -1615,7 +1615,8 @@ CDEFINES :=	-DANI_LITTLE_BYTE_ENDIAN \
 		-DCONVERGED_P2P_ENABLE \
 		-DWLAN_POLICY_MGR_ENABLE \
 		-DSUPPORT_11AX \
-		-DCONVERGED_TDLS_ENABLE
+		-DCONVERGED_TDLS_ENABLE \
+		-DCONFIG_HDD_INIT_WITH_RTNL_LOCK
 
 
 ############ WIFI POS ##############

+ 8 - 15
core/hdd/src/wlan_hdd_main.c

@@ -5648,15 +5648,9 @@ static int hdd_register_notifiers(struct hdd_context *hdd_ctx)
 {
 	int ret;
 
-	ret = register_netdevice_notifier(&hdd_netdev_notifier);
-	if (ret) {
-		hdd_err("register_netdevice_notifier failed: %d", ret);
-		goto out;
-	}
-
 	ret = hdd_wlan_register_ip6_notifier(hdd_ctx);
 	if (ret)
-		goto unregister_notifier;
+		goto out;
 
 	hdd_ctx->ipv4_notifier.notifier_call = wlan_hdd_ipv4_changed;
 	ret = register_inetaddr_notifier(&hdd_ctx->ipv4_notifier);
@@ -5669,8 +5663,6 @@ static int hdd_register_notifiers(struct hdd_context *hdd_ctx)
 
 unregister_ip6_notifier:
 	hdd_wlan_unregister_ip6_notifier(hdd_ctx);
-unregister_notifier:
-	unregister_netdevice_notifier(&hdd_netdev_notifier);
 out:
 	return ret;
 
@@ -5689,8 +5681,6 @@ void hdd_unregister_notifiers(struct hdd_context *hdd_ctx)
 	hdd_wlan_unregister_ip6_notifier(hdd_ctx);
 
 	unregister_inetaddr_notifier(&hdd_ctx->ipv4_notifier);
-
-	unregister_netdevice_notifier(&hdd_netdev_notifier);
 }
 
 /**
@@ -6024,6 +6014,8 @@ static void hdd_wlan_exit(struct hdd_context *hdd_ctx)
 		QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status));
 	}
 
+	unregister_netdevice_notifier(&hdd_netdev_notifier);
+
 	hdd_wlan_stop_modules(hdd_ctx, false);
 
 	qdf_spinlock_destroy(&hdd_ctx->hdd_adapter_lock);
@@ -9758,6 +9750,10 @@ int hdd_wlan_startup(struct device *dev)
 
 	hdd_initialize_mac_address(hdd_ctx);
 
+	ret = hdd_register_notifiers(hdd_ctx);
+	if (ret)
+		goto err_ipa_cleanup;
+
 	rtnl_held = hdd_hold_rtnl_lock();
 
 	ret = hdd_open_interfaces(hdd_ctx, rtnl_held);
@@ -9793,10 +9789,6 @@ int hdd_wlan_startup(struct device *dev)
 	if (hdd_ctx->rps)
 		hdd_set_rps_cpu_mask(hdd_ctx);
 
-	ret = hdd_register_notifiers(hdd_ctx);
-	if (ret)
-		goto err_close_adapters;
-
 	status = wlansap_global_init();
 	if (QDF_IS_STATUS_ERROR(status))
 		goto err_close_adapters;
@@ -9873,6 +9865,7 @@ err_release_rtnl_lock:
 	if (rtnl_held)
 		hdd_release_rtnl_lock();
 
+err_ipa_cleanup:
 	hdd_ipa_cleanup(hdd_ctx);
 
 err_wiphy_unregister: