Commit 3cb80859 authored by James Smart's avatar James Smart Committed by James Bottomley

[PATCH] add per scsi-host workqueues for defered processing

Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent eec217eb
......@@ -129,6 +129,15 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev)
GFP_KERNEL)) == NULL)
goto out_del_classdev;
if (shost->transportt->create_work_queue) {
snprintf(shost->work_q_name, KOBJ_NAME_LEN, "scsi_wq_%d",
shost->host_no);
shost->work_q = create_singlethread_workqueue(
shost->work_q_name);
if (!shost->work_q)
goto out_free_shost_data;
}
error = scsi_sysfs_add_host(shost);
if (error)
goto out_destroy_host;
......@@ -137,6 +146,10 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev)
return error;
out_destroy_host:
if (shost->work_q)
destroy_workqueue(shost->work_q);
out_free_shost_data:
kfree(shost->shost_data);
out_del_classdev:
class_device_del(&shost->shost_classdev);
out_del_gendev:
......@@ -160,6 +173,9 @@ static void scsi_host_dev_release(struct device *dev)
shost->eh_notify = NULL;
}
if (shost->work_q)
destroy_workqueue(shost->work_q);
scsi_proc_hostdir_rm(shost->hostt);
scsi_destroy_command_freelist(shost);
kfree(shost->shost_data);
......@@ -403,3 +419,27 @@ int scsi_is_host_device(const struct device *dev)
return dev->release == scsi_host_dev_release;
}
EXPORT_SYMBOL(scsi_is_host_device);
/**
* scsi_queue_work - Queue work to the Scsi_Host workqueue.
* @shost: Pointer to Scsi_Host.
* @work: Work to queue for execution.
*
* Return value:
* 0 on success / != 0 for error
**/
int scsi_queue_work(struct Scsi_Host *shost, struct work_struct *work)
{
if (unlikely(!shost->work_q)) {
printk(KERN_ERR
"ERROR: Scsi host '%s' attempted to queue scsi-work, "
"when no workqueue created.\n", shost->hostt->name);
dump_stack();
return -EINVAL;
}
return queue_work(shost->work_q, work);
}
EXPORT_SYMBOL_GPL(scsi_queue_work);
......@@ -4,6 +4,7 @@
#include <linux/device.h>
#include <linux/list.h>
#include <linux/types.h>
#include <linux/workqueue.h>
struct block_device;
struct module;
......@@ -519,6 +520,12 @@ struct Scsi_Host {
unsigned ordered_flush:1;
unsigned ordered_tag:1;
/*
* Optional work queue to be utilized by the transport
*/
char work_q_name[KOBJ_NAME_LEN];
struct workqueue_struct *work_q;
/*
* Host has rejected a command because it was busy.
*/
......@@ -582,6 +589,8 @@ static inline struct Scsi_Host *dev_to_shost(struct device *dev)
return container_of(dev, struct Scsi_Host, shost_gendev);
}
extern int scsi_queue_work(struct Scsi_Host *, struct work_struct *);
extern struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *, int);
extern int __must_check scsi_add_host(struct Scsi_Host *, struct device *);
extern void scsi_scan_host(struct Scsi_Host *);
......
......@@ -34,6 +34,11 @@ struct scsi_transport_template {
int device_size;
int target_size;
int host_size;
/*
* True if the transport wants to use a host-based work-queue
*/
unsigned int create_work_queue : 1;
};
#define transport_class_to_shost(tc) \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment