diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 4834d3c130d69fb61f78562fd0397dc07dcd10aa..0c825c0944f70a4dcf8d30411785c9ad60f0c3a0 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -801,6 +801,12 @@ static inline int fcoe_em_config(struct fc_lport *lport) /** * fcoe_if_destroy() - Tear down a SW FCoE instance * @lport: The local port to be destroyed + * + * Locking: must be called with the RTNL mutex held and RTNL mutex + * needed to be dropped by this function since not dropping RTNL + * would cause circular locking warning on synchronous fip worker + * cancelling thru fcoe_interface_put invoked by this function. + * */ static void fcoe_if_destroy(struct fc_lport *lport) { @@ -823,7 +829,6 @@ static void fcoe_if_destroy(struct fc_lport *lport) /* Free existing transmit skbs */ fcoe_clean_pending_queue(lport); - rtnl_lock(); if (!is_zero_ether_addr(port->data_src_addr)) dev_unicast_delete(netdev, port->data_src_addr); rtnl_unlock(); @@ -1902,7 +1907,12 @@ static int fcoe_disable(const char *buffer, struct kernel_param *kp) goto out_nodev; } - rtnl_lock(); + if (!rtnl_trylock()) { + dev_put(netdev); + mutex_unlock(&fcoe_config_mutex); + return restart_syscall(); + } + fcoe = fcoe_hostlist_lookup_port(netdev); rtnl_unlock(); @@ -1952,7 +1962,12 @@ static int fcoe_enable(const char *buffer, struct kernel_param *kp) goto out_nodev; } - rtnl_lock(); + if (!rtnl_trylock()) { + dev_put(netdev); + mutex_unlock(&fcoe_config_mutex); + return restart_syscall(); + } + fcoe = fcoe_hostlist_lookup_port(netdev); rtnl_unlock(); @@ -2003,7 +2018,12 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp) goto out_nodev; } - rtnl_lock(); + if (!rtnl_trylock()) { + dev_put(netdev); + mutex_unlock(&fcoe_config_mutex); + return restart_syscall(); + } + fcoe = fcoe_hostlist_lookup_port(netdev); if (!fcoe) { rtnl_unlock(); @@ -2012,7 +2032,7 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp) } list_del(&fcoe->list); fcoe_interface_cleanup(fcoe); - rtnl_unlock(); + /* RTNL mutex is dropped by fcoe_if_destroy */ fcoe_if_destroy(fcoe->ctlr.lp); module_put(THIS_MODULE); @@ -2033,6 +2053,8 @@ static void fcoe_destroy_work(struct work_struct *work) port = container_of(work, struct fcoe_port, destroy_work); mutex_lock(&fcoe_config_mutex); + rtnl_lock(); + /* RTNL mutex is dropped by fcoe_if_destroy */ fcoe_if_destroy(port->lport); mutex_unlock(&fcoe_config_mutex); } @@ -2054,6 +2076,12 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp) struct net_device *netdev; mutex_lock(&fcoe_config_mutex); + + if (!rtnl_trylock()) { + mutex_unlock(&fcoe_config_mutex); + return restart_syscall(); + } + #ifdef CONFIG_FCOE_MODULE /* * Make sure the module has been initialized, and is not about to be @@ -2071,7 +2099,6 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp) goto out_nomod; } - rtnl_lock(); netdev = fcoe_if_to_netdev(buffer); if (!netdev) { rc = -ENODEV; @@ -2126,9 +2153,9 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp) out_putdev: dev_put(netdev); out_nodev: - rtnl_unlock(); module_put(THIS_MODULE); out_nomod: + rtnl_unlock(); mutex_unlock(&fcoe_config_mutex); return rc; }