Currently, the netdev module ref count is not decremented with module_put()
when the module is unloaded while fcoe instances are present. To fix this
removed reference count on netdev module completely and added functionality to
netdev event handling for NETDEV_UNREGISTER events.

This allows fcoe to remove devices cleanly when the netdev module is unloaded
so we no longer need to hold a reference count for the netdev module.

Signed-off-by: John Fastabend <[email protected]>
---

 drivers/scsi/fcoe/fcoe.c |   94 +++++++---------------------------------------
 1 files changed, 14 insertions(+), 80 deletions(-)

diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index 03e1926..85e51e9 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -371,14 +371,16 @@ static int fcoe_if_destroy(struct net_device *netdev)
                fc_exch_mgr_free(lp->emp);
 
        /* Delete secondary MAC addresses */
-       rtnl_lock();
-       memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN);
-       dev_unicast_delete(fc->real_dev, flogi_maddr, ETH_ALEN);
-       if (!is_zero_ether_addr(fc->ctlr.data_src_addr))
-               dev_unicast_delete(fc->real_dev,
-                                  fc->ctlr.data_src_addr, ETH_ALEN);
-       dev_mc_delete(fc->real_dev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0);
-       rtnl_unlock();
+       if (fc->real_dev->reg_state == NETREG_REGISTERED) {
+               rtnl_lock();
+               memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN);
+               dev_unicast_delete(fc->real_dev, flogi_maddr, ETH_ALEN);
+               if (!is_zero_ether_addr(fc->ctlr.data_src_addr))
+                       dev_unicast_delete(fc->real_dev,
+                                          fc->ctlr.data_src_addr, ETH_ALEN);
+               dev_mc_delete(fc->real_dev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0);
+               rtnl_unlock();
+       }
 
        /* Free the per-CPU receive threads */
        fcoe_percpu_clean(lp);
@@ -1414,6 +1416,10 @@ static int fcoe_device_notification(struct 
notifier_block *notifier,
                break;
        case NETDEV_REGISTER:
                break;
+       case NETDEV_UNREGISTER:
+               fcoe_if_destroy(fc->real_dev);
+               goto out;
+               break;
        default:
                FC_DBG("Unknown event %ld from netdev netlink\n", event);
        }
@@ -1450,75 +1456,6 @@ static struct net_device *fcoe_if_to_netdev(const char 
*buffer)
 }
 
 /**
- * fcoe_netdev_to_module_owner() - finds out the driver module of the netdev
- * @netdev: the target netdev
- *
- * Returns: ptr to the struct module, NULL for failure
- */
-static struct module *
-fcoe_netdev_to_module_owner(const struct net_device *netdev)
-{
-       struct device *dev;
-
-       if (!netdev)
-               return NULL;
-
-       dev = netdev->dev.parent;
-       if (!dev)
-               return NULL;
-
-       if (!dev->driver)
-               return NULL;
-
-       return dev->driver->owner;
-}
-
-/**
- * fcoe_ethdrv_get() - Hold the Ethernet driver
- * @netdev: the target netdev
- *
- * Holds the Ethernet driver module by try_module_get() for
- * the corresponding netdev.
- *
- * Returns: 0 for success
- */
-static int fcoe_ethdrv_get(const struct net_device *netdev)
-{
-       struct module *owner;
-
-       owner = fcoe_netdev_to_module_owner(netdev);
-       if (owner) {
-               printk(KERN_DEBUG "fcoe:hold driver module %s for %s\n",
-                      module_name(owner), netdev->name);
-               return  try_module_get(owner);
-       }
-       return -ENODEV;
-}
-
-/**
- * fcoe_ethdrv_put() - Release the Ethernet driver
- * @netdev: the target netdev
- *
- * Releases the Ethernet driver module by module_put for
- * the corresponding netdev.
- *
- * Returns: 0 for success
- */
-static int fcoe_ethdrv_put(const struct net_device *netdev)
-{
-       struct module *owner;
-
-       owner = fcoe_netdev_to_module_owner(netdev);
-       if (owner) {
-               printk(KERN_DEBUG "fcoe:release driver module %s for %s\n",
-                      module_name(owner), netdev->name);
-               module_put(owner);
-               return 0;
-       }
-       return -ENODEV;
-}
-
-/**
  * fcoe_destroy() - handles the destroy from sysfs
  * @buffer: expected to be an eth if name
  * @kp: associated kernel param
@@ -1547,7 +1484,6 @@ static int fcoe_destroy(const char *buffer, struct 
kernel_param *kp)
                rc = -EIO;
                goto out_putdev;
        }
-       fcoe_ethdrv_put(netdev);
        rc = 0;
 out_putdev:
        dev_put(netdev);
@@ -1577,13 +1513,11 @@ static int fcoe_create(const char *buffer, struct 
kernel_param *kp)
                rc = -EEXIST;
                goto out_putdev;
        }
-       fcoe_ethdrv_get(netdev);
 
        rc = fcoe_if_create(netdev);
        if (rc) {
                printk(KERN_ERR "fcoe: fcoe_if_create(%s) failed\n",
                       netdev->name);
-               fcoe_ethdrv_put(netdev);
                rc = -EIO;
                goto out_putdev;
        }

_______________________________________________
devel mailing list
[email protected]
http://www.open-fcoe.org/mailman/listinfo/devel

Reply via email to