diff options
author | Hannes Reinecke <hare@suse.de> | 2017-09-15 13:12:14 +0200 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2017-09-15 15:44:49 -0400 |
commit | 7eccdf005b2f240b9e9f53c72eb19367e21a8cf8 (patch) | |
tree | f98061c1c54080ac2897df2364b2c15234c03583 | |
parent | 6f7f74abaec12af6becf0a471d5968bce2f389b6 (diff) | |
download | lwn-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.c | 18 |
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; |