[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>
This commit is contained in:
Tejun Heo
2011-01-24 14:57:29 +01:00
committed by James Bottomley
parent a684b8da35
commit 429305e465
3 changed files with 41 additions and 33 deletions

View File

@@ -1382,53 +1382,50 @@ static u32 mpi_msg_consume(struct pm8001_hba_info *pm8001_ha,
return MPI_IO_STATUS_BUSY;
}
static void pm8001_work_queue(struct work_struct *work)
static void pm8001_work_fn(struct work_struct *work)
{
struct delayed_work *dw = container_of(work, struct delayed_work, work);
struct pm8001_wq *wq = container_of(dw, struct pm8001_wq, work_q);
struct pm8001_work *pw = container_of(work, struct pm8001_work, work);
struct pm8001_device *pm8001_dev;
struct domain_device *dev;
struct domain_device *dev;
switch (wq->handler) {
switch (pw->handler) {
case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
pm8001_dev = wq->data;
pm8001_dev = pw->data;
dev = pm8001_dev->sas_device;
pm8001_I_T_nexus_reset(dev);
break;
case IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY:
pm8001_dev = wq->data;
pm8001_dev = pw->data;
dev = pm8001_dev->sas_device;
pm8001_I_T_nexus_reset(dev);
break;
case IO_DS_IN_ERROR:
pm8001_dev = wq->data;
pm8001_dev = pw->data;
dev = pm8001_dev->sas_device;
pm8001_I_T_nexus_reset(dev);
break;
case IO_DS_NON_OPERATIONAL:
pm8001_dev = wq->data;
pm8001_dev = pw->data;
dev = pm8001_dev->sas_device;
pm8001_I_T_nexus_reset(dev);
break;
}
list_del(&wq->entry);
kfree(wq);
kfree(pw);
}
static int pm8001_handle_event(struct pm8001_hba_info *pm8001_ha, void *data,
int handler)
{
struct pm8001_wq *wq;
struct pm8001_work *pw;
int ret = 0;
wq = kmalloc(sizeof(struct pm8001_wq), GFP_ATOMIC);
if (wq) {
wq->pm8001_ha = pm8001_ha;
wq->data = data;
wq->handler = handler;
INIT_DELAYED_WORK(&wq->work_q, pm8001_work_queue);
list_add_tail(&wq->entry, &pm8001_ha->wq_list);
schedule_delayed_work(&wq->work_q, 0);
pw = kmalloc(sizeof(struct pm8001_work), GFP_ATOMIC);
if (pw) {
pw->pm8001_ha = pm8001_ha;
pw->data = data;
pw->handler = handler;
INIT_WORK(&pw->work, pm8001_work_fn);
queue_work(pm8001_wq, &pw->work);
} else
ret = -ENOMEM;