فهرست منبع

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>
Hannes Reinecke 8 سال پیش
والد
کامیت
7eccdf005b
1فایلهای تغییر یافته به همراه13 افزوده شده و 5 حذف شده
  1. 13 5
      drivers/scsi/fcoe/fcoe.c

+ 13 - 5
drivers/scsi/fcoe/fcoe.c

@@ -1009,6 +1009,8 @@ skip_oem:
  * fcoe_if_destroy() - Tear down a SW FCoE instance
  * fcoe_if_destroy() - Tear down a SW FCoE instance
  * @lport: The local port to be destroyed
  * @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)
 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 */
 	/* Free existing transmit skbs */
 	fcoe_clean_pending_queue(lport);
 	fcoe_clean_pending_queue(lport);
 
 
-	rtnl_lock();
 	if (!is_zero_ether_addr(port->data_src_addr))
 	if (!is_zero_ether_addr(port->data_src_addr))
 		dev_uc_del(netdev, port->data_src_addr);
 		dev_uc_del(netdev, port->data_src_addr);
 	if (lport->vport)
 	if (lport->vport)
 		synchronize_net();
 		synchronize_net();
 	else
 	else
 		fcoe_interface_remove(fcoe);
 		fcoe_interface_remove(fcoe);
-	rtnl_unlock();
 
 
 	/* Free queued packets for the per-CPU receive threads */
 	/* Free queued packets for the per-CPU receive threads */
 	fcoe_percpu_clean(lport);
 	fcoe_percpu_clean(lport);
@@ -1898,7 +1898,14 @@ static int fcoe_device_notification(struct notifier_block *notifier,
 	case NETDEV_UNREGISTER:
 	case NETDEV_UNREGISTER:
 		list_del(&fcoe->list);
 		list_del(&fcoe->list);
 		port = lport_priv(ctlr->lp);
 		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;
 		goto out;
 		break;
 		break;
 	case NETDEV_FEAT_CHANGE:
 	case NETDEV_FEAT_CHANGE:
@@ -2114,9 +2121,8 @@ static void fcoe_destroy_work(struct work_struct *work)
 	ctlr = fcoe_to_ctlr(fcoe);
 	ctlr = fcoe_to_ctlr(fcoe);
 	cdev = fcoe_ctlr_to_ctlr_dev(ctlr);
 	cdev = fcoe_ctlr_to_ctlr_dev(ctlr);
 
 
-	fcoe_if_destroy(port->lport);
-
 	rtnl_lock();
 	rtnl_lock();
+	fcoe_if_destroy(port->lport);
 	if (!fcoe->removed)
 	if (!fcoe->removed)
 		fcoe_interface_remove(fcoe);
 		fcoe_interface_remove(fcoe);
 	rtnl_unlock();
 	rtnl_unlock();
@@ -2720,7 +2726,9 @@ static int fcoe_vport_destroy(struct fc_vport *vport)
 	mutex_unlock(&n_port->lp_mutex);
 	mutex_unlock(&n_port->lp_mutex);
 
 
 	mutex_lock(&fcoe_config_mutex);
 	mutex_lock(&fcoe_config_mutex);
+	rtnl_lock();
 	fcoe_if_destroy(vn_port);
 	fcoe_if_destroy(vn_port);
+	rtnl_unlock();
 	mutex_unlock(&fcoe_config_mutex);
 	mutex_unlock(&fcoe_config_mutex);
 
 
 	return 0;
 	return 0;