sfc: Fix synchronisation of efx_mtd_{probe,rename,remove}
authorBen Hutchings <bhutchings@solarflare.com>
Sat, 13 Dec 2008 06:09:38 +0000 (22:09 -0800)
committerDavid S. Miller <davem@davemloft.net>
Sat, 13 Dec 2008 06:09:38 +0000 (22:09 -0800)
Currently efx_mtd_rename() can race with the probe() and remove()
functions.

Move probe() before device registration and remove() after
unregistration.  Move initialisation/update of all names based on the
netdev name into a new function and call it under the RTNL immediately
after registration.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/sfc/efx.c

index 8f832bf1e4d229711afe0944fe075d774472bf3a..086629c0fe57bcf9a0ea97f8630eb83eeea4babb 100644 (file)
@@ -1517,18 +1517,21 @@ static const struct net_device_ops efx_netdev_ops = {
 #endif
 };
 
+static void efx_update_name(struct efx_nic *efx)
+{
+       strcpy(efx->name, efx->net_dev->name);
+       efx_mtd_rename(efx);
+       efx_set_channel_names(efx);
+}
+
 static int efx_netdev_event(struct notifier_block *this,
                            unsigned long event, void *ptr)
 {
        struct net_device *net_dev = ptr;
 
-       if (net_dev->netdev_ops == &efx_netdev_ops && event == NETDEV_CHANGENAME) {
-               struct efx_nic *efx = netdev_priv(net_dev);
-
-               strcpy(efx->name, net_dev->name);
-               efx_mtd_rename(efx);
-               efx_set_channel_names(efx);
-       }
+       if (net_dev->netdev_ops == &efx_netdev_ops &&
+           event == NETDEV_CHANGENAME)
+               efx_update_name(netdev_priv(net_dev));
 
        return NOTIFY_DONE;
 }
@@ -1568,8 +1571,10 @@ static int efx_register_netdev(struct efx_nic *efx)
                EFX_ERR(efx, "could not register net dev\n");
                return rc;
        }
-       strcpy(efx->name, net_dev->name);
-       efx_set_channel_names(efx);
+
+       rtnl_lock();
+       efx_update_name(efx);
+       rtnl_unlock();
 
        rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_type);
        if (rc) {
@@ -1978,8 +1983,6 @@ static void efx_pci_remove(struct pci_dev *pci_dev)
        if (!efx)
                return;
 
-       efx_mtd_remove(efx);
-
        /* Mark the NIC as fini, then stop the interface */
        rtnl_lock();
        efx->state = STATE_FINI;
@@ -1993,6 +1996,8 @@ static void efx_pci_remove(struct pci_dev *pci_dev)
 
        efx_unregister_netdev(efx);
 
+       efx_mtd_remove(efx);
+
        /* Wait for any scheduled resets to complete. No more will be
         * scheduled from this point because efx_stop_all() has been
         * called, we are no longer registered with driverlink, and
@@ -2146,17 +2151,15 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
        /* Switch to the running state before we expose the device to
         * the OS.  This is to ensure that the initial gathering of
         * MAC stats succeeds. */
-       rtnl_lock();
        efx->state = STATE_RUNNING;
-       rtnl_unlock();
+
+       efx_mtd_probe(efx); /* allowed to fail */
 
        rc = efx_register_netdev(efx);
        if (rc)
                goto fail5;
 
        EFX_LOG(efx, "initialisation successful\n");
-
-       efx_mtd_probe(efx); /* allowed to fail */
        return 0;
 
  fail5: