diff options
author | Vasu Dev <vasu.dev@intel.com> | 2011-04-01 19:06:45 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2011-05-01 11:20:59 -0400 |
commit | f04ca1b65480df9ecbaaa797e62b063387429410 (patch) | |
tree | 31f3c58011bf0447c0a93698d3e7bba4a746c48d /drivers/scsi | |
parent | f2817ec2e0faece03959888050730ed35e5f2bd2 (diff) |
[SCSI] fcoe: have fcoe log off and lport destroy before ndo_fcoe_disable
Currently fcoe interface cleanup is done after ndo_fcoe_disable
and that prevents logoff going out to the peer, so this patch
moves all netdev cleanup and its releasing inside
fcoe_interface_cleanup to have log off before ndo_fcoe_disable
disables the fcoe.
This patch also fixes asymmetric rtnl locking around fcoe_if_destroy,
as currently this function requires rtnl held by its caller
and then have this func drops the lock, instead now don't have
any processing under rtnl inside fcoe_if_destroy, this required
moving few func to get build working again.
Signed-off-by: Vasu Dev <vasu.dev@intel.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')
-rw-r--r-- | drivers/scsi/fcoe/fcoe.c | 131 |
1 files changed, 60 insertions, 71 deletions
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 34408d945175..5d3700dc6f8c 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c | |||
@@ -381,6 +381,42 @@ out: | |||
381 | } | 381 | } |
382 | 382 | ||
383 | /** | 383 | /** |
384 | * fcoe_interface_release() - fcoe_port kref release function | ||
385 | * @kref: Embedded reference count in an fcoe_interface struct | ||
386 | */ | ||
387 | static void fcoe_interface_release(struct kref *kref) | ||
388 | { | ||
389 | struct fcoe_interface *fcoe; | ||
390 | struct net_device *netdev; | ||
391 | |||
392 | fcoe = container_of(kref, struct fcoe_interface, kref); | ||
393 | netdev = fcoe->netdev; | ||
394 | /* tear-down the FCoE controller */ | ||
395 | fcoe_ctlr_destroy(&fcoe->ctlr); | ||
396 | kfree(fcoe); | ||
397 | dev_put(netdev); | ||
398 | module_put(THIS_MODULE); | ||
399 | } | ||
400 | |||
401 | /** | ||
402 | * fcoe_interface_get() - Get a reference to a FCoE interface | ||
403 | * @fcoe: The FCoE interface to be held | ||
404 | */ | ||
405 | static inline void fcoe_interface_get(struct fcoe_interface *fcoe) | ||
406 | { | ||
407 | kref_get(&fcoe->kref); | ||
408 | } | ||
409 | |||
410 | /** | ||
411 | * fcoe_interface_put() - Put a reference to a FCoE interface | ||
412 | * @fcoe: The FCoE interface to be released | ||
413 | */ | ||
414 | static inline void fcoe_interface_put(struct fcoe_interface *fcoe) | ||
415 | { | ||
416 | kref_put(&fcoe->kref, fcoe_interface_release); | ||
417 | } | ||
418 | |||
419 | /** | ||
384 | * fcoe_interface_cleanup() - Clean up a FCoE interface | 420 | * fcoe_interface_cleanup() - Clean up a FCoE interface |
385 | * @fcoe: The FCoE interface to be cleaned up | 421 | * @fcoe: The FCoE interface to be cleaned up |
386 | * | 422 | * |
@@ -392,6 +428,21 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe) | |||
392 | struct fcoe_ctlr *fip = &fcoe->ctlr; | 428 | struct fcoe_ctlr *fip = &fcoe->ctlr; |
393 | u8 flogi_maddr[ETH_ALEN]; | 429 | u8 flogi_maddr[ETH_ALEN]; |
394 | const struct net_device_ops *ops; | 430 | const struct net_device_ops *ops; |
431 | struct fcoe_port *port = lport_priv(fcoe->ctlr.lp); | ||
432 | |||
433 | FCOE_NETDEV_DBG(netdev, "Destroying interface\n"); | ||
434 | |||
435 | /* Logout of the fabric */ | ||
436 | fc_fabric_logoff(fcoe->ctlr.lp); | ||
437 | |||
438 | /* Cleanup the fc_lport */ | ||
439 | fc_lport_destroy(fcoe->ctlr.lp); | ||
440 | |||
441 | /* Stop the transmit retry timer */ | ||
442 | del_timer_sync(&port->timer); | ||
443 | |||
444 | /* Free existing transmit skbs */ | ||
445 | fcoe_clean_pending_queue(fcoe->ctlr.lp); | ||
395 | 446 | ||
396 | /* | 447 | /* |
397 | * Don't listen for Ethernet packets anymore. | 448 | * Don't listen for Ethernet packets anymore. |
@@ -414,6 +465,9 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe) | |||
414 | } else | 465 | } else |
415 | dev_mc_del(netdev, FIP_ALL_ENODE_MACS); | 466 | dev_mc_del(netdev, FIP_ALL_ENODE_MACS); |
416 | 467 | ||
468 | if (!is_zero_ether_addr(port->data_src_addr)) | ||
469 | dev_uc_del(netdev, port->data_src_addr); | ||
470 | |||
417 | /* Tell the LLD we are done w/ FCoE */ | 471 | /* Tell the LLD we are done w/ FCoE */ |
418 | ops = netdev->netdev_ops; | 472 | ops = netdev->netdev_ops; |
419 | if (ops->ndo_fcoe_disable) { | 473 | if (ops->ndo_fcoe_disable) { |
@@ -421,42 +475,7 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe) | |||
421 | FCOE_NETDEV_DBG(netdev, "Failed to disable FCoE" | 475 | FCOE_NETDEV_DBG(netdev, "Failed to disable FCoE" |
422 | " specific feature for LLD.\n"); | 476 | " specific feature for LLD.\n"); |
423 | } | 477 | } |
424 | } | 478 | fcoe_interface_put(fcoe); |
425 | |||
426 | /** | ||
427 | * fcoe_interface_release() - fcoe_port kref release function | ||
428 | * @kref: Embedded reference count in an fcoe_interface struct | ||
429 | */ | ||
430 | static void fcoe_interface_release(struct kref *kref) | ||
431 | { | ||
432 | struct fcoe_interface *fcoe; | ||
433 | struct net_device *netdev; | ||
434 | |||
435 | fcoe = container_of(kref, struct fcoe_interface, kref); | ||
436 | netdev = fcoe->netdev; | ||
437 | /* tear-down the FCoE controller */ | ||
438 | fcoe_ctlr_destroy(&fcoe->ctlr); | ||
439 | kfree(fcoe); | ||
440 | dev_put(netdev); | ||
441 | module_put(THIS_MODULE); | ||
442 | } | ||
443 | |||
444 | /** | ||
445 | * fcoe_interface_get() - Get a reference to a FCoE interface | ||
446 | * @fcoe: The FCoE interface to be held | ||
447 | */ | ||
448 | static inline void fcoe_interface_get(struct fcoe_interface *fcoe) | ||
449 | { | ||
450 | kref_get(&fcoe->kref); | ||
451 | } | ||
452 | |||
453 | /** | ||
454 | * fcoe_interface_put() - Put a reference to a FCoE interface | ||
455 | * @fcoe: The FCoE interface to be released | ||
456 | */ | ||
457 | static inline void fcoe_interface_put(struct fcoe_interface *fcoe) | ||
458 | { | ||
459 | kref_put(&fcoe->kref, fcoe_interface_release); | ||
460 | } | 479 | } |
461 | 480 | ||
462 | /** | 481 | /** |
@@ -821,39 +840,9 @@ skip_oem: | |||
821 | * fcoe_if_destroy() - Tear down a SW FCoE instance | 840 | * fcoe_if_destroy() - Tear down a SW FCoE instance |
822 | * @lport: The local port to be destroyed | 841 | * @lport: The local port to be destroyed |
823 | * | 842 | * |
824 | * Locking: must be called with the RTNL mutex held and RTNL mutex | ||
825 | * needed to be dropped by this function since not dropping RTNL | ||
826 | * would cause circular locking warning on synchronous fip worker | ||
827 | * cancelling thru fcoe_interface_put invoked by this function. | ||
828 | * | ||
829 | */ | 843 | */ |
830 | static void fcoe_if_destroy(struct fc_lport *lport) | 844 | static void fcoe_if_destroy(struct fc_lport *lport) |
831 | { | 845 | { |
832 | struct fcoe_port *port = lport_priv(lport); | ||
833 | struct fcoe_interface *fcoe = port->priv; | ||
834 | struct net_device *netdev = fcoe->netdev; | ||
835 | |||
836 | FCOE_NETDEV_DBG(netdev, "Destroying interface\n"); | ||
837 | |||
838 | /* Logout of the fabric */ | ||
839 | fc_fabric_logoff(lport); | ||
840 | |||
841 | /* Cleanup the fc_lport */ | ||
842 | fc_lport_destroy(lport); | ||
843 | |||
844 | /* Stop the transmit retry timer */ | ||
845 | del_timer_sync(&port->timer); | ||
846 | |||
847 | /* Free existing transmit skbs */ | ||
848 | fcoe_clean_pending_queue(lport); | ||
849 | |||
850 | if (!is_zero_ether_addr(port->data_src_addr)) | ||
851 | dev_uc_del(netdev, port->data_src_addr); | ||
852 | rtnl_unlock(); | ||
853 | |||
854 | /* receives may not be stopped until after this */ | ||
855 | fcoe_interface_put(fcoe); | ||
856 | |||
857 | /* Free queued packets for the per-CPU receive threads */ | 846 | /* Free queued packets for the per-CPU receive threads */ |
858 | fcoe_percpu_clean(lport); | 847 | fcoe_percpu_clean(lport); |
859 | 848 | ||
@@ -1836,6 +1825,7 @@ static int fcoe_enable(struct net_device *netdev) | |||
1836 | static int fcoe_destroy(struct net_device *netdev) | 1825 | static int fcoe_destroy(struct net_device *netdev) |
1837 | { | 1826 | { |
1838 | struct fcoe_interface *fcoe; | 1827 | struct fcoe_interface *fcoe; |
1828 | struct fc_lport *lport; | ||
1839 | int rc = 0; | 1829 | int rc = 0; |
1840 | 1830 | ||
1841 | mutex_lock(&fcoe_config_mutex); | 1831 | mutex_lock(&fcoe_config_mutex); |
@@ -1846,10 +1836,11 @@ static int fcoe_destroy(struct net_device *netdev) | |||
1846 | rc = -ENODEV; | 1836 | rc = -ENODEV; |
1847 | goto out_nodev; | 1837 | goto out_nodev; |
1848 | } | 1838 | } |
1849 | fcoe_interface_cleanup(fcoe); | 1839 | lport = fcoe->ctlr.lp; |
1850 | list_del(&fcoe->list); | 1840 | list_del(&fcoe->list); |
1851 | /* RTNL mutex is dropped by fcoe_if_destroy */ | 1841 | fcoe_interface_cleanup(fcoe); |
1852 | fcoe_if_destroy(fcoe->ctlr.lp); | 1842 | rtnl_unlock(); |
1843 | fcoe_if_destroy(lport); | ||
1853 | out_nodev: | 1844 | out_nodev: |
1854 | mutex_unlock(&fcoe_config_mutex); | 1845 | mutex_unlock(&fcoe_config_mutex); |
1855 | return rc; | 1846 | return rc; |
@@ -1865,8 +1856,6 @@ static void fcoe_destroy_work(struct work_struct *work) | |||
1865 | 1856 | ||
1866 | port = container_of(work, struct fcoe_port, destroy_work); | 1857 | port = container_of(work, struct fcoe_port, destroy_work); |
1867 | mutex_lock(&fcoe_config_mutex); | 1858 | mutex_lock(&fcoe_config_mutex); |
1868 | rtnl_lock(); | ||
1869 | /* RTNL mutex is dropped by fcoe_if_destroy */ | ||
1870 | fcoe_if_destroy(port->lport); | 1859 | fcoe_if_destroy(port->lport); |
1871 | mutex_unlock(&fcoe_config_mutex); | 1860 | mutex_unlock(&fcoe_config_mutex); |
1872 | } | 1861 | } |