From: Andrew Vasquez <andrew.vasquez@qlogic.com>
To: Linux-SCSI Mailing List <linux-scsi@vger.kernel.org>
Subject: [RFC] adding per scsi-host workqueues for defered processing
Date: Mon, 21 Feb 2005 16:09:37 -0800 [thread overview]
Message-ID: <20050222000937.GA7338@plap.qlogic.org> (raw)
Following discussions which resulted from the:
[RFC] target code updates to support scanned targets
http://marc.theaimsgroup.com/?l=linux-scsi&m=110850749515984&w=2
thread, the overall consensus seems to be that transport-classes
should support a 'true-hotplug' mechanism of device discovery and
removal (this involves both registration and lun-scanning). In order
to facilitate this ability and to not constrain the LLDD from the
typical restrictions of the storage scanning process:
* must be done from process context -- depending on transport type,
discovery can occur from a non-process context
* potentially _long_ scan times -- even if discovery is done from a
'sleeping' capable context, halting a LLDD for discovery purposes
is typically undesirable.
I'd like to propose the addition of a per-Scsi_Host work-queue to
manage these scanning as well as any other (relevant)
lower-level-driver differed requests.
The attached patch adds:
1) a new scsi-host template member 'create_work_queue' which when set
will create a single-threaded (the per-CPU option seemed too
heavyweight) work-queue.
2) an exported helper function scsi_queue_work() to queue the work to
the scsi-host work-queue.
the interface was kept flexible -- queuing of a work_struct object
rather than adding small wrapper functions to perform distinct
operations (i.e. scsi_scan_target_deferred(...), etc) so that any
'deferred' action could be requested by a transport-class or LLDD.
Example usage:
scsi_transport_fc.h:
struct fc_rport {
...
struct work_struct scan_work;
} __attribute__((aligned(sizeof(unsigned long))));
scsi_transport_fc.c:
...
static void fc_scan_rport_work(void *data)
{
struct fc_rport *rport = (struct fc_rport *)data;
scsi_scan_target(&rport->dev, rport->channel,
rport->scsi_target_id, SCAN_WILD_CARD, 0);
}
struct fc_rport *
fc_create_rport(struct Scsi_Host *shost, int channel,
struct fc_rport_identifiers *ids)
{
...
INIT_WORK(&rport->scan_work,
fc_scan_rport_work, rport);
...
void
fc_remote_port_unblock(struct fc_rport *rport)
{
struct Scsi_Host *shost = rport_to_shost(rport);
...
if (rport->port_state == FC_PORTSTATE_OFFLINE)
/* Initiate a full rescan, as all
* scsi_target objects have been previously
* torn-down. */
scsi_queue_work(shost, &rport->scan_work);
else
scsi_target_unblock(&rport->dev);
Anyway, comments?
--
Andrew Vasquez
===== drivers/scsi/hosts.c 1.107 vs edited =====
--- 1.107/drivers/scsi/hosts.c 2005-01-18 11:15:06 -08:00
+++ edited/drivers/scsi/hosts.c 2005-02-21 15:10:38 -08:00
@@ -160,6 +160,9 @@ static void scsi_host_dev_release(struct
shost->eh_notify = NULL;
}
+ if (shost->create_work_queue)
+ destroy_workqueue(shost->work_q);
+
scsi_proc_hostdir_rm(shost->hostt);
scsi_destroy_command_freelist(shost);
kfree(shost->shost_data);
@@ -247,6 +250,7 @@ struct Scsi_Host *scsi_host_alloc(struct
shost->cmd_per_lun = sht->cmd_per_lun;
shost->unchecked_isa_dma = sht->unchecked_isa_dma;
shost->use_clustering = sht->use_clustering;
+ shost->create_work_queue = sht->create_work_queue;
if (sht->max_host_blocked)
shost->max_host_blocked = sht->max_host_blocked;
@@ -285,16 +289,27 @@ struct Scsi_Host *scsi_host_alloc(struct
snprintf(shost->shost_classdev.class_id, BUS_ID_SIZE, "host%d",
shost->host_no);
+ if (shost->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 fail_destroy_freelist;
+ }
+
shost->eh_notify = &complete;
rval = kernel_thread(scsi_error_handler, shost, 0);
if (rval < 0)
- goto fail_destroy_freelist;
+ goto fail_destroy_workqueue;
wait_for_completion(&complete);
shost->eh_notify = NULL;
scsi_proc_hostdir_add(shost->hostt);
return shost;
+ fail_destroy_workqueue:
+ destroy_workqueue(shost->work_q);
fail_destroy_freelist:
scsi_destroy_command_freelist(shost);
fail_kfree:
@@ -392,3 +407,26 @@ int scsi_is_host_device(const struct 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->create_work_queue)) {
+ 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);
===== include/scsi/scsi_host.h 1.26 vs edited =====
--- 1.26/include/scsi/scsi_host.h 2005-01-19 08:01:21 -08:00
+++ edited/include/scsi/scsi_host.h 2005-02-21 12:13:32 -08:00
@@ -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;
@@ -363,6 +364,11 @@ struct scsi_host_template {
unsigned skip_settle_delay:1;
/*
+ * True if a work-queue should be created for shost processing.
+ */
+ unsigned create_work_queue:1;
+
+ /*
* Countdown for host blocking with no commands outstanding
*/
unsigned int max_host_blocked;
@@ -501,6 +507,11 @@ struct Scsi_Host {
*/
unsigned reverse_ordering:1;
+ unsigned create_work_queue:1;
+
+ char work_q_name[KOBJ_NAME_LEN];
+ struct workqueue_struct *work_q;
+
/*
* Host has rejected a command because it was busy.
*/
@@ -598,6 +609,7 @@ extern void scsi_free_host_dev(struct sc
extern struct scsi_device *scsi_get_host_dev(struct Scsi_Host *);
int scsi_is_host_device(const struct device *);
+extern int scsi_queue_work(struct Scsi_Host *, struct work_struct *);
/* legacy interfaces */
extern struct Scsi_Host *scsi_register(struct scsi_host_template *, int);
next reply other threads:[~2005-02-22 0:09 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-02-22 0:09 Andrew Vasquez [this message]
2005-02-22 1:05 ` [RFC] adding per scsi-host workqueues for defered processing Matthew Wilcox
-- strict thread matches above, loose matches on Subject: below --
2005-02-22 4:08 James.Smart
2005-03-05 13:07 James.Smart
2005-03-08 7:10 ` Andrew Vasquez
2005-03-05 17:30 James.Smart
2005-03-08 7:00 ` Andrew Vasquez
2005-03-08 13:11 ` Luben Tuikov
2005-03-09 5:19 James.Smart
2005-03-09 7:38 ` Andrew Vasquez
2005-03-09 14:25 ` Brian King
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20050222000937.GA7338@plap.qlogic.org \
--to=andrew.vasquez@qlogic.com \
--cc=linux-scsi@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.