aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/fcoe
diff options
context:
space:
mode:
authorRobert Love <robert.w.love@intel.com>2012-02-10 20:18:41 -0500
committerJames Bottomley <JBottomley@Parallels.com>2012-02-19 10:25:17 -0500
commitccefd23ed2d683ad3c0282280e6e6d0b163ad041 (patch)
treea819e2a95ee58e1ccf7f7537be2407f5d6e7dfd9 /drivers/scsi/fcoe
parent6f68794c9283bbce3f7c91d3be34cb4f4f6ed960 (diff)
[SCSI] fcoe: Do not switch context in vport_delete callback
Currently all port deletion is routed though the FCoE workqueue (fcoe_wq). When fc_remove_host is called on an N_Port (for example, from fcoe_destroy) the vports are queued into a FC Transport workqueue. fc_remove_host flushes that queue and each vport is passed to fcoe's fcoe_vport_destroy, which simply queues the associated fcoe_ports for later deletion. This queue cannot be flushed within the N_Ports destroy path because of circular locking issues. The result is that the NPIV ports are destroyed after the N_Port, which is reverse of how they are created. This quirk causes fcoe to keep references on the fcoe_interface shared by each of these ports (N_Port and NPIV). Changing the ordering such that NPIV ports are destroyed before the N_Port will allow us to remove reference counting on the fcoe_interface instances. This patch simply allows fcoe_vport_destory to destroy NPIV ports without deferring them to a workqueue context. This ensures that when fc_remove_host is called the NPIV ports will be destroyed first before the N_Port and allows reference counting on the fcoe's fcoe_interface to be remove in a later patch. Signed-off-by: Robert Love <robert.w.love@intel.com> Tested-by: Ross Brattain <ross.b.brattain@intel.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/fcoe')
-rw-r--r--drivers/scsi/fcoe/fcoe.c15
1 files changed, 6 insertions, 9 deletions
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index 449d31ea07bd..5126685ab982 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -2107,20 +2107,14 @@ static void fcoe_destroy_work(struct work_struct *work)
2107{ 2107{
2108 struct fcoe_port *port; 2108 struct fcoe_port *port;
2109 struct fcoe_interface *fcoe; 2109 struct fcoe_interface *fcoe;
2110 int npiv = 0;
2111 2110
2112 port = container_of(work, struct fcoe_port, destroy_work); 2111 port = container_of(work, struct fcoe_port, destroy_work);
2113 mutex_lock(&fcoe_config_mutex); 2112 mutex_lock(&fcoe_config_mutex);
2114 2113
2115 /* set if this is an NPIV port */
2116 npiv = port->lport->vport ? 1 : 0;
2117
2118 fcoe = port->priv; 2114 fcoe = port->priv;
2119 fcoe_if_destroy(port->lport); 2115 fcoe_if_destroy(port->lport);
2120 2116
2121 /* Do not tear down the fcoe interface for NPIV port */ 2117 fcoe_interface_cleanup(fcoe);
2122 if (!npiv)
2123 fcoe_interface_cleanup(fcoe);
2124 2118
2125 mutex_unlock(&fcoe_config_mutex); 2119 mutex_unlock(&fcoe_config_mutex);
2126} 2120}
@@ -2691,12 +2685,15 @@ static int fcoe_vport_destroy(struct fc_vport *vport)
2691 struct Scsi_Host *shost = vport_to_shost(vport); 2685 struct Scsi_Host *shost = vport_to_shost(vport);
2692 struct fc_lport *n_port = shost_priv(shost); 2686 struct fc_lport *n_port = shost_priv(shost);
2693 struct fc_lport *vn_port = vport->dd_data; 2687 struct fc_lport *vn_port = vport->dd_data;
2694 struct fcoe_port *port = lport_priv(vn_port);
2695 2688
2696 mutex_lock(&n_port->lp_mutex); 2689 mutex_lock(&n_port->lp_mutex);
2697 list_del(&vn_port->list); 2690 list_del(&vn_port->list);
2698 mutex_unlock(&n_port->lp_mutex); 2691 mutex_unlock(&n_port->lp_mutex);
2699 queue_work(fcoe_wq, &port->destroy_work); 2692
2693 mutex_lock(&fcoe_config_mutex);
2694 fcoe_if_destroy(vn_port);
2695 mutex_unlock(&fcoe_config_mutex);
2696
2700 return 0; 2697 return 0;
2701} 2698}
2702 2699