summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHannes Reinecke <hare@suse.de>2017-09-15 13:12:14 +0200
committerMartin K. Petersen <martin.petersen@oracle.com>2017-09-15 15:44:49 -0400
commit7eccdf005b2f240b9e9f53c72eb19367e21a8cf8 (patch)
treef98061c1c54080ac2897df2364b2c15234c03583
parent6f7f74abaec12af6becf0a471d5968bce2f389b6 (diff)
downloadlwn-7eccdf005b2f240b9e9f53c72eb19367e21a8cf8.tar.gz
lwn-7eccdf005b2f240b9e9f53c72eb19367e21a8cf8.zip
scsi: fcoe: open-code fcoe_destroy_work() for NETDEV_UNREGISTER
When a NETDEV_UNREGISTER notification is received the network device is _deleted_ after the callback returns. So we cannot use a workqueue here, as this would cause an inversion when removing the device as the netdev is already gone. This manifests with a nasty warning during shutdown: sysfs group ffffffff81eff0e0 not found for kobject 'fc_host7' So open-code fcoe_destroy_work() when receiving the notification to avoid this inversion. Signed-off-by: Hannes Reinecke <hare@suse.com> Reviewed-by: Lee Duncan <lduncan@suse.com> Acked-by: Johannes Thumshirn <jth@kernel.org> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
-rw-r--r--drivers/scsi/fcoe/fcoe.c18
1 files changed, 13 insertions, 5 deletions
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index 617348fa4e86..77adced58ebf 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -1009,6 +1009,8 @@ skip_oem:
* 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.
+ *
*/
static void fcoe_if_destroy(struct fc_lport *lport)
{
@@ -1030,14 +1032,12 @@ static void fcoe_if_destroy(struct fc_lport *lport)
/* Free existing transmit skbs */
fcoe_clean_pending_queue(lport);
- rtnl_lock();
if (!is_zero_ether_addr(port->data_src_addr))
dev_uc_del(netdev, port->data_src_addr);
if (lport->vport)
synchronize_net();
else
fcoe_interface_remove(fcoe);
- rtnl_unlock();
/* Free queued packets for the per-CPU receive threads */
fcoe_percpu_clean(lport);
@@ -1898,7 +1898,14 @@ static int fcoe_device_notification(struct notifier_block *notifier,
case NETDEV_UNREGISTER:
list_del(&fcoe->list);
port = lport_priv(ctlr->lp);
- queue_work(fcoe_wq, &port->destroy_work);
+ fcoe_vport_remove(lport);
+ mutex_lock(&fcoe_config_mutex);
+ fcoe_if_destroy(lport);
+ if (!fcoe->removed)
+ fcoe_interface_remove(fcoe);
+ fcoe_interface_cleanup(fcoe);
+ mutex_unlock(&fcoe_config_mutex);
+ fcoe_ctlr_device_delete(fcoe_ctlr_to_ctlr_dev(ctlr));
goto out;
break;
case NETDEV_FEAT_CHANGE:
@@ -2114,9 +2121,8 @@ static void fcoe_destroy_work(struct work_struct *work)
ctlr = fcoe_to_ctlr(fcoe);
cdev = fcoe_ctlr_to_ctlr_dev(ctlr);
- fcoe_if_destroy(port->lport);
-
rtnl_lock();
+ fcoe_if_destroy(port->lport);
if (!fcoe->removed)
fcoe_interface_remove(fcoe);
rtnl_unlock();
@@ -2720,7 +2726,9 @@ static int fcoe_vport_destroy(struct fc_vport *vport)
mutex_unlock(&n_port->lp_mutex);
mutex_lock(&fcoe_config_mutex);
+ rtnl_lock();
fcoe_if_destroy(vn_port);
+ rtnl_unlock();
mutex_unlock(&fcoe_config_mutex);
return 0;