On Thu, 2011-08-04 at 11:47 -0700, Bhanu Prakash Gollapudi wrote: > Since the driver holds the reference for vlan netdev, the reference has to be > released by the driver when the vlan device is removed. Driver handles this in > NETDEV_UNREGISTER event. > > Signed-off-by: Bhanu Prakash Gollapudi <bprakash@xxxxxxxxxxxx> As per Mike Christie's comments, we need not call __bnx2fc_destroy() with schedule parameter, because we are already in the right context with indicate_netevent being called with rtnl_lock(). Re-spinning this patch alone with 'schedule' parameter removed from __bnx2fc_destroy(). ------------------------ Since the driver holds the reference for vlan netdev, the reference has to be released by the driver when the vlan device is removed. Driver handles this in NETDEV_UNREGISTER event. Signed-off-by: Bhanu Prakash Gollapudi <bprakash@xxxxxxxxxxxx> --- drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 87 ++++++++++++++++++++++--------------- 1 files changed, 52 insertions(+), 35 deletions(-) diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index 673c97c..9a7077b 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -56,6 +56,7 @@ static struct scsi_host_template bnx2fc_shost_template; static struct fc_function_template bnx2fc_transport_function; static struct fc_function_template bnx2fc_vport_xport_function; static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode); +static void __bnx2fc_destroy(struct bnx2fc_interface *interface); static int bnx2fc_destroy(struct net_device *net_device); static int bnx2fc_enable(struct net_device *netdev); static int bnx2fc_disable(struct net_device *netdev); @@ -78,6 +79,7 @@ static void bnx2fc_destroy_work(struct work_struct *work); static struct bnx2fc_hba *bnx2fc_hba_lookup(struct net_device *phys_dev); static struct bnx2fc_interface *bnx2fc_interface_lookup(struct net_device *phys_dev); +static inline void bnx2fc_interface_put(struct bnx2fc_interface *interface); static struct bnx2fc_hba *bnx2fc_find_hba_for_cnic(struct cnic_dev *cnic); static int bnx2fc_fw_init(struct bnx2fc_hba *hba); @@ -783,7 +785,7 @@ static void bnx2fc_destroy_timer(unsigned long data) * @vlan_id: vlan id - associated vlan id with this event * * Handles NETDEV_UP, NETDEV_DOWN, NETDEV_GOING_DOWN,NETDEV_CHANGE and - * NETDEV_CHANGE_MTU events + * NETDEV_CHANGE_MTU events. Handle NETDEV_UNREGISTER only for vlans. */ static void bnx2fc_indicate_netevent(void *context, unsigned long event, u16 vlan_id) @@ -791,12 +793,11 @@ static void bnx2fc_indicate_netevent(void *context, unsigned long event, struct bnx2fc_hba *hba = (struct bnx2fc_hba *)context; struct fc_lport *lport; struct fc_lport *vport; - struct bnx2fc_interface *interface; + struct bnx2fc_interface *interface, *tmp; int wait_for_upload = 0; u32 link_possible = 1; - /* Ignore vlans for now */ - if (vlan_id != 0) + if (vlan_id != 0 && event != NETDEV_UNREGISTER) return; switch (event) { @@ -820,6 +821,18 @@ static void bnx2fc_indicate_netevent(void *context, unsigned long event, case NETDEV_CHANGE: break; + case NETDEV_UNREGISTER: + if (!vlan_id) + return; + mutex_lock(&bnx2fc_dev_lock); + list_for_each_entry_safe(interface, tmp, &if_list, list) { + if (interface->hba != hba) + continue; + __bnx2fc_destroy(interface); + } + mutex_unlock(&bnx2fc_dev_lock); + return; + default: printk(KERN_ERR PFX "Unkonwn netevent %ld", event); return; @@ -1022,12 +1035,27 @@ static int bnx2fc_vport_create(struct fc_vport *vport, bool disabled) return 0; } +static void bnx2fc_free_vport(struct bnx2fc_hba *hba, struct fc_lport *lport) +{ + struct bnx2fc_lport *blport, *tmp; + + spin_lock_bh(&hba->hba_lock); + list_for_each_entry_safe(blport, tmp, &hba->vports, list) { + if (blport->lport == lport) { + list_del(&blport->list); + kfree(blport); + } + } + spin_unlock_bh(&hba->hba_lock); +} + static int bnx2fc_vport_destroy(struct fc_vport *vport) { struct Scsi_Host *shost = vport_to_shost(vport); struct fc_lport *n_port = shost_priv(shost); struct fc_lport *vn_port = vport->dd_data; struct fcoe_port *port = lport_priv(vn_port); + struct bnx2fc_interface *interface = port->priv; struct fc_lport *v_port; bool found = false; @@ -1044,6 +1072,9 @@ static int bnx2fc_vport_destroy(struct fc_vport *vport) } list_del(&vn_port->list); mutex_unlock(&n_port->lp_mutex); + bnx2fc_free_vport(interface->hba, port->lport); + bnx2fc_port_shutdown(port->lport); + bnx2fc_interface_put(interface); queue_work(bnx2fc_wq, &port->destroy_work); return 0; } @@ -1386,7 +1417,6 @@ static void bnx2fc_interface_cleanup(struct bnx2fc_interface *interface) { struct fc_lport *lport = interface->ctlr.lp; struct fcoe_port *port = lport_priv(lport); - struct bnx2fc_lport *blport, *tmp; struct bnx2fc_hba *hba = interface->hba; /* Stop the transmit retry timer */ @@ -1400,14 +1430,7 @@ static void bnx2fc_interface_cleanup(struct bnx2fc_interface *interface) __dev_remove_pack(&interface->fip_packet_type); synchronize_net(); - spin_lock_bh(&hba->hba_lock); - list_for_each_entry_safe(blport, tmp, &hba->vports, list) { - if (blport->lport == lport) { - list_del(&blport->list); - kfree(blport); - } - } - spin_unlock_bh(&hba->hba_lock); + bnx2fc_free_vport(hba, lport); } static void bnx2fc_if_destroy(struct fc_lport *lport) @@ -1433,6 +1456,18 @@ static void bnx2fc_if_destroy(struct fc_lport *lport) scsi_host_put(lport->host); } +static void __bnx2fc_destroy(struct bnx2fc_interface *interface) +{ + struct fc_lport *lport = interface->ctlr.lp; + + bnx2fc_interface_cleanup(interface); + bnx2fc_stop(interface); + list_del(&interface->list); + lport = interface->ctlr.lp; + bnx2fc_interface_put(interface); + bnx2fc_if_destroy(lport); +} + /** * bnx2fc_destroy - Destroy a bnx2fc FCoE interface * @@ -1446,7 +1481,6 @@ static void bnx2fc_if_destroy(struct fc_lport *lport) static int bnx2fc_destroy(struct net_device *netdev) { struct bnx2fc_interface *interface = NULL; - struct fc_lport *lport; int rc = 0; rtnl_lock(); @@ -1460,13 +1494,8 @@ static int bnx2fc_destroy(struct net_device *netdev) } - bnx2fc_interface_cleanup(interface); - lport = interface->ctlr.lp; - bnx2fc_stop(interface); - list_del(&interface->list); destroy_workqueue(interface->timer_work_queue); - bnx2fc_interface_put(interface); - bnx2fc_if_destroy(lport); + __bnx2fc_destroy(interface); netdev_err: mutex_unlock(&bnx2fc_dev_lock); @@ -1478,15 +1507,12 @@ static void bnx2fc_destroy_work(struct work_struct *work) { struct fcoe_port *port; struct fc_lport *lport; - struct bnx2fc_interface *interface; port = container_of(work, struct fcoe_port, destroy_work); lport = port->lport; - interface = port->priv; BNX2FC_HBA_DBG(lport, "Entered bnx2fc_destroy_work\n"); - bnx2fc_port_shutdown(lport); rtnl_lock(); mutex_lock(&bnx2fc_dev_lock); bnx2fc_if_destroy(lport); @@ -2031,7 +2057,6 @@ static void bnx2fc_ulp_exit(struct cnic_dev *dev) { struct bnx2fc_hba *hba; struct bnx2fc_interface *interface, *tmp; - struct fc_lport *lport; BNX2FC_MISC_DBG("Entered bnx2fc_ulp_exit\n"); @@ -2053,18 +2078,10 @@ static void bnx2fc_ulp_exit(struct cnic_dev *dev) list_del_init(&hba->list); adapter_count--; - list_for_each_entry_safe(interface, tmp, &if_list, list) { + list_for_each_entry_safe(interface, tmp, &if_list, list) /* destroy not called yet, move to quiesced list */ - if (interface->hba == hba) { - bnx2fc_interface_cleanup(interface); - bnx2fc_stop(interface); - - list_del(&interface->list); - lport = interface->ctlr.lp; - bnx2fc_interface_put(interface); - bnx2fc_if_destroy(lport); - } - } + if (interface->hba == hba) + __bnx2fc_destroy(interface); mutex_unlock(&bnx2fc_dev_lock); bnx2fc_ulp_stop(hba); -- 1.7.1 > --- > drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 87 +++++++++++++++++++++++------------- > 1 files changed, 55 insertions(+), 32 deletions(-) > > diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c > index d87ab8d..68eda64 100644 > --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c > +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c > @@ -56,6 +56,7 @@ static struct scsi_host_template bnx2fc_shost_template; > static struct fc_function_template bnx2fc_transport_function; > static struct fc_function_template bnx2fc_vport_xport_function; > static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode); > +static void __bnx2fc_destroy(struct bnx2fc_interface *interface, bool schedule); > static int bnx2fc_destroy(struct net_device *net_device); > static int bnx2fc_enable(struct net_device *netdev); > static int bnx2fc_disable(struct net_device *netdev); > @@ -78,6 +79,7 @@ static void bnx2fc_destroy_work(struct work_struct *work); > static struct bnx2fc_hba *bnx2fc_hba_lookup(struct net_device *phys_dev); > static struct bnx2fc_interface *bnx2fc_interface_lookup(struct net_device > *phys_dev); > +static inline void bnx2fc_interface_put(struct bnx2fc_interface *interface); > static struct bnx2fc_hba *bnx2fc_find_hba_for_cnic(struct cnic_dev *cnic); > > static int bnx2fc_fw_init(struct bnx2fc_hba *hba); > @@ -791,7 +793,7 @@ static void bnx2fc_indicate_netevent(void *context, unsigned long event, > struct bnx2fc_hba *hba = (struct bnx2fc_hba *)context; > struct fc_lport *lport; > struct fc_lport *vport; > - struct bnx2fc_interface *interface; > + struct bnx2fc_interface *interface, *tmp; > int wait_for_upload = 0; > u32 link_possible = 1; > > @@ -820,6 +822,18 @@ static void bnx2fc_indicate_netevent(void *context, unsigned long event, > case NETDEV_CHANGE: > break; > > + case NETDEV_UNREGISTER: > + if (!vlan_id) > + return; > + mutex_lock(&bnx2fc_dev_lock); > + list_for_each_entry_safe(interface, tmp, &if_list, list) { > + if (interface->hba != hba) > + continue; > + __bnx2fc_destroy(interface, true); > + } > + mutex_unlock(&bnx2fc_dev_lock); > + return; > + > default: > printk(KERN_ERR PFX "Unkonwn netevent %ld", event); > return; > @@ -1022,12 +1036,27 @@ static int bnx2fc_vport_create(struct fc_vport *vport, bool disabled) > return 0; > } > > +static void bnx2fc_free_vport(struct bnx2fc_hba *hba, struct fc_lport *lport) > +{ > + struct bnx2fc_lport *blport, *tmp; > + > + spin_lock_bh(&hba->hba_lock); > + list_for_each_entry_safe(blport, tmp, &hba->vports, list) { > + if (blport->lport == lport) { > + list_del(&blport->list); > + kfree(blport); > + } > + } > + spin_unlock_bh(&hba->hba_lock); > +} > + > static int bnx2fc_vport_destroy(struct fc_vport *vport) > { > struct Scsi_Host *shost = vport_to_shost(vport); > struct fc_lport *n_port = shost_priv(shost); > struct fc_lport *vn_port = vport->dd_data; > struct fcoe_port *port = lport_priv(vn_port); > + struct bnx2fc_interface *interface = port->priv; > struct fc_lport *v_port; > bool found = false; > > @@ -1045,6 +1074,9 @@ static int bnx2fc_vport_destroy(struct fc_vport *vport) > } > list_del(&vn_port->list); > mutex_unlock(&n_port->lp_mutex); > + bnx2fc_free_vport(interface->hba, port->lport); > + bnx2fc_port_shutdown(port->lport); > + bnx2fc_interface_put(interface); > queue_work(bnx2fc_wq, &port->destroy_work); > return 0; > } > @@ -1387,7 +1419,6 @@ static void bnx2fc_interface_cleanup(struct bnx2fc_interface *interface) > { > struct fc_lport *lport = interface->ctlr.lp; > struct fcoe_port *port = lport_priv(lport); > - struct bnx2fc_lport *blport, *tmp; > struct bnx2fc_hba *hba = interface->hba; > > /* Stop the transmit retry timer */ > @@ -1401,14 +1432,7 @@ static void bnx2fc_interface_cleanup(struct bnx2fc_interface *interface) > __dev_remove_pack(&interface->fip_packet_type); > synchronize_net(); > > - spin_lock_bh(&hba->hba_lock); > - list_for_each_entry_safe(blport, tmp, &hba->vports, list) { > - if (blport->lport == lport) { > - list_del(&blport->list); > - kfree(blport); > - } > - } > - spin_unlock_bh(&hba->hba_lock); > + bnx2fc_free_vport(hba, lport); > } > > static void bnx2fc_if_destroy(struct fc_lport *lport) > @@ -1434,6 +1458,23 @@ static void bnx2fc_if_destroy(struct fc_lport *lport) > scsi_host_put(lport->host); > } > > +static void __bnx2fc_destroy(struct bnx2fc_interface *interface, bool schedule) > +{ > + struct fc_lport *lport = interface->ctlr.lp; > + struct fcoe_port *port = lport_priv(lport); > + > + bnx2fc_interface_cleanup(interface); > + bnx2fc_stop(interface); > + > + list_del(&interface->list); > + lport = interface->ctlr.lp; > + bnx2fc_interface_put(interface); > + if (schedule) > + queue_work(bnx2fc_wq, &port->destroy_work); > + else > + bnx2fc_if_destroy(lport); > +} > + > /** > * bnx2fc_destroy - Destroy a bnx2fc FCoE interface > * > @@ -1447,7 +1488,6 @@ static void bnx2fc_if_destroy(struct fc_lport *lport) > static int bnx2fc_destroy(struct net_device *netdev) > { > struct bnx2fc_interface *interface = NULL; > - struct fc_lport *lport; > int rc = 0; > > rtnl_lock(); > @@ -1461,13 +1501,8 @@ static int bnx2fc_destroy(struct net_device *netdev) > } > > > - bnx2fc_interface_cleanup(interface); > - lport = interface->ctlr.lp; > - bnx2fc_stop(interface); > - list_del(&interface->list); > destroy_workqueue(interface->timer_work_queue); > - bnx2fc_interface_put(interface); > - bnx2fc_if_destroy(lport); > + __bnx2fc_destroy(interface, false); > > netdev_err: > mutex_unlock(&bnx2fc_dev_lock); > @@ -1479,15 +1514,12 @@ static void bnx2fc_destroy_work(struct work_struct *work) > { > struct fcoe_port *port; > struct fc_lport *lport; > - struct bnx2fc_interface *interface; > > port = container_of(work, struct fcoe_port, destroy_work); > lport = port->lport; > - interface = port->priv; > > BNX2FC_HBA_DBG(lport, "Entered bnx2fc_destroy_work\n"); > > - bnx2fc_port_shutdown(lport); > rtnl_lock(); > mutex_lock(&bnx2fc_dev_lock); > bnx2fc_if_destroy(lport); > @@ -2032,7 +2064,6 @@ static void bnx2fc_ulp_exit(struct cnic_dev *dev) > { > struct bnx2fc_hba *hba; > struct bnx2fc_interface *interface, *tmp; > - struct fc_lport *lport; > > BNX2FC_MISC_DBG("Entered bnx2fc_ulp_exit\n"); > > @@ -2054,18 +2085,10 @@ static void bnx2fc_ulp_exit(struct cnic_dev *dev) > list_del_init(&hba->list); > adapter_count--; > > - list_for_each_entry_safe(interface, tmp, &if_list, list) { > + list_for_each_entry_safe(interface, tmp, &if_list, list) > /* destroy not called yet, move to quiesced list */ > - if (interface->hba == hba) { > - bnx2fc_interface_cleanup(interface); > - bnx2fc_stop(interface); > - > - list_del(&interface->list); > - lport = interface->ctlr.lp; > - bnx2fc_interface_put(interface); > - bnx2fc_if_destroy(lport); > - } > - } > + if (interface->hba == hba) > + __bnx2fc_destroy(interface, false); > mutex_unlock(&bnx2fc_dev_lock); > > bnx2fc_ulp_stop(hba); -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html