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 <[email protected]>
---
 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);
 


_______________________________________________
devel mailing list
[email protected]
http://www.open-fcoe.org/mailman/listinfo/devel

Reply via email to