From: Hannes Reinecke Date: Fri, 15 Sep 2017 11:12:14 +0000 (+0200) Subject: scsi: fcoe: open-code fcoe_destroy_work() for NETDEV_UNREGISTER X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=7eccdf005b2f240b9e9f53c72eb19367e21a8cf8;p=openwrt%2Fstaging%2Fblogic.git 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 Reviewed-by: Lee Duncan Acked-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- 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;