[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:

committed by
James Bottomley

parent
a684b8da35
commit
429305e465
@@ -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;
|
||||
|
||||
|
Reference in New Issue
Block a user