[Open-FCoE] [PATCH 2/5] fcoe: fix unprotected list usage in fcoe_exit()

Joe Eykholt jeykholt at cisco.com
Tue Jul 7 23:59:17 UTC 2009


BUG: unable to handle kernel paging request at 0000000000100100
from fcoe_exit+0x2b.  That address is the list magic which indicates
an item not on the list was being referenced.

The list traversal in fcoe_exit() wasn't protected by mutex, and
a simultaneous /sys write to destroy was going on.

Fix the list traversal to be safe and remove the softc from
the list under the lock.

Signed-off-by: Joe Eykholt <jeykholt at cisco.com>
---
 drivers/scsi/fcoe/fcoe.c |   40 ++++++++++++++++++++--------------------
 1 files changed, 20 insertions(+), 20 deletions(-)


diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index 598a0c6..fb7ab8b 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -502,25 +502,12 @@ skip_oem:
  *
  * Returns: 0 if link is OK for use by FCoE.
  */
-static int fcoe_if_destroy(struct net_device *netdev)
+static int fcoe_if_destroy(struct fcoe_softc *fc)
 {
-	struct fc_lport *lp = NULL;
-	struct fcoe_softc *fc;
-
-	BUG_ON(!netdev);
-
-	FCOE_NETDEV_DBG(netdev, "Destroying interface\n");
+	struct fc_lport *lp;
 
-	write_lock_bh(&fcoe_hostlist_lock);
-	fc = fcoe_hostlist_lookup_softc(netdev);
-	if (!fc) {
-		write_unlock_bh(&fcoe_hostlist_lock);
-		return -ENODEV;
-	}
-	/* Remove the instance from fcoe's list */
-	list_del(&fc->list);
-	write_unlock_bh(&fcoe_hostlist_lock);
 	lp = fc->ctlr.lp;
+	FCOE_NETDEV_DBG(fcoe_netdev(lp), "Destroying interface\n");
 
 	/* Logout of the fabric */
 	fc_fabric_logoff(lp);
@@ -1616,6 +1603,7 @@ static int fcoe_ethdrv_put(const struct net_device *netdev)
 static int fcoe_destroy(const char *buffer, struct kernel_param *kp)
 {
 	int rc;
+	struct fcoe_softc *fc;
 	struct net_device *netdev;
 
 	netdev = fcoe_if_to_netdev(buffer);
@@ -1624,11 +1612,18 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp)
 		goto out_nodev;
 	}
 	/* look for existing lport */
-	if (!fcoe_hostlist_lookup(netdev)) {
+	write_lock_bh(&fcoe_hostlist_lock);
+	fc = fcoe_hostlist_lookup_softc(netdev);
+	if (!fc) {
+		write_unlock_bh(&fcoe_hostlist_lock);
 		rc = -ENODEV;
 		goto out_putdev;
 	}
-	rc = fcoe_if_destroy(netdev);
+	/* Remove the instance from fcoe's list */
+	list_del(&fc->list);
+	write_unlock_bh(&fcoe_hostlist_lock);
+
+	rc = fcoe_if_destroy(fc);
 	if (rc) {
 		printk(KERN_ERR "fcoe: Failed to destroy interface (%s)\n",
 		       netdev->name);
@@ -1902,12 +1897,17 @@ static void __exit fcoe_exit(void)
 {
 	unsigned int cpu;
 	struct fcoe_softc *fc, *tmp;
+	LIST_HEAD(local_list);
 
 	fcoe_dev_cleanup();
 
+	write_lock_bh(&fcoe_hostlist_lock);
+	list_splice_init(&fcoe_hostlist, &local_list);
+	write_unlock_bh(&fcoe_hostlist_lock);
+
 	/* releases the associated fcoe hosts */
-	list_for_each_entry_safe(fc, tmp, &fcoe_hostlist, list)
-		fcoe_if_destroy(fc->real_dev);
+	list_for_each_entry_safe(fc, tmp, &local_list, list)
+		fcoe_if_destroy(fc);
 
 	unregister_hotcpu_notifier(&fcoe_cpu_notifier);
 





More information about the devel mailing list