Commit f04ca1b6 authored by Vasu Dev's avatar Vasu Dev Committed by James Bottomley

[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: default avatarVasu Dev <vasu.dev@intel.com>
Signed-off-by: default avatarRobert Love <robert.w.love@intel.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent f2817ec2
......@@ -380,6 +380,42 @@ static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev,
return fcoe;
}
/**
* fcoe_interface_release() - fcoe_port kref release function
* @kref: Embedded reference count in an fcoe_interface struct
*/
static void fcoe_interface_release(struct kref *kref)
{
struct fcoe_interface *fcoe;
struct net_device *netdev;
fcoe = container_of(kref, struct fcoe_interface, kref);
netdev = fcoe->netdev;
/* tear-down the FCoE controller */
fcoe_ctlr_destroy(&fcoe->ctlr);
kfree(fcoe);
dev_put(netdev);
module_put(THIS_MODULE);
}
/**
* fcoe_interface_get() - Get a reference to a FCoE interface
* @fcoe: The FCoE interface to be held
*/
static inline void fcoe_interface_get(struct fcoe_interface *fcoe)
{
kref_get(&fcoe->kref);
}
/**
* fcoe_interface_put() - Put a reference to a FCoE interface
* @fcoe: The FCoE interface to be released
*/
static inline void fcoe_interface_put(struct fcoe_interface *fcoe)
{
kref_put(&fcoe->kref, fcoe_interface_release);
}
/**
* fcoe_interface_cleanup() - Clean up a FCoE interface
* @fcoe: The FCoE interface to be cleaned up
......@@ -392,6 +428,21 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
struct fcoe_ctlr *fip = &fcoe->ctlr;
u8 flogi_maddr[ETH_ALEN];
const struct net_device_ops *ops;
struct fcoe_port *port = lport_priv(fcoe->ctlr.lp);
FCOE_NETDEV_DBG(netdev, "Destroying interface\n");
/* Logout of the fabric */
fc_fabric_logoff(fcoe->ctlr.lp);
/* Cleanup the fc_lport */
fc_lport_destroy(fcoe->ctlr.lp);
/* Stop the transmit retry timer */
del_timer_sync(&port->timer);
/* Free existing transmit skbs */
fcoe_clean_pending_queue(fcoe->ctlr.lp);
/*
* Don't listen for Ethernet packets anymore.
......@@ -414,6 +465,9 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
} else
dev_mc_del(netdev, FIP_ALL_ENODE_MACS);
if (!is_zero_ether_addr(port->data_src_addr))
dev_uc_del(netdev, port->data_src_addr);
/* Tell the LLD we are done w/ FCoE */
ops = netdev->netdev_ops;
if (ops->ndo_fcoe_disable) {
......@@ -421,42 +475,7 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
FCOE_NETDEV_DBG(netdev, "Failed to disable FCoE"
" specific feature for LLD.\n");
}
}
/**
* fcoe_interface_release() - fcoe_port kref release function
* @kref: Embedded reference count in an fcoe_interface struct
*/
static void fcoe_interface_release(struct kref *kref)
{
struct fcoe_interface *fcoe;
struct net_device *netdev;
fcoe = container_of(kref, struct fcoe_interface, kref);
netdev = fcoe->netdev;
/* tear-down the FCoE controller */
fcoe_ctlr_destroy(&fcoe->ctlr);
kfree(fcoe);
dev_put(netdev);
module_put(THIS_MODULE);
}
/**
* fcoe_interface_get() - Get a reference to a FCoE interface
* @fcoe: The FCoE interface to be held
*/
static inline void fcoe_interface_get(struct fcoe_interface *fcoe)
{
kref_get(&fcoe->kref);
}
/**
* fcoe_interface_put() - Put a reference to a FCoE interface
* @fcoe: The FCoE interface to be released
*/
static inline void fcoe_interface_put(struct fcoe_interface *fcoe)
{
kref_put(&fcoe->kref, fcoe_interface_release);
fcoe_interface_put(fcoe);
}
/**
......@@ -821,39 +840,9 @@ static inline int fcoe_em_config(struct fc_lport *lport)
* fcoe_if_destroy() - Tear down a SW FCoE instance
* @lport: The local port to be destroyed
*
* Locking: must be called with the RTNL mutex held and RTNL mutex
* needed to be dropped by this function since not dropping RTNL
* would cause circular locking warning on synchronous fip worker
* cancelling thru fcoe_interface_put invoked by this function.
*
*/
static void fcoe_if_destroy(struct fc_lport *lport)
{
struct fcoe_port *port = lport_priv(lport);
struct fcoe_interface *fcoe = port->priv;
struct net_device *netdev = fcoe->netdev;
FCOE_NETDEV_DBG(netdev, "Destroying interface\n");
/* Logout of the fabric */
fc_fabric_logoff(lport);
/* Cleanup the fc_lport */
fc_lport_destroy(lport);
/* Stop the transmit retry timer */
del_timer_sync(&port->timer);
/* Free existing transmit skbs */
fcoe_clean_pending_queue(lport);
if (!is_zero_ether_addr(port->data_src_addr))
dev_uc_del(netdev, port->data_src_addr);
rtnl_unlock();
/* receives may not be stopped until after this */
fcoe_interface_put(fcoe);
/* Free queued packets for the per-CPU receive threads */
fcoe_percpu_clean(lport);
......@@ -1836,6 +1825,7 @@ static int fcoe_enable(struct net_device *netdev)
static int fcoe_destroy(struct net_device *netdev)
{
struct fcoe_interface *fcoe;
struct fc_lport *lport;
int rc = 0;
mutex_lock(&fcoe_config_mutex);
......@@ -1846,10 +1836,11 @@ static int fcoe_destroy(struct net_device *netdev)
rc = -ENODEV;
goto out_nodev;
}
fcoe_interface_cleanup(fcoe);
lport = fcoe->ctlr.lp;
list_del(&fcoe->list);
/* RTNL mutex is dropped by fcoe_if_destroy */
fcoe_if_destroy(fcoe->ctlr.lp);
fcoe_interface_cleanup(fcoe);
rtnl_unlock();
fcoe_if_destroy(lport);
out_nodev:
mutex_unlock(&fcoe_config_mutex);
return rc;
......@@ -1865,8 +1856,6 @@ static void fcoe_destroy_work(struct work_struct *work)
port = container_of(work, struct fcoe_port, destroy_work);
mutex_lock(&fcoe_config_mutex);
rtnl_lock();
/* RTNL mutex is dropped by fcoe_if_destroy */
fcoe_if_destroy(port->lport);
mutex_unlock(&fcoe_config_mutex);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment