[SCSI] libfcoe: Remove stale fcoe-netdev entries
[pandora-kernel.git] / drivers / scsi / fcoe / fcoe_transport.c
index 745eb9a..2586841 100644 (file)
@@ -39,10 +39,13 @@ static struct fcoe_transport *fcoe_transport_lookup(struct net_device *device);
 static struct fcoe_transport *fcoe_netdev_map_lookup(struct net_device *device);
 static int fcoe_transport_enable(const char *, struct kernel_param *);
 static int fcoe_transport_disable(const char *, struct kernel_param *);
+static int libfcoe_device_notification(struct notifier_block *notifier,
+                                   ulong event, void *ptr);
 
 static LIST_HEAD(fcoe_transports);
-static LIST_HEAD(fcoe_netdevs);
 static DEFINE_MUTEX(ft_mutex);
+static LIST_HEAD(fcoe_netdevs);
+static DEFINE_MUTEX(fn_mutex);
 
 unsigned int libfcoe_debug_logging;
 module_param_named(debug_logging, libfcoe_debug_logging, int, S_IRUGO|S_IWUSR);
@@ -75,6 +78,11 @@ module_param_call(disable, fcoe_transport_disable, NULL, NULL, S_IWUSR);
 __MODULE_PARM_TYPE(disable, "string");
 MODULE_PARM_DESC(disable, " Disables fcoe on a ethernet interface.");
 
+/* notification function for packets from net device */
+static struct notifier_block libfcoe_notifier = {
+       .notifier_call = libfcoe_device_notification,
+};
+
 /**
  * fcoe_fc_crc() - Calculates the CRC for a given frame
  * @fp: The frame to be checksumed
@@ -375,6 +383,7 @@ static int fcoe_transport_show(char *buffer, const struct kernel_param *kp)
 
 static int __init fcoe_transport_init(void)
 {
+       register_netdevice_notifier(&libfcoe_notifier);
        return 0;
 }
 
@@ -382,6 +391,7 @@ static int __exit fcoe_transport_exit(void)
 {
        struct fcoe_transport *ft;
 
+       unregister_netdevice_notifier(&libfcoe_notifier);
        mutex_lock(&ft_mutex);
        list_for_each_entry(ft, &fcoe_transports, list)
                printk(KERN_ERR "FCoE transport %s is still attached!\n",
@@ -405,7 +415,9 @@ static int fcoe_add_netdev_mapping(struct net_device *netdev,
        nm->netdev = netdev;
        nm->ft = ft;
 
+       mutex_lock(&fn_mutex);
        list_add(&nm->list, &fcoe_netdevs);
+       mutex_unlock(&fn_mutex);
        return 0;
 }
 
@@ -414,13 +426,16 @@ static void fcoe_del_netdev_mapping(struct net_device *netdev)
 {
        struct fcoe_netdev_mapping *nm = NULL, *tmp;
 
+       mutex_lock(&fn_mutex);
        list_for_each_entry_safe(nm, tmp, &fcoe_netdevs, list) {
                if (nm->netdev == netdev) {
                        list_del(&nm->list);
                        kfree(nm);
+                       mutex_unlock(&fn_mutex);
                        return;
                }
        }
+       mutex_unlock(&fn_mutex);
 }
 
 
@@ -438,13 +453,16 @@ static struct fcoe_transport *fcoe_netdev_map_lookup(struct net_device *netdev)
        struct fcoe_transport *ft = NULL;
        struct fcoe_netdev_mapping *nm;
 
+       mutex_lock(&fn_mutex);
        list_for_each_entry(nm, &fcoe_netdevs, list) {
                if (netdev == nm->netdev) {
                        ft = nm->ft;
+                       mutex_unlock(&fn_mutex);
                        return ft;
                }
        }
 
+       mutex_unlock(&fn_mutex);
        return NULL;
 }
 
@@ -469,6 +487,32 @@ static struct net_device *fcoe_if_to_netdev(const char *buffer)
        return NULL;
 }
 
+/**
+ * libfcoe_device_notification() - Handler for net device events
+ * @notifier: The context of the notification
+ * @event:    The type of event
+ * @ptr:      The net device that the event was on
+ *
+ * This function is called by the Ethernet driver in case of link change event.
+ *
+ * Returns: 0 for success
+ */
+static int libfcoe_device_notification(struct notifier_block *notifier,
+                                   ulong event, void *ptr)
+{
+       struct net_device *netdev = ptr;
+
+       switch (event) {
+       case NETDEV_UNREGISTER:
+               printk(KERN_ERR "libfcoe_device_notification: NETDEV_UNREGISTER %s\n",
+                               netdev->name);
+               fcoe_del_netdev_mapping(netdev);
+               break;
+       }
+       return NOTIFY_OK;
+}
+
+
 /**
  * fcoe_transport_create() - Create a fcoe interface
  * @buffer: The name of the Ethernet interface to create on