From b9c945f7a049d2f1aee68d613904bffccce8b5d0 Mon Sep 17 00:00:00 2001 From: Bibhay Ranjan Date: Fri, 24 Oct 2014 14:08:01 -0700 Subject: [PATCH] bcmdhd:fix kernel panic due to early free of ndev because of http://git-master/r/555458, net_device structure was moved to some other context, which eventually was doing free_netdev and an early release of memory which resulted in kernel panic. moving free_netdev back to it original context. However, free_netdev has to be synchronized with thread wl_event_handler as per Bug 200040067. So, this syncronization has to be done by semaphore netif_sem using a writers lock. This ensures Bug 200040067 also remains fixed Bug 200040067 Bug 200048503 Change-Id: Ie2c664dc747cac4fba49c5edfe7a818d1bcae7ca Signed-off-by: Bibhay Ranjan Reviewed-on: http://git-master/r/562973 Reviewed-by: Dhiren Parmar --- drivers/net/wireless/bcmdhd/dhd_linux.c | 20 +++++++++++++------- drivers/net/wireless/bcmdhd/wl_cfg80211.c | 14 -------------- 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 3e2ef9b1d93..a52c037a6ca 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -1484,14 +1484,20 @@ dhd_op_if(dhd_if_t *ifp) if (ret < 0) { ifp->set_multicast = FALSE; - /* for DHD_DEL_IF we are handling it separately in wl_dealloc_netinfo*/ - if (ret != DHD_DEL_IF) { - if (ifp->net) { - free_netdev(ifp->net); - ifp->net = NULL; - } - } dhd->iflist[ifp->idx] = NULL; + +#ifdef WL_CFG80211 + extern struct wl_priv *wlcfg_drv_priv; + struct wl_priv *wl = wlcfg_drv_priv; + down_write(&wl->netif_sem); +#endif + if (ifp->net) { + free_netdev(ifp->net); + ifp->net = NULL; + } +#ifdef WL_CFG80211 + up_write(&wl->netif_sem); +#endif #ifdef SOFTAP flags = dhd_os_spin_lock(&dhd->pub); if (ifp->net == ap_net_dev) diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index 9879bd99c98..bf05aca7f25 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -9403,20 +9403,6 @@ static void wl_dealloc_netinfo(struct work_struct *work) WARN_ON(work_pending(&_net_info->wdev->cleanup_work)); kfree(_net_info->wdev); } - if (_net_info->ndev) { - /* free_netdev cannot be called unless the net_device - reg_state is marked as NETREG_UNREGISTERED. - So wait for it to become NETREG_UNREGISTERED. */ - int retry = 0; - while (_net_info->ndev->reg_state != NETREG_UNREGISTERED && retry != 10) { - msleep(100); - retry++; - } - - /* if retry has reached 10 then free_netdev will raise a BUG_ON */ - free_netdev(_net_info->ndev); - _net_info->ndev = NULL; - } kfree(_net_info); } up_write(&wl->netif_sem); -- 2.39.2