Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

authored by

Bhanu Prakash Gollapudi and committed by
James Bottomley
70be6344 f4d2b2b6

+45 -1
+45 -1
drivers/scsi/fcoe/fcoe_transport.c
··· 39 39 static struct fcoe_transport *fcoe_netdev_map_lookup(struct net_device *device); 40 40 static int fcoe_transport_enable(const char *, struct kernel_param *); 41 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 45 static LIST_HEAD(fcoe_transports); 44 - static LIST_HEAD(fcoe_netdevs); 45 46 static DEFINE_MUTEX(ft_mutex); 47 + static LIST_HEAD(fcoe_netdevs); 48 + static DEFINE_MUTEX(fn_mutex); 46 49 47 50 unsigned int libfcoe_debug_logging; 48 51 module_param_named(debug_logging, libfcoe_debug_logging, int, S_IRUGO|S_IWUSR); ··· 77 74 module_param_call(disable, fcoe_transport_disable, NULL, NULL, S_IWUSR); 78 75 __MODULE_PARM_TYPE(disable, "string"); 79 76 MODULE_PARM_DESC(disable, " Disables fcoe on a ethernet interface."); 77 + 78 + /* notification function for packets from net device */ 79 + static struct notifier_block libfcoe_notifier = { 80 + .notifier_call = libfcoe_device_notification, 81 + }; 80 82 81 83 /** 82 84 * fcoe_fc_crc() - Calculates the CRC for a given frame ··· 383 375 384 376 static int __init fcoe_transport_init(void) 385 377 { 378 + register_netdevice_notifier(&libfcoe_notifier); 386 379 return 0; 387 380 } 388 381 ··· 391 382 { 392 383 struct fcoe_transport *ft; 393 384 385 + unregister_netdevice_notifier(&libfcoe_notifier); 394 386 mutex_lock(&ft_mutex); 395 387 list_for_each_entry(ft, &fcoe_transports, list) 396 388 printk(KERN_ERR "FCoE transport %s is still attached!\n", ··· 415 405 nm->netdev = netdev; 416 406 nm->ft = ft; 417 407 408 + mutex_lock(&fn_mutex); 418 409 list_add(&nm->list, &fcoe_netdevs); 410 + mutex_unlock(&fn_mutex); 419 411 return 0; 420 412 } 421 413 ··· 426 414 { 427 415 struct fcoe_netdev_mapping *nm = NULL, *tmp; 428 416 417 + mutex_lock(&fn_mutex); 429 418 list_for_each_entry_safe(nm, tmp, &fcoe_netdevs, list) { 430 419 if (nm->netdev == netdev) { 431 420 list_del(&nm->list); 432 421 kfree(nm); 422 + mutex_unlock(&fn_mutex); 433 423 return; 434 424 } 435 425 } 426 + mutex_unlock(&fn_mutex); 436 427 } 437 428 438 429 ··· 453 438 struct fcoe_transport *ft = NULL; 454 439 struct fcoe_netdev_mapping *nm; 455 440 441 + mutex_lock(&fn_mutex); 456 442 list_for_each_entry(nm, &fcoe_netdevs, list) { 457 443 if (netdev == nm->netdev) { 458 444 ft = nm->ft; 445 + mutex_unlock(&fn_mutex); 459 446 return ft; 460 447 } 461 448 } 462 449 450 + mutex_unlock(&fn_mutex); 463 451 return NULL; 464 452 } 465 453 ··· 486 468 } 487 469 return NULL; 488 470 } 471 + 472 + /** 473 + * libfcoe_device_notification() - Handler for net device events 474 + * @notifier: The context of the notification 475 + * @event: The type of event 476 + * @ptr: The net device that the event was on 477 + * 478 + * This function is called by the Ethernet driver in case of link change event. 479 + * 480 + * Returns: 0 for success 481 + */ 482 + static int libfcoe_device_notification(struct notifier_block *notifier, 483 + ulong event, void *ptr) 484 + { 485 + struct net_device *netdev = ptr; 486 + 487 + switch (event) { 488 + case NETDEV_UNREGISTER: 489 + printk(KERN_ERR "libfcoe_device_notification: NETDEV_UNREGISTER %s\n", 490 + netdev->name); 491 + fcoe_del_netdev_mapping(netdev); 492 + break; 493 + } 494 + return NOTIFY_OK; 495 + } 496 + 489 497 490 498 /** 491 499 * fcoe_transport_create() - Create a fcoe interface