|
@@ -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
|