To avoid races and lock-ups where multiple threads are deleting interfaces, hold a mutex over the entire create or delete operation.
This is in reaction to a problem seen where one thread could be deleting an instance, having taken it off the list already, but not to the point of deleting the scsi_host and transport attributes yet, and another thread is in fcoe_exit from rmmod, and reached a BUG() in fc_release_transport() because of the undeleted instance. Note that the existing fcoe_hostlist_lock is left as a r/w lock and held only over list changes so it can be used in the netdev notification. Otherwise we'd have a deadlock with the netdev rtnl_mutex. Signed-off-by: Joe Eykholt <[email protected]> --- drivers/scsi/fcoe/fcoe.c | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 91edf2d..da321e0 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -52,6 +52,7 @@ MODULE_LICENSE("GPL v2"); /* fcoe host list */ LIST_HEAD(fcoe_hostlist); DEFINE_RWLOCK(fcoe_hostlist_lock); +DEFINE_MUTEX(fcoe_config_mutex); DEFINE_PER_CPU(struct fcoe_percpu_s, fcoe_percpu); /* Function Prototypes */ @@ -1602,6 +1603,7 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp) struct fcoe_softc *fc; struct net_device *netdev; + mutex_lock(&fcoe_config_mutex); netdev = fcoe_if_to_netdev(buffer); if (!netdev) { rc = -ENODEV; @@ -1625,6 +1627,7 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp) out_putdev: dev_put(netdev); out_nodev: + mutex_unlock(&fcoe_config_mutex); return rc; } @@ -1640,6 +1643,7 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp) int rc; struct net_device *netdev; + mutex_lock(&fcoe_config_mutex); netdev = fcoe_if_to_netdev(buffer); if (!netdev) { rc = -ENODEV; @@ -1664,6 +1668,7 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp) out_putdev: dev_put(netdev); out_nodev: + mutex_unlock(&fcoe_config_mutex); return rc; } @@ -1849,6 +1854,7 @@ static int __init fcoe_init(void) INIT_LIST_HEAD(&fcoe_hostlist); rwlock_init(&fcoe_hostlist_lock); + mutex_lock(&fcoe_config_mutex); for_each_possible_cpu(cpu) { p = &per_cpu(fcoe_percpu, cpu); skb_queue_head_init(&p->fcoe_rx_list); @@ -1867,6 +1873,7 @@ static int __init fcoe_init(void) fcoe_if_init(); + mutex_unlock(&fcoe_config_mutex); return 0; out_free: @@ -1874,6 +1881,7 @@ out_free: fcoe_percpu_thread_destroy(cpu); } + mutex_unlock(&fcoe_config_mutex); return rc; } module_init(fcoe_init); @@ -1889,6 +1897,7 @@ static void __exit fcoe_exit(void) struct fcoe_softc *fc, *tmp; LIST_HEAD(local_list); + mutex_lock(&fcoe_config_mutex); fcoe_dev_cleanup(); write_lock_bh(&fcoe_hostlist_lock); @@ -1907,5 +1916,6 @@ static void __exit fcoe_exit(void) /* detach from scsi transport */ fcoe_if_exit(); + mutex_unlock(&fcoe_config_mutex); } module_exit(fcoe_exit); _______________________________________________ devel mailing list [email protected] http://www.open-fcoe.org/mailman/listinfo/devel
