diff options
author | Bhanu Prakash Gollapudi <bprakash@broadcom.com> | 2011-02-25 18:03:17 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2011-02-28 19:33:46 -0500 |
commit | 70be6344ea1ad9110a5b422aeab47a3fbb01ba7f (patch) | |
tree | a0432b0fcd56a708f81d1d680dba264dbddc7f72 /drivers/scsi/fcoe/fcoe_transport.c | |
parent | f4d2b2b6ea8abd0df72a31b4724522a277af6a6c (diff) |
[SCSI] libfcoe: Remove stale fcoe-netdev entries
When L2 driver is unloaded, libfcoe_destroy tries to access the fcoe
transport structure matching the netdev. However, since the netdev is
unregistered by that time, it fails to do so. Hence the stale mappings
exists in the fcoe-netdev list. Handle NETDEV_UREGISTER device
notification mechanism to remove the stale fcoe-netdev mapping.
Signed-off-by: Bhanu Prakash Gollapudi <bprakash@broadcom.com>
Signed-off-by: Robert Love <robert.w.love@intel.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/fcoe/fcoe_transport.c')
-rw-r--r-- | drivers/scsi/fcoe/fcoe_transport.c | 46 |
1 files changed, 45 insertions, 1 deletions
diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c index 745eb9a22d64..258684101bfd 100644 --- a/drivers/scsi/fcoe/fcoe_transport.c +++ b/drivers/scsi/fcoe/fcoe_transport.c | |||
@@ -39,10 +39,13 @@ static struct fcoe_transport *fcoe_transport_lookup(struct net_device *device); | |||
39 | static struct fcoe_transport *fcoe_netdev_map_lookup(struct net_device *device); | 39 | static struct fcoe_transport *fcoe_netdev_map_lookup(struct net_device *device); |
40 | static int fcoe_transport_enable(const char *, struct kernel_param *); | 40 | static int fcoe_transport_enable(const char *, struct kernel_param *); |
41 | static int fcoe_transport_disable(const char *, struct kernel_param *); | 41 | static int fcoe_transport_disable(const char *, struct kernel_param *); |
42 | static int libfcoe_device_notification(struct notifier_block *notifier, | ||
43 | ulong event, void *ptr); | ||
42 | 44 | ||
43 | static LIST_HEAD(fcoe_transports); | 45 | static LIST_HEAD(fcoe_transports); |
44 | static LIST_HEAD(fcoe_netdevs); | ||
45 | static DEFINE_MUTEX(ft_mutex); | 46 | static DEFINE_MUTEX(ft_mutex); |
47 | static LIST_HEAD(fcoe_netdevs); | ||
48 | static DEFINE_MUTEX(fn_mutex); | ||
46 | 49 | ||
47 | unsigned int libfcoe_debug_logging; | 50 | unsigned int libfcoe_debug_logging; |
48 | module_param_named(debug_logging, libfcoe_debug_logging, int, S_IRUGO|S_IWUSR); | 51 | 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); | |||
75 | __MODULE_PARM_TYPE(disable, "string"); | 78 | __MODULE_PARM_TYPE(disable, "string"); |
76 | MODULE_PARM_DESC(disable, " Disables fcoe on a ethernet interface."); | 79 | MODULE_PARM_DESC(disable, " Disables fcoe on a ethernet interface."); |
77 | 80 | ||
81 | /* notification function for packets from net device */ | ||
82 | static struct notifier_block libfcoe_notifier = { | ||
83 | .notifier_call = libfcoe_device_notification, | ||
84 | }; | ||
85 | |||
78 | /** | 86 | /** |
79 | * fcoe_fc_crc() - Calculates the CRC for a given frame | 87 | * fcoe_fc_crc() - Calculates the CRC for a given frame |
80 | * @fp: The frame to be checksumed | 88 | * @fp: The frame to be checksumed |
@@ -375,6 +383,7 @@ static int fcoe_transport_show(char *buffer, const struct kernel_param *kp) | |||
375 | 383 | ||
376 | static int __init fcoe_transport_init(void) | 384 | static int __init fcoe_transport_init(void) |
377 | { | 385 | { |
386 | register_netdevice_notifier(&libfcoe_notifier); | ||
378 | return 0; | 387 | return 0; |
379 | } | 388 | } |
380 | 389 | ||
@@ -382,6 +391,7 @@ static int __exit fcoe_transport_exit(void) | |||
382 | { | 391 | { |
383 | struct fcoe_transport *ft; | 392 | struct fcoe_transport *ft; |
384 | 393 | ||
394 | unregister_netdevice_notifier(&libfcoe_notifier); | ||
385 | mutex_lock(&ft_mutex); | 395 | mutex_lock(&ft_mutex); |
386 | list_for_each_entry(ft, &fcoe_transports, list) | 396 | list_for_each_entry(ft, &fcoe_transports, list) |
387 | printk(KERN_ERR "FCoE transport %s is still attached!\n", | 397 | printk(KERN_ERR "FCoE transport %s is still attached!\n", |
@@ -405,7 +415,9 @@ static int fcoe_add_netdev_mapping(struct net_device *netdev, | |||
405 | nm->netdev = netdev; | 415 | nm->netdev = netdev; |
406 | nm->ft = ft; | 416 | nm->ft = ft; |
407 | 417 | ||
418 | mutex_lock(&fn_mutex); | ||
408 | list_add(&nm->list, &fcoe_netdevs); | 419 | list_add(&nm->list, &fcoe_netdevs); |
420 | mutex_unlock(&fn_mutex); | ||
409 | return 0; | 421 | return 0; |
410 | } | 422 | } |
411 | 423 | ||
@@ -414,13 +426,16 @@ static void fcoe_del_netdev_mapping(struct net_device *netdev) | |||
414 | { | 426 | { |
415 | struct fcoe_netdev_mapping *nm = NULL, *tmp; | 427 | struct fcoe_netdev_mapping *nm = NULL, *tmp; |
416 | 428 | ||
429 | mutex_lock(&fn_mutex); | ||
417 | list_for_each_entry_safe(nm, tmp, &fcoe_netdevs, list) { | 430 | list_for_each_entry_safe(nm, tmp, &fcoe_netdevs, list) { |
418 | if (nm->netdev == netdev) { | 431 | if (nm->netdev == netdev) { |
419 | list_del(&nm->list); | 432 | list_del(&nm->list); |
420 | kfree(nm); | 433 | kfree(nm); |
434 | mutex_unlock(&fn_mutex); | ||
421 | return; | 435 | return; |
422 | } | 436 | } |
423 | } | 437 | } |
438 | mutex_unlock(&fn_mutex); | ||
424 | } | 439 | } |
425 | 440 | ||
426 | 441 | ||
@@ -438,13 +453,16 @@ static struct fcoe_transport *fcoe_netdev_map_lookup(struct net_device *netdev) | |||
438 | struct fcoe_transport *ft = NULL; | 453 | struct fcoe_transport *ft = NULL; |
439 | struct fcoe_netdev_mapping *nm; | 454 | struct fcoe_netdev_mapping *nm; |
440 | 455 | ||
456 | mutex_lock(&fn_mutex); | ||
441 | list_for_each_entry(nm, &fcoe_netdevs, list) { | 457 | list_for_each_entry(nm, &fcoe_netdevs, list) { |
442 | if (netdev == nm->netdev) { | 458 | if (netdev == nm->netdev) { |
443 | ft = nm->ft; | 459 | ft = nm->ft; |
460 | mutex_unlock(&fn_mutex); | ||
444 | return ft; | 461 | return ft; |
445 | } | 462 | } |
446 | } | 463 | } |
447 | 464 | ||
465 | mutex_unlock(&fn_mutex); | ||
448 | return NULL; | 466 | return NULL; |
449 | } | 467 | } |
450 | 468 | ||
@@ -470,6 +488,32 @@ static struct net_device *fcoe_if_to_netdev(const char *buffer) | |||
470 | } | 488 | } |
471 | 489 | ||
472 | /** | 490 | /** |
491 | * libfcoe_device_notification() - Handler for net device events | ||
492 | * @notifier: The context of the notification | ||
493 | * @event: The type of event | ||
494 | * @ptr: The net device that the event was on | ||
495 | * | ||
496 | * This function is called by the Ethernet driver in case of link change event. | ||
497 | * | ||
498 | * Returns: 0 for success | ||
499 | */ | ||
500 | static int libfcoe_device_notification(struct notifier_block *notifier, | ||
501 | ulong event, void *ptr) | ||
502 | { | ||
503 | struct net_device *netdev = ptr; | ||
504 | |||
505 | switch (event) { | ||
506 | case NETDEV_UNREGISTER: | ||
507 | printk(KERN_ERR "libfcoe_device_notification: NETDEV_UNREGISTER %s\n", | ||
508 | netdev->name); | ||
509 | fcoe_del_netdev_mapping(netdev); | ||
510 | break; | ||
511 | } | ||
512 | return NOTIFY_OK; | ||
513 | } | ||
514 | |||
515 | |||
516 | /** | ||
473 | * fcoe_transport_create() - Create a fcoe interface | 517 | * fcoe_transport_create() - Create a fcoe interface |
474 | * @buffer: The name of the Ethernet interface to create on | 518 | * @buffer: The name of the Ethernet interface to create on |
475 | * @kp: The associated kernel param | 519 | * @kp: The associated kernel param |