diff options
author | Tejun Heo <tj@kernel.org> | 2011-01-24 08:57:29 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2011-02-12 11:31:03 -0500 |
commit | 429305e4650c5d3395c21ca183455a3f3e3568af (patch) | |
tree | 22f80762c0a2d3dcca39bde7aec19e5401a3d292 /drivers/scsi/pm8001/pm8001_hwi.c | |
parent | a684b8da35a429a246ec2a91e2742bdff5209709 (diff) |
[SCSI] pm8001: simplify workqueue usage
pm8001 manages its own list of pending works and cancel them on device
free. It is unnecessarily complex and has a race condition - the
works are canceled but not synced, so the work could still be running
during and after the data structures are freed.
This patch simplifies workqueue usage.
* A driver specific workqueue pm8001_wq is created to serve these
work items.
* To avoid confusion, the "queue" suffixes are dropped from work items
and functions.
* Delayed queueing was never used. pm8001_work now uses work_struct
instead.
* The driver no longer keeps track of pending works. All pm8001_works
are queued to pm8001_wq and the workqueue is flushed as necessary.
flush_scheduled_work() usage is removed during conversion.
Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Jack Wang <jack_wang@usish.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/pm8001/pm8001_hwi.c')
-rw-r--r-- | drivers/scsi/pm8001/pm8001_hwi.c | 37 |
1 files changed, 17 insertions, 20 deletions
diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index d8db0137c0c..18b6c55cd08 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c | |||
@@ -1382,53 +1382,50 @@ static u32 mpi_msg_consume(struct pm8001_hba_info *pm8001_ha, | |||
1382 | return MPI_IO_STATUS_BUSY; | 1382 | return MPI_IO_STATUS_BUSY; |
1383 | } | 1383 | } |
1384 | 1384 | ||
1385 | static void pm8001_work_queue(struct work_struct *work) | 1385 | static void pm8001_work_fn(struct work_struct *work) |
1386 | { | 1386 | { |
1387 | struct delayed_work *dw = container_of(work, struct delayed_work, work); | 1387 | struct pm8001_work *pw = container_of(work, struct pm8001_work, work); |
1388 | struct pm8001_wq *wq = container_of(dw, struct pm8001_wq, work_q); | ||
1389 | struct pm8001_device *pm8001_dev; | 1388 | struct pm8001_device *pm8001_dev; |
1390 | struct domain_device *dev; | 1389 | struct domain_device *dev; |
1391 | 1390 | ||
1392 | switch (wq->handler) { | 1391 | switch (pw->handler) { |
1393 | case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS: | 1392 | case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS: |
1394 | pm8001_dev = wq->data; | 1393 | pm8001_dev = pw->data; |
1395 | dev = pm8001_dev->sas_device; | 1394 | dev = pm8001_dev->sas_device; |
1396 | pm8001_I_T_nexus_reset(dev); | 1395 | pm8001_I_T_nexus_reset(dev); |
1397 | break; | 1396 | break; |
1398 | case IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY: | 1397 | case IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY: |
1399 | pm8001_dev = wq->data; | 1398 | pm8001_dev = pw->data; |
1400 | dev = pm8001_dev->sas_device; | 1399 | dev = pm8001_dev->sas_device; |
1401 | pm8001_I_T_nexus_reset(dev); | 1400 | pm8001_I_T_nexus_reset(dev); |
1402 | break; | 1401 | break; |
1403 | case IO_DS_IN_ERROR: | 1402 | case IO_DS_IN_ERROR: |
1404 | pm8001_dev = wq->data; | 1403 | pm8001_dev = pw->data; |
1405 | dev = pm8001_dev->sas_device; | 1404 | dev = pm8001_dev->sas_device; |
1406 | pm8001_I_T_nexus_reset(dev); | 1405 | pm8001_I_T_nexus_reset(dev); |
1407 | break; | 1406 | break; |
1408 | case IO_DS_NON_OPERATIONAL: | 1407 | case IO_DS_NON_OPERATIONAL: |
1409 | pm8001_dev = wq->data; | 1408 | pm8001_dev = pw->data; |
1410 | dev = pm8001_dev->sas_device; | 1409 | dev = pm8001_dev->sas_device; |
1411 | pm8001_I_T_nexus_reset(dev); | 1410 | pm8001_I_T_nexus_reset(dev); |
1412 | break; | 1411 | break; |
1413 | } | 1412 | } |
1414 | list_del(&wq->entry); | 1413 | kfree(pw); |
1415 | kfree(wq); | ||
1416 | } | 1414 | } |
1417 | 1415 | ||
1418 | static int pm8001_handle_event(struct pm8001_hba_info *pm8001_ha, void *data, | 1416 | static int pm8001_handle_event(struct pm8001_hba_info *pm8001_ha, void *data, |
1419 | int handler) | 1417 | int handler) |
1420 | { | 1418 | { |
1421 | struct pm8001_wq *wq; | 1419 | struct pm8001_work *pw; |
1422 | int ret = 0; | 1420 | int ret = 0; |
1423 | 1421 | ||
1424 | wq = kmalloc(sizeof(struct pm8001_wq), GFP_ATOMIC); | 1422 | pw = kmalloc(sizeof(struct pm8001_work), GFP_ATOMIC); |
1425 | if (wq) { | 1423 | if (pw) { |
1426 | wq->pm8001_ha = pm8001_ha; | 1424 | pw->pm8001_ha = pm8001_ha; |
1427 | wq->data = data; | 1425 | pw->data = data; |
1428 | wq->handler = handler; | 1426 | pw->handler = handler; |
1429 | INIT_DELAYED_WORK(&wq->work_q, pm8001_work_queue); | 1427 | INIT_WORK(&pw->work, pm8001_work_fn); |
1430 | list_add_tail(&wq->entry, &pm8001_ha->wq_list); | 1428 | queue_work(pm8001_wq, &pw->work); |
1431 | schedule_delayed_work(&wq->work_q, 0); | ||
1432 | } else | 1429 | } else |
1433 | ret = -ENOMEM; | 1430 | ret = -ENOMEM; |
1434 | 1431 | ||