Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ipw2x00: fix rtnl mutex deadlock

This fix regression introduced by:

commit: ecb4433550f0620f3d1471ae7099037ede30a91e
Author: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Fri Aug 12 14:00:59 2011 +0200

mac80211: fix suspend/resume races with unregister hw

Above commit add rtnl_lock() into wiphy_register(), what cause deadlock
when initializing ipw2x00 driver, which itself call wiphy_register()
from register_netdev() internal callback with rtnl mutex taken.

To fix move wiphy_register() outside register_netdev(). This solution
have side effect of not creating /sys/class/net/wlanX/phy80211 link,
but that's a minor issue we can live with.

Bisected-by: Witold Baryluk <baryluk@smp.if.uj.edu.pl>
Bisected-by: Michael Witten <mfwitten@gmail.com>
Tested-by: Witold Baryluk <baryluk@smp.if.uj.edu.pl>
Tested-by: Michael Witten <mfwitten@gmail.com>
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

authored by

Stanislaw Gruszka and committed by
John W. Linville
7cabafce aa3d7eef

+40 -20
+14 -7
drivers/net/wireless/ipw2x00/ipw2100.c
··· 1903 1903 static int ipw2100_net_init(struct net_device *dev) 1904 1904 { 1905 1905 struct ipw2100_priv *priv = libipw_priv(dev); 1906 + 1907 + return ipw2100_up(priv, 1); 1908 + } 1909 + 1910 + static int ipw2100_wdev_init(struct net_device *dev) 1911 + { 1912 + struct ipw2100_priv *priv = libipw_priv(dev); 1906 1913 const struct libipw_geo *geo = libipw_get_geo(priv->ieee); 1907 1914 struct wireless_dev *wdev = &priv->ieee->wdev; 1908 - int ret; 1909 1915 int i; 1910 - 1911 - ret = ipw2100_up(priv, 1); 1912 - if (ret) 1913 - return ret; 1914 1916 1915 1917 memcpy(wdev->wiphy->perm_addr, priv->mac_addr, ETH_ALEN); 1916 1918 ··· 6352 6350 "Error calling register_netdev.\n"); 6353 6351 goto fail; 6354 6352 } 6353 + registered = 1; 6354 + 6355 + err = ipw2100_wdev_init(dev); 6356 + if (err) 6357 + goto fail; 6355 6358 6356 6359 mutex_lock(&priv->action_mutex); 6357 - registered = 1; 6358 6360 6359 6361 IPW_DEBUG_INFO("%s: Bound to %s\n", dev->name, pci_name(pci_dev)); 6360 6362 ··· 6395 6389 6396 6390 fail_unlock: 6397 6391 mutex_unlock(&priv->action_mutex); 6398 - 6392 + wiphy_unregister(priv->ieee->wdev.wiphy); 6393 + kfree(priv->ieee->bg_band.channels); 6399 6394 fail: 6400 6395 if (dev) { 6401 6396 if (registered)
+26 -13
drivers/net/wireless/ipw2x00/ipw2200.c
··· 11425 11425 /* Called by register_netdev() */ 11426 11426 static int ipw_net_init(struct net_device *dev) 11427 11427 { 11428 + int rc = 0; 11429 + struct ipw_priv *priv = libipw_priv(dev); 11430 + 11431 + mutex_lock(&priv->mutex); 11432 + if (ipw_up(priv)) 11433 + rc = -EIO; 11434 + mutex_unlock(&priv->mutex); 11435 + 11436 + return rc; 11437 + } 11438 + 11439 + static int ipw_wdev_init(struct net_device *dev) 11440 + { 11428 11441 int i, rc = 0; 11429 11442 struct ipw_priv *priv = libipw_priv(dev); 11430 11443 const struct libipw_geo *geo = libipw_get_geo(priv->ieee); 11431 11444 struct wireless_dev *wdev = &priv->ieee->wdev; 11432 - mutex_lock(&priv->mutex); 11433 - 11434 - if (ipw_up(priv)) { 11435 - rc = -EIO; 11436 - goto out; 11437 - } 11438 11445 11439 11446 memcpy(wdev->wiphy->perm_addr, priv->mac_addr, ETH_ALEN); 11440 11447 ··· 11526 11519 set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev); 11527 11520 11528 11521 /* With that information in place, we can now register the wiphy... */ 11529 - if (wiphy_register(wdev->wiphy)) { 11522 + if (wiphy_register(wdev->wiphy)) 11530 11523 rc = -EIO; 11531 - goto out; 11532 - } 11533 - 11534 11524 out: 11535 - mutex_unlock(&priv->mutex); 11536 11525 return rc; 11537 11526 } 11538 11527 ··· 11835 11832 goto out_remove_sysfs; 11836 11833 } 11837 11834 11835 + err = ipw_wdev_init(net_dev); 11836 + if (err) { 11837 + IPW_ERROR("failed to register wireless device\n"); 11838 + goto out_unregister_netdev; 11839 + } 11840 + 11838 11841 #ifdef CONFIG_IPW2200_PROMISCUOUS 11839 11842 if (rtap_iface) { 11840 11843 err = ipw_prom_alloc(priv); 11841 11844 if (err) { 11842 11845 IPW_ERROR("Failed to register promiscuous network " 11843 11846 "device (error %d).\n", err); 11844 - unregister_netdev(priv->net_dev); 11845 - goto out_remove_sysfs; 11847 + wiphy_unregister(priv->ieee->wdev.wiphy); 11848 + kfree(priv->ieee->a_band.channels); 11849 + kfree(priv->ieee->bg_band.channels); 11850 + goto out_unregister_netdev; 11846 11851 } 11847 11852 } 11848 11853 #endif ··· 11862 11851 11863 11852 return 0; 11864 11853 11854 + out_unregister_netdev: 11855 + unregister_netdev(priv->net_dev); 11865 11856 out_remove_sysfs: 11866 11857 sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group); 11867 11858 out_release_irq: