From 08479ba85be5b15a7b697d7a5172730510ff503a Mon Sep 17 00:00:00 2001 From: Arun Khandavalli Date: Mon, 7 Aug 2017 19:56:23 +0530 Subject: [PATCH] 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 --- Kbuild | 3 ++- core/hdd/src/wlan_hdd_main.c | 23 ++++++++--------------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/Kbuild b/Kbuild index c291ec52fb88..d4b15fb5a50c 100644 --- a/Kbuild +++ b/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 ############## diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 5bd62d8ee299..081d0cfbd463 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/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: