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
