Commit 7dde596e authored by Ben Hutchings's avatar Ben Hutchings Committed by David S. Miller

sfc: Fix synchronisation of efx_mtd_{probe,rename,remove}

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: default avatarBen Hutchings <bhutchings@solarflare.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0c53d8c8
...@@ -1517,18 +1517,21 @@ static const struct net_device_ops efx_netdev_ops = { ...@@ -1517,18 +1517,21 @@ static const struct net_device_ops efx_netdev_ops = {
#endif #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, static int efx_netdev_event(struct notifier_block *this,
unsigned long event, void *ptr) unsigned long event, void *ptr)
{ {
struct net_device *net_dev = ptr; struct net_device *net_dev = ptr;
if (net_dev->netdev_ops == &efx_netdev_ops && event == NETDEV_CHANGENAME) { if (net_dev->netdev_ops == &efx_netdev_ops &&
struct efx_nic *efx = netdev_priv(net_dev); event == NETDEV_CHANGENAME)
efx_update_name(netdev_priv(net_dev));
strcpy(efx->name, net_dev->name);
efx_mtd_rename(efx);
efx_set_channel_names(efx);
}
return NOTIFY_DONE; return NOTIFY_DONE;
} }
...@@ -1568,8 +1571,10 @@ static int efx_register_netdev(struct efx_nic *efx) ...@@ -1568,8 +1571,10 @@ static int efx_register_netdev(struct efx_nic *efx)
EFX_ERR(efx, "could not register net dev\n"); EFX_ERR(efx, "could not register net dev\n");
return rc; 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); rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_type);
if (rc) { if (rc) {
...@@ -1978,8 +1983,6 @@ static void efx_pci_remove(struct pci_dev *pci_dev) ...@@ -1978,8 +1983,6 @@ static void efx_pci_remove(struct pci_dev *pci_dev)
if (!efx) if (!efx)
return; return;
efx_mtd_remove(efx);
/* Mark the NIC as fini, then stop the interface */ /* Mark the NIC as fini, then stop the interface */
rtnl_lock(); rtnl_lock();
efx->state = STATE_FINI; efx->state = STATE_FINI;
...@@ -1993,6 +1996,8 @@ static void efx_pci_remove(struct pci_dev *pci_dev) ...@@ -1993,6 +1996,8 @@ static void efx_pci_remove(struct pci_dev *pci_dev)
efx_unregister_netdev(efx); efx_unregister_netdev(efx);
efx_mtd_remove(efx);
/* Wait for any scheduled resets to complete. No more will be /* Wait for any scheduled resets to complete. No more will be
* scheduled from this point because efx_stop_all() has been * scheduled from this point because efx_stop_all() has been
* called, we are no longer registered with driverlink, and * called, we are no longer registered with driverlink, and
...@@ -2146,17 +2151,15 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev, ...@@ -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 /* Switch to the running state before we expose the device to
* the OS. This is to ensure that the initial gathering of * the OS. This is to ensure that the initial gathering of
* MAC stats succeeds. */ * MAC stats succeeds. */
rtnl_lock();
efx->state = STATE_RUNNING; efx->state = STATE_RUNNING;
rtnl_unlock();
efx_mtd_probe(efx); /* allowed to fail */
rc = efx_register_netdev(efx); rc = efx_register_netdev(efx);
if (rc) if (rc)
goto fail5; goto fail5;
EFX_LOG(efx, "initialisation successful\n"); EFX_LOG(efx, "initialisation successful\n");
efx_mtd_probe(efx); /* allowed to fail */
return 0; return 0;
fail5: fail5:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment