aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2011-01-28 19:05:32 -0500
committerJames Bottomley <James.Bottomley@suse.de>2011-02-12 12:17:50 -0500
commit2ca32b4848a865fb088e8c00af0dc194701c373a (patch)
tree935d1a9f72f7cf1d6642ae2b427ea73108b3d8e6
parent75a2792df296c77004a72056c76628a1f835bc93 (diff)
[SCSI] fcoe: use dedicated workqueue instead of system_wq
fcoe uses the system_wq to destroy ports and the work items need to be flushed before the driver is unloaded. As the work items free the containing data structure, they can't be flushed directly. The workqueue should be flushed instead. Also, the destruction works can be chained - ie. destruction of a port may lead to destruction of another port where the work item for the former queues the work for the latter. Currently, the depth of chain can be at most two and fcoe_exit() makes sure everything is complete by calling flush_scheduled_work() twice. With commit c8efcc25 (workqueue: allow chained queueing during destruction), destroy_workqueue() can take care of chained works on workqueue destruction. Add and use fcoe_wq instead. Simply destroying fcoe_wq on driver unload takes care of flushing. Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Robert Love <robert.w.love@intel.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
-rw-r--r--drivers/scsi/fcoe/fcoe.c32
1 files changed, 21 insertions, 11 deletions
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index 8a1005d117b7..46c57e5755ae 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -31,6 +31,7 @@
31#include <linux/fs.h> 31#include <linux/fs.h>
32#include <linux/sysfs.h> 32#include <linux/sysfs.h>
33#include <linux/ctype.h> 33#include <linux/ctype.h>
34#include <linux/workqueue.h>
34#include <scsi/scsi_tcq.h> 35#include <scsi/scsi_tcq.h>
35#include <scsi/scsicam.h> 36#include <scsi/scsicam.h>
36#include <scsi/scsi_transport.h> 37#include <scsi/scsi_transport.h>
@@ -58,6 +59,8 @@ MODULE_PARM_DESC(ddp_min, "Minimum I/O size in bytes for " \
58 59
59DEFINE_MUTEX(fcoe_config_mutex); 60DEFINE_MUTEX(fcoe_config_mutex);
60 61
62static struct workqueue_struct *fcoe_wq;
63
61/* fcoe_percpu_clean completion. Waiter protected by fcoe_create_mutex */ 64/* fcoe_percpu_clean completion. Waiter protected by fcoe_create_mutex */
62static DECLARE_COMPLETION(fcoe_flush_completion); 65static DECLARE_COMPLETION(fcoe_flush_completion);
63 66
@@ -1896,7 +1899,7 @@ static int fcoe_device_notification(struct notifier_block *notifier,
1896 list_del(&fcoe->list); 1899 list_del(&fcoe->list);
1897 port = lport_priv(fcoe->ctlr.lp); 1900 port = lport_priv(fcoe->ctlr.lp);
1898 fcoe_interface_cleanup(fcoe); 1901 fcoe_interface_cleanup(fcoe);
1899 schedule_work(&port->destroy_work); 1902 queue_work(fcoe_wq, &port->destroy_work);
1900 goto out; 1903 goto out;
1901 break; 1904 break;
1902 case NETDEV_FEAT_CHANGE: 1905 case NETDEV_FEAT_CHANGE:
@@ -2387,6 +2390,10 @@ static int __init fcoe_init(void)
2387 unsigned int cpu; 2390 unsigned int cpu;
2388 int rc = 0; 2391 int rc = 0;
2389 2392
2393 fcoe_wq = alloc_workqueue("fcoe", 0, 0);
2394 if (!fcoe_wq)
2395 return -ENOMEM;
2396
2390 /* register as a fcoe transport */ 2397 /* register as a fcoe transport */
2391 rc = fcoe_transport_attach(&fcoe_sw_transport); 2398 rc = fcoe_transport_attach(&fcoe_sw_transport);
2392 if (rc) { 2399 if (rc) {
@@ -2425,6 +2432,7 @@ out_free:
2425 fcoe_percpu_thread_destroy(cpu); 2432 fcoe_percpu_thread_destroy(cpu);
2426 } 2433 }
2427 mutex_unlock(&fcoe_config_mutex); 2434 mutex_unlock(&fcoe_config_mutex);
2435 destroy_workqueue(fcoe_wq);
2428 return rc; 2436 return rc;
2429} 2437}
2430module_init(fcoe_init); 2438module_init(fcoe_init);
@@ -2450,7 +2458,7 @@ static void __exit fcoe_exit(void)
2450 list_del(&fcoe->list); 2458 list_del(&fcoe->list);
2451 port = lport_priv(fcoe->ctlr.lp); 2459 port = lport_priv(fcoe->ctlr.lp);
2452 fcoe_interface_cleanup(fcoe); 2460 fcoe_interface_cleanup(fcoe);
2453 schedule_work(&port->destroy_work); 2461 queue_work(fcoe_wq, &port->destroy_work);
2454 } 2462 }
2455 rtnl_unlock(); 2463 rtnl_unlock();
2456 2464
@@ -2461,15 +2469,17 @@ static void __exit fcoe_exit(void)
2461 2469
2462 mutex_unlock(&fcoe_config_mutex); 2470 mutex_unlock(&fcoe_config_mutex);
2463 2471
2464 /* flush any asyncronous interface destroys, 2472 /*
2465 * this should happen after the netdev notifier is unregistered */ 2473 * destroy_work's may be chained but destroy_workqueue()
2466 flush_scheduled_work(); 2474 * can take care of them. Just kill the fcoe_wq.
2467 /* That will flush out all the N_Ports on the hostlist, but now we 2475 */
2468 * may have NPIV VN_Ports scheduled for destruction */ 2476 destroy_workqueue(fcoe_wq);
2469 flush_scheduled_work();
2470 2477
2471 /* detach from scsi transport 2478 /*
2472 * must happen after all destroys are done, therefor after the flush */ 2479 * Detaching from the scsi transport must happen after all
2480 * destroys are done on the fcoe_wq. destroy_workqueue will
2481 * enusre the fcoe_wq is flushed.
2482 */
2473 fcoe_if_exit(); 2483 fcoe_if_exit();
2474 2484
2475 /* detach from fcoe transport */ 2485 /* detach from fcoe transport */
@@ -2618,7 +2628,7 @@ static int fcoe_vport_destroy(struct fc_vport *vport)
2618 mutex_lock(&n_port->lp_mutex); 2628 mutex_lock(&n_port->lp_mutex);
2619 list_del(&vn_port->list); 2629 list_del(&vn_port->list);
2620 mutex_unlock(&n_port->lp_mutex); 2630 mutex_unlock(&n_port->lp_mutex);
2621 schedule_work(&port->destroy_work); 2631 queue_work(fcoe_wq, &port->destroy_work);
2622 return 0; 2632 return 0;
2623} 2633}
2624 2634