* [PATCH 1/9] scsi: avoid useless free_list lock roundtrips
2014-02-20 22:20 [PATCH 0/9] I/O path micro-optimizations and per-command private data support Christoph Hellwig
@ 2014-02-20 22:20 ` Christoph Hellwig
2014-02-20 22:20 ` [PATCH 2/9] scsi: avoid taking host_lock in scsi_run_queue unless nessecary Christoph Hellwig
` (8 subsequent siblings)
9 siblings, 0 replies; 13+ messages in thread
From: Christoph Hellwig @ 2014-02-20 22:20 UTC (permalink / raw)
To: James Bottomley; +Cc: linux-scsi, Hannes Reinecke
[-- Attachment #1: 0001-scsi-avoid-useless-free_list-lock-roundtrips.patch --]
[-- Type: text/plain, Size: 1136 bytes --]
Avoid hitting the host-wide free_list lock unless we need to put a command
back onto the freelist.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Acked-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/scsi.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index d8afec8..fb86479 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -320,13 +320,14 @@ void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd,
{
unsigned long flags;
- /* changing locks here, don't need to restore the irq state */
- spin_lock_irqsave(&shost->free_list_lock, flags);
if (unlikely(list_empty(&shost->free_list))) {
- list_add(&cmd->list, &shost->free_list);
- cmd = NULL;
+ spin_lock_irqsave(&shost->free_list_lock, flags);
+ if (list_empty(&shost->free_list)) {
+ list_add(&cmd->list, &shost->free_list);
+ cmd = NULL;
+ }
+ spin_unlock_irqrestore(&shost->free_list_lock, flags);
}
- spin_unlock_irqrestore(&shost->free_list_lock, flags);
if (likely(cmd != NULL))
scsi_pool_free_command(shost->cmd_pool, cmd);
--
1.7.10.4
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 2/9] scsi: avoid taking host_lock in scsi_run_queue unless nessecary
2014-02-20 22:20 [PATCH 0/9] I/O path micro-optimizations and per-command private data support Christoph Hellwig
2014-02-20 22:20 ` [PATCH 1/9] scsi: avoid useless free_list lock roundtrips Christoph Hellwig
@ 2014-02-20 22:20 ` Christoph Hellwig
2014-02-21 12:19 ` Hannes Reinecke
2014-02-20 22:20 ` [PATCH 3/9] scsi: do not manipulate device reference counts in scsi_get/put_command Christoph Hellwig
` (7 subsequent siblings)
9 siblings, 1 reply; 13+ messages in thread
From: Christoph Hellwig @ 2014-02-20 22:20 UTC (permalink / raw)
To: James Bottomley; +Cc: linux-scsi
[-- Attachment #1: 0002-scsi-avoid-taking-host_lock-in-scsi_run_queue-unless.patch --]
[-- Type: text/plain, Size: 2111 bytes --]
If we don't have starved devices we don't need to take the host lock
to iterate over them. Also split the function up to be more clear.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/scsi/scsi_lib.c | 43 ++++++++++++++++++++++++-------------------
1 file changed, 24 insertions(+), 19 deletions(-)
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 7bd7f0d..ad516c0 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -385,29 +385,12 @@ static inline int scsi_host_is_busy(struct Scsi_Host *shost)
return 0;
}
-/*
- * Function: scsi_run_queue()
- *
- * Purpose: Select a proper request queue to serve next
- *
- * Arguments: q - last request's queue
- *
- * Returns: Nothing
- *
- * Notes: The previous command was completely finished, start
- * a new one if possible.
- */
-static void scsi_run_queue(struct request_queue *q)
+static void scsi_starved_list_run(struct Scsi_Host *shost)
{
- struct scsi_device *sdev = q->queuedata;
- struct Scsi_Host *shost;
LIST_HEAD(starved_list);
+ struct scsi_device *sdev;
unsigned long flags;
- shost = sdev->host;
- if (scsi_target(sdev)->single_lun)
- scsi_single_lun_run(sdev);
-
spin_lock_irqsave(shost->host_lock, flags);
list_splice_init(&shost->starved_list, &starved_list);
@@ -459,6 +442,28 @@ static void scsi_run_queue(struct request_queue *q)
/* put any unprocessed entries back */
list_splice(&starved_list, &shost->starved_list);
spin_unlock_irqrestore(shost->host_lock, flags);
+}
+
+/*
+ * Function: scsi_run_queue()
+ *
+ * Purpose: Select a proper request queue to serve next
+ *
+ * Arguments: q - last request's queue
+ *
+ * Returns: Nothing
+ *
+ * Notes: The previous command was completely finished, start
+ * a new one if possible.
+ */
+static void scsi_run_queue(struct request_queue *q)
+{
+ struct scsi_device *sdev = q->queuedata;
+
+ if (scsi_target(sdev)->single_lun)
+ scsi_single_lun_run(sdev);
+ if (!list_empty(&sdev->host->starved_list))
+ scsi_starved_list_run(sdev->host);
blk_run_queue(q);
}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [PATCH 2/9] scsi: avoid taking host_lock in scsi_run_queue unless nessecary
2014-02-20 22:20 ` [PATCH 2/9] scsi: avoid taking host_lock in scsi_run_queue unless nessecary Christoph Hellwig
@ 2014-02-21 12:19 ` Hannes Reinecke
0 siblings, 0 replies; 13+ messages in thread
From: Hannes Reinecke @ 2014-02-21 12:19 UTC (permalink / raw)
To: Christoph Hellwig, James Bottomley; +Cc: linux-scsi
On 02/20/2014 11:20 PM, Christoph Hellwig wrote:
> If we don't have starved devices we don't need to take the host lock
> to iterate over them. Also split the function up to be more clear.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
Acked-by: Hannes Reinecke <hare@suse.de>
Cheers,
Hannes
--
Dr. Hannes Reinecke zSeries & Storage
hare@suse.de +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 3/9] scsi: do not manipulate device reference counts in scsi_get/put_command
2014-02-20 22:20 [PATCH 0/9] I/O path micro-optimizations and per-command private data support Christoph Hellwig
2014-02-20 22:20 ` [PATCH 1/9] scsi: avoid useless free_list lock roundtrips Christoph Hellwig
2014-02-20 22:20 ` [PATCH 2/9] scsi: avoid taking host_lock in scsi_run_queue unless nessecary Christoph Hellwig
@ 2014-02-20 22:20 ` Christoph Hellwig
2014-02-21 12:20 ` Hannes Reinecke
2014-02-20 22:20 ` [PATCH 4/9] scsi: remove a useless get/put_device pair in scsi_request_fn Christoph Hellwig
` (6 subsequent siblings)
9 siblings, 1 reply; 13+ messages in thread
From: Christoph Hellwig @ 2014-02-20 22:20 UTC (permalink / raw)
To: James Bottomley; +Cc: linux-scsi
[-- Attachment #1: 0003-scsi-do-not-manipulate-device-reference-counts-in-sc.patch --]
[-- Type: text/plain, Size: 6394 bytes --]
Many callers won't need this and we can optimize them away. In addition
the handling in the __-prefixed variants was inconsistant to start with.
Based on an earlier patch from Bart Van Assche.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/scsi/scsi.c | 36 ++++++++++++------------------------
drivers/scsi/scsi_error.c | 6 ++++++
drivers/scsi/scsi_lib.c | 12 +++++++++++-
drivers/scsi/scsi_tgt_lib.c | 3 ++-
include/scsi/scsi_cmnd.h | 3 +--
5 files changed, 32 insertions(+), 28 deletions(-)
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index fb86479..843b4f1 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -284,27 +284,19 @@ EXPORT_SYMBOL_GPL(__scsi_get_command);
*/
struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask)
{
- struct scsi_cmnd *cmd;
+ struct scsi_cmnd *cmd = __scsi_get_command(dev->host, gfp_mask);
+ unsigned long flags;
- /* Bail if we can't get a reference to the device */
- if (!get_device(&dev->sdev_gendev))
+ if (unlikely(cmd == NULL))
return NULL;
- cmd = __scsi_get_command(dev->host, gfp_mask);
-
- if (likely(cmd != NULL)) {
- unsigned long flags;
-
- cmd->device = dev;
- INIT_LIST_HEAD(&cmd->list);
- INIT_DELAYED_WORK(&cmd->abort_work, scmd_eh_abort_handler);
- spin_lock_irqsave(&dev->list_lock, flags);
- list_add_tail(&cmd->list, &dev->cmd_list);
- spin_unlock_irqrestore(&dev->list_lock, flags);
- cmd->jiffies_at_alloc = jiffies;
- } else
- put_device(&dev->sdev_gendev);
-
+ cmd->device = dev;
+ INIT_LIST_HEAD(&cmd->list);
+ INIT_DELAYED_WORK(&cmd->abort_work, scmd_eh_abort_handler);
+ spin_lock_irqsave(&dev->list_lock, flags);
+ list_add_tail(&cmd->list, &dev->cmd_list);
+ spin_unlock_irqrestore(&dev->list_lock, flags);
+ cmd->jiffies_at_alloc = jiffies;
return cmd;
}
EXPORT_SYMBOL(scsi_get_command);
@@ -315,8 +307,7 @@ EXPORT_SYMBOL(scsi_get_command);
* @cmd: Command to free
* @dev: parent scsi device
*/
-void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd,
- struct device *dev)
+void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
{
unsigned long flags;
@@ -331,8 +322,6 @@ void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd,
if (likely(cmd != NULL))
scsi_pool_free_command(shost->cmd_pool, cmd);
-
- put_device(dev);
}
EXPORT_SYMBOL(__scsi_put_command);
@@ -346,7 +335,6 @@ EXPORT_SYMBOL(__scsi_put_command);
*/
void scsi_put_command(struct scsi_cmnd *cmd)
{
- struct scsi_device *sdev = cmd->device;
unsigned long flags;
/* serious error if the command hasn't come from a device list */
@@ -357,7 +345,7 @@ void scsi_put_command(struct scsi_cmnd *cmd)
cancel_delayed_work(&cmd->abort_work);
- __scsi_put_command(cmd->device->host, cmd, &sdev->sdev_gendev);
+ __scsi_put_command(cmd->device->host, cmd);
}
EXPORT_SYMBOL(scsi_put_command);
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 78b004d..771c16b 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -2288,6 +2288,11 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
if (scsi_autopm_get_host(shost) < 0)
return FAILED;
+ if (!get_device(&dev->sdev_gendev)) {
+ rtn = FAILED;
+ goto out_put_autopm_host;
+ }
+
scmd = scsi_get_command(dev, GFP_KERNEL);
blk_rq_init(NULL, &req);
scmd->request = &req;
@@ -2345,6 +2350,7 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
scsi_run_host_queues(shost);
scsi_next_command(scmd);
+out_put_autopm_host:
scsi_autopm_put_host(shost);
return rtn;
}
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index ad516c0..500178c 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -95,6 +95,7 @@ static void scsi_unprep_request(struct request *req)
req->special = NULL;
scsi_put_command(cmd);
+ put_device(&cmd->device->sdev_gendev);
}
/**
@@ -529,6 +530,7 @@ void scsi_next_command(struct scsi_cmnd *cmd)
get_device(&sdev->sdev_gendev);
scsi_put_command(cmd);
+ put_device(&sdev->sdev_gendev);
scsi_run_queue(q);
/* ok to remove device now */
@@ -1116,6 +1118,7 @@ err_exit:
scsi_release_buffers(cmd);
cmd->request->special = NULL;
scsi_put_command(cmd);
+ put_device(&cmd->device->sdev_gendev);
return error;
}
EXPORT_SYMBOL(scsi_init_io);
@@ -1126,9 +1129,15 @@ static struct scsi_cmnd *scsi_get_cmd_from_req(struct scsi_device *sdev,
struct scsi_cmnd *cmd;
if (!req->special) {
+ /* Bail if we can't get a reference to the device */
+ if (!get_device(&sdev->sdev_gendev))
+ return NULL;
+
cmd = scsi_get_command(sdev, GFP_ATOMIC);
- if (unlikely(!cmd))
+ if (unlikely(!cmd)) {
+ put_device(&sdev->sdev_gendev);
return NULL;
+ }
req->special = cmd;
} else {
cmd = req->special;
@@ -1291,6 +1300,7 @@ int scsi_prep_return(struct request_queue *q, struct request *req, int ret)
struct scsi_cmnd *cmd = req->special;
scsi_release_buffers(cmd);
scsi_put_command(cmd);
+ put_device(&cmd->device->sdev_gendev);
req->special = NULL;
}
break;
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
index 84a1fdf..e51add0 100644
--- a/drivers/scsi/scsi_tgt_lib.c
+++ b/drivers/scsi/scsi_tgt_lib.c
@@ -155,7 +155,8 @@ void scsi_host_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
__blk_put_request(q, rq);
spin_unlock_irqrestore(q->queue_lock, flags);
- __scsi_put_command(shost, cmd, &shost->shost_gendev);
+ __scsi_put_command(shost, cmd);
+ put_device(&shost->shost_gendev);
}
EXPORT_SYMBOL_GPL(scsi_host_put_command);
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index 91558a1..414edf9 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -142,8 +142,7 @@ static inline struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd)
extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t);
extern struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *, gfp_t);
extern void scsi_put_command(struct scsi_cmnd *);
-extern void __scsi_put_command(struct Scsi_Host *, struct scsi_cmnd *,
- struct device *);
+extern void __scsi_put_command(struct Scsi_Host *, struct scsi_cmnd *);
extern void scsi_finish_command(struct scsi_cmnd *cmd);
extern void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count,
--
1.7.10.4
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [PATCH 3/9] scsi: do not manipulate device reference counts in scsi_get/put_command
2014-02-20 22:20 ` [PATCH 3/9] scsi: do not manipulate device reference counts in scsi_get/put_command Christoph Hellwig
@ 2014-02-21 12:20 ` Hannes Reinecke
0 siblings, 0 replies; 13+ messages in thread
From: Hannes Reinecke @ 2014-02-21 12:20 UTC (permalink / raw)
To: Christoph Hellwig, James Bottomley; +Cc: linux-scsi
On 02/20/2014 11:20 PM, Christoph Hellwig wrote:
> Many callers won't need this and we can optimize them away. In addition
> the handling in the __-prefixed variants was inconsistant to start with.
>
> Based on an earlier patch from Bart Van Assche.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
Acked-by: Hannes Reinecke <hare@suse.de>
Cheers,
Hannes
--
Dr. Hannes Reinecke zSeries & Storage
hare@suse.de +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 4/9] scsi: remove a useless get/put_device pair in scsi_request_fn
2014-02-20 22:20 [PATCH 0/9] I/O path micro-optimizations and per-command private data support Christoph Hellwig
` (2 preceding siblings ...)
2014-02-20 22:20 ` [PATCH 3/9] scsi: do not manipulate device reference counts in scsi_get/put_command Christoph Hellwig
@ 2014-02-20 22:20 ` Christoph Hellwig
2014-02-20 22:20 ` [PATCH 5/9] scsi: remove a useless get/put_device pair in scsi_next_command Christoph Hellwig
` (5 subsequent siblings)
9 siblings, 0 replies; 13+ messages in thread
From: Christoph Hellwig @ 2014-02-20 22:20 UTC (permalink / raw)
To: James Bottomley
Cc: linux-scsi, Bart Van Assche, Tejun Heo, Hannes Reinecke,
Mike Christie
[-- Attachment #1: 0004-scsi-remove-a-useless-get-put_device-pair-in-scsi_re.patch --]
[-- Type: text/plain, Size: 2125 bytes --]
From: Bart Van Assche <bvanassche@acm.org>
SCSI devices may only be removed by calling scsi_remove_device().
That function must invoke blk_cleanup_queue() before the final put
of sdev->sdev_gendev. Since blk_cleanup_queue() waits for the
block queue to drain and then tears it down, scsi_request_fn cannot
be active anymore after blk_cleanup_queue() has returned and hence
the get_device()/put_device() pair in scsi_request_fn is unnecessary.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Acked-by: Tejun Heo <tj@kernel.org>
Acked-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Mike Christie <michaelc@cs.wisc.edu>
---
drivers/scsi/scsi_lib.c | 14 +++-----------
1 file changed, 3 insertions(+), 11 deletions(-)
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 500178c..7d35678 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -1558,16 +1558,14 @@ static void scsi_softirq_done(struct request *rq)
* Lock status: IO request lock assumed to be held when called.
*/
static void scsi_request_fn(struct request_queue *q)
+ __releases(q->queue_lock)
+ __acquires(q->queue_lock)
{
struct scsi_device *sdev = q->queuedata;
struct Scsi_Host *shost;
struct scsi_cmnd *cmd;
struct request *req;
- if(!get_device(&sdev->sdev_gendev))
- /* We must be tearing the block queue down already */
- return;
-
/*
* To start with, we keep looping until the queue is empty, or until
* the host is no longer able to accept any more requests.
@@ -1656,7 +1654,7 @@ static void scsi_request_fn(struct request_queue *q)
goto out_delay;
}
- goto out;
+ return;
not_ready:
spin_unlock_irq(shost->host_lock);
@@ -1675,12 +1673,6 @@ static void scsi_request_fn(struct request_queue *q)
out_delay:
if (sdev->device_busy == 0)
blk_delay_queue(q, SCSI_QUEUE_DELAY);
-out:
- /* must be careful here...if we trigger the ->remove() function
- * we cannot be holding the q lock */
- spin_unlock_irq(q->queue_lock);
- put_device(&sdev->sdev_gendev);
- spin_lock_irq(q->queue_lock);
}
u64 scsi_calculate_bounce_limit(struct Scsi_Host *shost)
--
1.7.10.4
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 5/9] scsi: remove a useless get/put_device pair in scsi_next_command
2014-02-20 22:20 [PATCH 0/9] I/O path micro-optimizations and per-command private data support Christoph Hellwig
` (3 preceding siblings ...)
2014-02-20 22:20 ` [PATCH 4/9] scsi: remove a useless get/put_device pair in scsi_request_fn Christoph Hellwig
@ 2014-02-20 22:20 ` Christoph Hellwig
2014-02-20 22:20 ` [PATCH 6/9] scsi: remove a useless get/put_device pair in scsi_requeue_command Christoph Hellwig
` (4 subsequent siblings)
9 siblings, 0 replies; 13+ messages in thread
From: Christoph Hellwig @ 2014-02-20 22:20 UTC (permalink / raw)
To: James Bottomley; +Cc: linux-scsi, Bart Van Assche, Hannes Reinecke
[-- Attachment #1: 0005-scsi-remove-a-useless-get-put_device-pair-in-scsi_ne.patch --]
[-- Type: text/plain, Size: 1049 bytes --]
From: Bart Van Assche <bvanassche@acm.org>
Eliminate a get_device() / put_device() pair from scsi_next_command().
Both are atomic operations hence removing these slightly improves
performance.
[hch: slight changes due to different context]
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Acked-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/scsi/scsi_lib.c | 5 -----
1 file changed, 5 deletions(-)
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 7d35678..91ca414 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -526,14 +526,9 @@ void scsi_next_command(struct scsi_cmnd *cmd)
struct scsi_device *sdev = cmd->device;
struct request_queue *q = sdev->request_queue;
- /* need to hold a reference on the device before we let go of the cmd */
- get_device(&sdev->sdev_gendev);
-
scsi_put_command(cmd);
- put_device(&sdev->sdev_gendev);
scsi_run_queue(q);
- /* ok to remove device now */
put_device(&sdev->sdev_gendev);
}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 6/9] scsi: remove a useless get/put_device pair in scsi_requeue_command
2014-02-20 22:20 [PATCH 0/9] I/O path micro-optimizations and per-command private data support Christoph Hellwig
` (4 preceding siblings ...)
2014-02-20 22:20 ` [PATCH 5/9] scsi: remove a useless get/put_device pair in scsi_next_command Christoph Hellwig
@ 2014-02-20 22:20 ` Christoph Hellwig
2014-02-20 22:20 ` [PATCH 7/9] megaraid: simplify internal command handling Christoph Hellwig
` (3 subsequent siblings)
9 siblings, 0 replies; 13+ messages in thread
From: Christoph Hellwig @ 2014-02-20 22:20 UTC (permalink / raw)
To: James Bottomley; +Cc: linux-scsi, Hannes Reinecke
[-- Attachment #1: 0006-scsi-remove-a-useless-get-put_device-pair-in-scsi_re.patch --]
[-- Type: text/plain, Size: 1907 bytes --]
Avoid a spurious device get/put pair by cleaning up scsi_requeue_command
and folding scsi_unprep_request into it.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Acked-by: Hannes Reinecke <hare@suse.de>
---
drivers/scsi/scsi_lib.c | 35 +++--------------------------------
1 file changed, 3 insertions(+), 32 deletions(-)
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 91ca414..9350691 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -75,29 +75,6 @@ struct kmem_cache *scsi_sdb_cache;
*/
#define SCSI_QUEUE_DELAY 3
-/*
- * Function: scsi_unprep_request()
- *
- * Purpose: Remove all preparation done for a request, including its
- * associated scsi_cmnd, so that it can be requeued.
- *
- * Arguments: req - request to unprepare
- *
- * Lock status: Assumed that no locks are held upon entry.
- *
- * Returns: Nothing.
- */
-static void scsi_unprep_request(struct request *req)
-{
- struct scsi_cmnd *cmd = req->special;
-
- blk_unprep_request(req);
- req->special = NULL;
-
- scsi_put_command(cmd);
- put_device(&cmd->device->sdev_gendev);
-}
-
/**
* __scsi_queue_insert - private queue insertion
* @cmd: The SCSI command being requeued
@@ -503,16 +480,10 @@ static void scsi_requeue_command(struct request_queue *q, struct scsi_cmnd *cmd)
struct request *req = cmd->request;
unsigned long flags;
- /*
- * We need to hold a reference on the device to avoid the queue being
- * killed after the unlock and before scsi_run_queue is invoked which
- * may happen because scsi_unprep_request() puts the command which
- * releases its reference on the device.
- */
- get_device(&sdev->sdev_gendev);
-
spin_lock_irqsave(q->queue_lock, flags);
- scsi_unprep_request(req);
+ blk_unprep_request(req);
+ req->special = NULL;
+ scsi_put_command(cmd);
blk_requeue_request(q, req);
spin_unlock_irqrestore(q->queue_lock, flags);
--
1.7.10.4
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 7/9] megaraid: simplify internal command handling
2014-02-20 22:20 [PATCH 0/9] I/O path micro-optimizations and per-command private data support Christoph Hellwig
` (5 preceding siblings ...)
2014-02-20 22:20 ` [PATCH 6/9] scsi: remove a useless get/put_device pair in scsi_requeue_command Christoph Hellwig
@ 2014-02-20 22:20 ` Christoph Hellwig
2014-02-20 22:21 ` [PATCH 8/9] scsi: simplify command allocation and freeing a bit Christoph Hellwig
` (2 subsequent siblings)
9 siblings, 0 replies; 13+ messages in thread
From: Christoph Hellwig @ 2014-02-20 22:20 UTC (permalink / raw)
To: James Bottomley; +Cc: linux-scsi
[-- Attachment #1: 0007-megaraid-simplify-internal-command-handling.patch --]
[-- Type: text/plain, Size: 9741 bytes --]
We don't use the passed in scsi command for anything, so just add a adapter-
wide internal status to go along with the internal scb that is used unter
int_mtx to pass back the return value and get rid of all the complexities
and abuse of the scsi_cmnd structure.
This gets rid of the only user of scsi_allocate_command/scsi_free_command,
which can now be removed.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Cc: Sumit.Saxena@lsi.com
Cc: kashyap.desai@lsi.com
Cc: megaraidlinux@lsi.com
---
drivers/scsi/megaraid.c | 120 ++++++++++++----------------------------------
drivers/scsi/megaraid.h | 3 +-
drivers/scsi/scsi.c | 56 ----------------------
include/scsi/scsi_cmnd.h | 3 --
4 files changed, 32 insertions(+), 150 deletions(-)
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 816db12..8bca30f 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -531,13 +531,6 @@ mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy)
int target = 0;
int ldrv_num = 0; /* logical drive number */
-
- /*
- * filter the internal and ioctl commands
- */
- if((cmd->cmnd[0] == MEGA_INTERNAL_CMD))
- return (scb_t *)cmd->host_scribble;
-
/*
* We know what channels our logical drives are on - mega_find_card()
*/
@@ -1439,19 +1432,22 @@ mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status)
cmdid = completed[i];
- if( cmdid == CMDID_INT_CMDS ) { /* internal command */
+ /*
+ * Only free SCBs for the commands coming down from the
+ * mid-layer, not for which were issued internally
+ *
+ * For internal command, restore the status returned by the
+ * firmware so that user can interpret it.
+ */
+ if (cmdid == CMDID_INT_CMDS) {
scb = &adapter->int_scb;
- cmd = scb->cmd;
- mbox = (mbox_t *)scb->raw_mbox;
- /*
- * Internal command interface do not fire the extended
- * passthru or 64-bit passthru
- */
- pthru = scb->pthru;
+ list_del_init(&scb->list);
+ scb->state = SCB_FREE;
- }
- else {
+ adapter->int_status = status;
+ complete(&adapter->int_waitq);
+ } else {
scb = &adapter->scb_list[cmdid];
/*
@@ -1640,25 +1636,7 @@ mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status)
cmd->result |= (DID_BAD_TARGET << 16)|status;
}
- /*
- * Only free SCBs for the commands coming down from the
- * mid-layer, not for which were issued internally
- *
- * For internal command, restore the status returned by the
- * firmware so that user can interpret it.
- */
- if( cmdid == CMDID_INT_CMDS ) { /* internal command */
- cmd->result = status;
-
- /*
- * Remove the internal command from the pending list
- */
- list_del_init(&scb->list);
- scb->state = SCB_FREE;
- }
- else {
- mega_free_scb(adapter, scb);
- }
+ mega_free_scb(adapter, scb);
/* Add Scsi_Command to end of completed queue */
list_add_tail(SCSI_LIST(cmd), &adapter->completed_list);
@@ -4133,23 +4111,15 @@ mega_internal_dev_inquiry(adapter_t *adapter, u8 ch, u8 tgt,
* The last argument is the address of the passthru structure if the command
* to be fired is a passthru command
*
- * lockscope specifies whether the caller has already acquired the lock. Of
- * course, the caller must know which lock we are talking about.
- *
* Note: parameter 'pthru' is null for non-passthru commands.
*/
static int
mega_internal_command(adapter_t *adapter, megacmd_t *mc, mega_passthru *pthru)
{
- Scsi_Cmnd *scmd;
- struct scsi_device *sdev;
+ unsigned long flags;
scb_t *scb;
int rval;
- scmd = scsi_allocate_command(GFP_KERNEL);
- if (!scmd)
- return -ENOMEM;
-
/*
* The internal commands share one command id and hence are
* serialized. This is so because we want to reserve maximum number of
@@ -4160,73 +4130,45 @@ mega_internal_command(adapter_t *adapter, megacmd_t *mc, mega_passthru *pthru)
scb = &adapter->int_scb;
memset(scb, 0, sizeof(scb_t));
- sdev = kzalloc(sizeof(struct scsi_device), GFP_KERNEL);
- scmd->device = sdev;
-
- memset(adapter->int_cdb, 0, sizeof(adapter->int_cdb));
- scmd->cmnd = adapter->int_cdb;
- scmd->device->host = adapter->host;
- scmd->host_scribble = (void *)scb;
- scmd->cmnd[0] = MEGA_INTERNAL_CMD;
-
- scb->state |= SCB_ACTIVE;
- scb->cmd = scmd;
+ scb->idx = CMDID_INT_CMDS;
+ scb->state |= SCB_ACTIVE | SCB_PENDQ;
memcpy(scb->raw_mbox, mc, sizeof(megacmd_t));
/*
* Is it a passthru command
*/
- if( mc->cmd == MEGA_MBOXCMD_PASSTHRU ) {
-
+ if (mc->cmd == MEGA_MBOXCMD_PASSTHRU)
scb->pthru = pthru;
- }
-
- scb->idx = CMDID_INT_CMDS;
- megaraid_queue_lck(scmd, mega_internal_done);
+ spin_lock_irqsave(&adapter->lock, flags);
+ list_add_tail(&scb->list, &adapter->pending_list);
+ /*
+ * Check if the HBA is in quiescent state, e.g., during a
+ * delete logical drive opertion. If it is, don't run
+ * the pending_list.
+ */
+ if (atomic_read(&adapter->quiescent) == 0)
+ mega_runpendq(adapter);
+ spin_unlock_irqrestore(&adapter->lock, flags);
wait_for_completion(&adapter->int_waitq);
- rval = scmd->result;
- mc->status = scmd->result;
- kfree(sdev);
+ mc->status = rval = adapter->int_status;
/*
* Print a debug message for all failed commands. Applications can use
* this information.
*/
- if( scmd->result && trace_level ) {
+ if( rval && trace_level ) {
printk("megaraid: cmd [%x, %x, %x] status:[%x]\n",
- mc->cmd, mc->opcode, mc->subopcode, scmd->result);
+ mc->cmd, mc->opcode, mc->subopcode, rval);
}
mutex_unlock(&adapter->int_mtx);
-
- scsi_free_command(GFP_KERNEL, scmd);
-
return rval;
}
-
-/**
- * mega_internal_done()
- * @scmd - internal scsi command
- *
- * Callback routine for internal commands.
- */
-static void
-mega_internal_done(Scsi_Cmnd *scmd)
-{
- adapter_t *adapter;
-
- adapter = (adapter_t *)scmd->device->host->hostdata;
-
- complete(&adapter->int_waitq);
-
-}
-
-
static struct scsi_host_template megaraid_template = {
.module = THIS_MODULE,
.name = "MegaRAID",
diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h
index 4d0ce4e..8f2e026 100644
--- a/drivers/scsi/megaraid.h
+++ b/drivers/scsi/megaraid.h
@@ -853,10 +853,10 @@ typedef struct {
u8 sglen; /* f/w supported scatter-gather list length */
- unsigned char int_cdb[MAX_COMMAND_SIZE];
scb_t int_scb;
struct mutex int_mtx; /* To synchronize the internal
commands */
+ int int_status; /* status of internal cmd */
struct completion int_waitq; /* wait queue for internal
cmds */
@@ -1004,7 +1004,6 @@ static int mega_del_logdrv(adapter_t *, int);
static int mega_do_del_logdrv(adapter_t *, int);
static void mega_get_max_sgl(adapter_t *);
static int mega_internal_command(adapter_t *, megacmd_t *, mega_passthru *);
-static void mega_internal_done(Scsi_Cmnd *);
static int mega_support_cluster(adapter_t *);
#endif
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 843b4f1..a1ac75d 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -404,62 +404,6 @@ static void scsi_put_host_cmd_pool(gfp_t gfp_mask)
}
/**
- * scsi_allocate_command - get a fully allocated SCSI command
- * @gfp_mask: allocation mask
- *
- * This function is for use outside of the normal host based pools.
- * It allocates the relevant command and takes an additional reference
- * on the pool it used. This function *must* be paired with
- * scsi_free_command which also has the identical mask, otherwise the
- * free pool counts will eventually go wrong and you'll trigger a bug.
- *
- * This function should *only* be used by drivers that need a static
- * command allocation at start of day for internal functions.
- */
-struct scsi_cmnd *scsi_allocate_command(gfp_t gfp_mask)
-{
- struct scsi_host_cmd_pool *pool = scsi_get_host_cmd_pool(gfp_mask);
-
- if (!pool)
- return NULL;
-
- return scsi_pool_alloc_command(pool, gfp_mask);
-}
-EXPORT_SYMBOL(scsi_allocate_command);
-
-/**
- * scsi_free_command - free a command allocated by scsi_allocate_command
- * @gfp_mask: mask used in the original allocation
- * @cmd: command to free
- *
- * Note: using the original allocation mask is vital because that's
- * what determines which command pool we use to free the command. Any
- * mismatch will cause the system to BUG eventually.
- */
-void scsi_free_command(gfp_t gfp_mask, struct scsi_cmnd *cmd)
-{
- struct scsi_host_cmd_pool *pool = scsi_get_host_cmd_pool(gfp_mask);
-
- /*
- * this could trigger if the mask to scsi_allocate_command
- * doesn't match this mask. Otherwise we're guaranteed that this
- * succeeds because scsi_allocate_command must have taken a reference
- * on the pool
- */
- BUG_ON(!pool);
-
- scsi_pool_free_command(pool, cmd);
- /*
- * scsi_put_host_cmd_pool is called twice; once to release the
- * reference we took above, and once to release the reference
- * originally taken by scsi_allocate_command
- */
- scsi_put_host_cmd_pool(gfp_mask);
- scsi_put_host_cmd_pool(gfp_mask);
-}
-EXPORT_SYMBOL(scsi_free_command);
-
-/**
* scsi_setup_command_freelist - Setup the command freelist for a scsi host.
* @shost: host to allocate the freelist for.
*
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index 414edf9..dd7c998 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -155,9 +155,6 @@ extern void scsi_release_buffers(struct scsi_cmnd *cmd);
extern int scsi_dma_map(struct scsi_cmnd *cmd);
extern void scsi_dma_unmap(struct scsi_cmnd *cmd);
-struct scsi_cmnd *scsi_allocate_command(gfp_t gfp_mask);
-void scsi_free_command(gfp_t gfp_mask, struct scsi_cmnd *cmd);
-
static inline unsigned scsi_sg_count(struct scsi_cmnd *cmd)
{
return cmd->sdb.table.nents;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 8/9] scsi: simplify command allocation and freeing a bit
2014-02-20 22:20 [PATCH 0/9] I/O path micro-optimizations and per-command private data support Christoph Hellwig
` (6 preceding siblings ...)
2014-02-20 22:20 ` [PATCH 7/9] megaraid: simplify internal command handling Christoph Hellwig
@ 2014-02-20 22:21 ` Christoph Hellwig
2014-02-20 22:21 ` [PATCH 9/9] scsi: add support for per-host cmd pools Christoph Hellwig
2014-03-12 7:27 ` [PATCH 0/9] I/O path micro-optimizations and per-command private data support Christoph Hellwig
9 siblings, 0 replies; 13+ messages in thread
From: Christoph Hellwig @ 2014-02-20 22:21 UTC (permalink / raw)
To: James Bottomley; +Cc: linux-scsi, Paolo Bonzini
[-- Attachment #1: 0008-scsi-simplify-command-allocation-and-freeing-a-bit.patch --]
[-- Type: text/plain, Size: 3815 bytes --]
Just have one level of alloc/free functions that take a host instead
of two levels for the allocation and different calling conventions
for the free.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
---
drivers/scsi/scsi.c | 67 +++++++++++++++++++--------------------------------
1 file changed, 25 insertions(+), 42 deletions(-)
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index a1ac75d..a94a486 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -161,47 +161,20 @@ static struct scsi_host_cmd_pool scsi_cmd_dma_pool = {
static DEFINE_MUTEX(host_cmd_pool_mutex);
/**
- * scsi_pool_alloc_command - internal function to get a fully allocated command
- * @pool: slab pool to allocate the command from
- * @gfp_mask: mask for the allocation
- *
- * Returns a fully allocated command (with the allied sense buffer) or
- * NULL on failure
- */
-static struct scsi_cmnd *
-scsi_pool_alloc_command(struct scsi_host_cmd_pool *pool, gfp_t gfp_mask)
-{
- struct scsi_cmnd *cmd;
-
- cmd = kmem_cache_zalloc(pool->cmd_slab, gfp_mask | pool->gfp_mask);
- if (!cmd)
- return NULL;
-
- cmd->sense_buffer = kmem_cache_alloc(pool->sense_slab,
- gfp_mask | pool->gfp_mask);
- if (!cmd->sense_buffer) {
- kmem_cache_free(pool->cmd_slab, cmd);
- return NULL;
- }
-
- return cmd;
-}
-
-/**
- * scsi_pool_free_command - internal function to release a command
- * @pool: slab pool to allocate the command from
+ * scsi_host_free_command - internal function to release a command
+ * @host: host to free the command for
* @cmd: command to release
*
* the command must previously have been allocated by
- * scsi_pool_alloc_command.
+ * scsi_host_alloc_command.
*/
static void
-scsi_pool_free_command(struct scsi_host_cmd_pool *pool,
- struct scsi_cmnd *cmd)
+scsi_host_free_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
{
+ struct scsi_host_cmd_pool *pool = shost->cmd_pool;
+
if (cmd->prot_sdb)
kmem_cache_free(scsi_sdb_cache, cmd->prot_sdb);
-
kmem_cache_free(pool->sense_slab, cmd->sense_buffer);
kmem_cache_free(pool->cmd_slab, cmd);
}
@@ -217,22 +190,32 @@ scsi_pool_free_command(struct scsi_host_cmd_pool *pool,
static struct scsi_cmnd *
scsi_host_alloc_command(struct Scsi_Host *shost, gfp_t gfp_mask)
{
+ struct scsi_host_cmd_pool *pool = shost->cmd_pool;
struct scsi_cmnd *cmd;
- cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask);
+ cmd = kmem_cache_zalloc(pool->cmd_slab, gfp_mask | pool->gfp_mask);
if (!cmd)
- return NULL;
+ goto fail;
+
+ cmd->sense_buffer = kmem_cache_alloc(pool->sense_slab,
+ gfp_mask | pool->gfp_mask);
+ if (!cmd->sense_buffer)
+ goto fail_free_cmd;
if (scsi_host_get_prot(shost) >= SHOST_DIX_TYPE0_PROTECTION) {
cmd->prot_sdb = kmem_cache_zalloc(scsi_sdb_cache, gfp_mask);
-
- if (!cmd->prot_sdb) {
- scsi_pool_free_command(shost->cmd_pool, cmd);
- return NULL;
- }
+ if (!cmd->prot_sdb)
+ goto fail_free_sense;
}
return cmd;
+
+fail_free_sense:
+ kmem_cache_free(pool->sense_slab, cmd->sense_buffer);
+fail_free_cmd:
+ kmem_cache_free(pool->cmd_slab, cmd);
+fail:
+ return NULL;
}
/**
@@ -321,7 +304,7 @@ void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
}
if (likely(cmd != NULL))
- scsi_pool_free_command(shost->cmd_pool, cmd);
+ scsi_host_free_command(shost, cmd);
}
EXPORT_SYMBOL(__scsi_put_command);
@@ -457,7 +440,7 @@ void scsi_destroy_command_freelist(struct Scsi_Host *shost)
cmd = list_entry(shost->free_list.next, struct scsi_cmnd, list);
list_del_init(&cmd->list);
- scsi_pool_free_command(shost->cmd_pool, cmd);
+ scsi_host_free_command(shost, cmd);
}
shost->cmd_pool = NULL;
scsi_put_host_cmd_pool(shost->unchecked_isa_dma ? GFP_DMA : GFP_KERNEL);
--
1.7.10.4
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 9/9] scsi: add support for per-host cmd pools
2014-02-20 22:20 [PATCH 0/9] I/O path micro-optimizations and per-command private data support Christoph Hellwig
` (7 preceding siblings ...)
2014-02-20 22:21 ` [PATCH 8/9] scsi: simplify command allocation and freeing a bit Christoph Hellwig
@ 2014-02-20 22:21 ` Christoph Hellwig
2014-03-12 7:27 ` [PATCH 0/9] I/O path micro-optimizations and per-command private data support Christoph Hellwig
9 siblings, 0 replies; 13+ messages in thread
From: Christoph Hellwig @ 2014-02-20 22:21 UTC (permalink / raw)
To: James Bottomley; +Cc: linux-scsi, Paolo Bonzini
[-- Attachment #1: 0009-scsi-add-support-for-per-host-cmd-pools.patch --]
[-- Type: text/plain, Size: 5945 bytes --]
This allows drivers to specify the size of their per-command private
data in the host template and then get extra memory allocated for
each command instead of needing another allocation in ->queuecommand.
With the current SCSI code that already does multiple allocations for
each command this probably doesn't make a big performance impact, but
it allows to clean up the drivers, and prepare them for using the
blk-mq infrastructure where the common allocation will make a difference.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
---
drivers/scsi/scsi.c | 96 +++++++++++++++++++++++++++++++++++++---------
include/scsi/scsi_host.h | 7 ++++
2 files changed, 84 insertions(+), 19 deletions(-)
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index a94a486..a45f01c 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -332,46 +332,103 @@ void scsi_put_command(struct scsi_cmnd *cmd)
}
EXPORT_SYMBOL(scsi_put_command);
-static struct scsi_host_cmd_pool *scsi_get_host_cmd_pool(gfp_t gfp_mask)
+static struct scsi_host_cmd_pool *
+scsi_find_host_cmd_pool(struct Scsi_Host *shost)
{
+ if (shost->hostt->cmd_size)
+ return shost->hostt->cmd_pool;
+ if (shost->unchecked_isa_dma)
+ return &scsi_cmd_dma_pool;
+ return &scsi_cmd_pool;
+}
+
+static void
+scsi_free_host_cmd_pool(struct scsi_host_cmd_pool *pool)
+{
+ kfree(pool->sense_name);
+ kfree(pool->cmd_name);
+ kfree(pool);
+}
+
+static struct scsi_host_cmd_pool *
+scsi_alloc_host_cmd_pool(struct Scsi_Host *shost)
+{
+ struct scsi_host_template *hostt = shost->hostt;
+ struct scsi_host_cmd_pool *pool;
+
+ pool = kzalloc(sizeof(*pool), GFP_KERNEL);
+ if (!pool)
+ return NULL;
+
+ pool->cmd_name = kasprintf(GFP_KERNEL, "%s_cmd", hostt->name);
+ pool->sense_name = kasprintf(GFP_KERNEL, "%s_sense", hostt->name);
+ if (!pool->cmd_name || !pool->sense_name) {
+ scsi_free_host_cmd_pool(pool);
+ return NULL;
+ }
+
+ pool->slab_flags = SLAB_HWCACHE_ALIGN;
+ if (shost->unchecked_isa_dma) {
+ pool->slab_flags |= SLAB_CACHE_DMA;
+ pool->gfp_mask = __GFP_DMA;
+ }
+ return pool;
+}
+
+static struct scsi_host_cmd_pool *
+scsi_get_host_cmd_pool(struct Scsi_Host *shost)
+{
+ struct scsi_host_template *hostt = shost->hostt;
struct scsi_host_cmd_pool *retval = NULL, *pool;
+ size_t cmd_size = sizeof(struct scsi_cmnd) + hostt->cmd_size;
+
/*
* Select a command slab for this host and create it if not
* yet existent.
*/
mutex_lock(&host_cmd_pool_mutex);
- pool = (gfp_mask & __GFP_DMA) ? &scsi_cmd_dma_pool :
- &scsi_cmd_pool;
+ pool = scsi_find_host_cmd_pool(shost);
+ if (!pool) {
+ pool = scsi_alloc_host_cmd_pool(shost);
+ if (!pool)
+ goto out;
+ }
+
if (!pool->users) {
- pool->cmd_slab = kmem_cache_create(pool->cmd_name,
- sizeof(struct scsi_cmnd), 0,
+ pool->cmd_slab = kmem_cache_create(pool->cmd_name, cmd_size, 0,
pool->slab_flags, NULL);
if (!pool->cmd_slab)
- goto fail;
+ goto out_free_pool;
pool->sense_slab = kmem_cache_create(pool->sense_name,
SCSI_SENSE_BUFFERSIZE, 0,
pool->slab_flags, NULL);
- if (!pool->sense_slab) {
- kmem_cache_destroy(pool->cmd_slab);
- goto fail;
- }
+ if (!pool->sense_slab)
+ goto out_free_slab;
}
pool->users++;
retval = pool;
- fail:
+out:
mutex_unlock(&host_cmd_pool_mutex);
return retval;
+
+out_free_slab:
+ kmem_cache_destroy(pool->cmd_slab);
+out_free_pool:
+ if (hostt->cmd_size)
+ scsi_free_host_cmd_pool(pool);
+ goto out;
}
-static void scsi_put_host_cmd_pool(gfp_t gfp_mask)
+static void scsi_put_host_cmd_pool(struct Scsi_Host *shost)
{
+ struct scsi_host_template *hostt = shost->hostt;
struct scsi_host_cmd_pool *pool;
mutex_lock(&host_cmd_pool_mutex);
- pool = (gfp_mask & __GFP_DMA) ? &scsi_cmd_dma_pool :
- &scsi_cmd_pool;
+ pool = scsi_find_host_cmd_pool(shost);
+
/*
* This may happen if a driver has a mismatched get and put
* of the command pool; the driver should be implicated in
@@ -382,6 +439,8 @@ static void scsi_put_host_cmd_pool(gfp_t gfp_mask)
if (!--pool->users) {
kmem_cache_destroy(pool->cmd_slab);
kmem_cache_destroy(pool->sense_slab);
+ if (hostt->cmd_size)
+ scsi_free_host_cmd_pool(pool);
}
mutex_unlock(&host_cmd_pool_mutex);
}
@@ -398,14 +457,13 @@ static void scsi_put_host_cmd_pool(gfp_t gfp_mask)
*/
int scsi_setup_command_freelist(struct Scsi_Host *shost)
{
- struct scsi_cmnd *cmd;
const gfp_t gfp_mask = shost->unchecked_isa_dma ? GFP_DMA : GFP_KERNEL;
+ struct scsi_cmnd *cmd;
spin_lock_init(&shost->free_list_lock);
INIT_LIST_HEAD(&shost->free_list);
- shost->cmd_pool = scsi_get_host_cmd_pool(gfp_mask);
-
+ shost->cmd_pool = scsi_get_host_cmd_pool(shost);
if (!shost->cmd_pool)
return -ENOMEM;
@@ -414,7 +472,7 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost)
*/
cmd = scsi_host_alloc_command(shost, gfp_mask);
if (!cmd) {
- scsi_put_host_cmd_pool(gfp_mask);
+ scsi_put_host_cmd_pool(shost);
shost->cmd_pool = NULL;
return -ENOMEM;
}
@@ -443,7 +501,7 @@ void scsi_destroy_command_freelist(struct Scsi_Host *shost)
scsi_host_free_command(shost, cmd);
}
shost->cmd_pool = NULL;
- scsi_put_host_cmd_pool(shost->unchecked_isa_dma ? GFP_DMA : GFP_KERNEL);
+ scsi_put_host_cmd_pool(shost);
}
#ifdef CONFIG_SCSI_LOGGING
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 53075e5..94844fc 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -15,6 +15,7 @@ struct completion;
struct module;
struct scsi_cmnd;
struct scsi_device;
+struct scsi_host_cmd_pool;
struct scsi_target;
struct Scsi_Host;
struct scsi_host_cmd_pool;
@@ -524,6 +525,12 @@ struct scsi_host_template {
* scsi_netlink.h
*/
u64 vendor_id;
+
+ /*
+ * Additional per-command data allocated for the driver.
+ */
+ unsigned int cmd_size;
+ struct scsi_host_cmd_pool *cmd_pool;
};
/*
--
1.7.10.4
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [PATCH 0/9] I/O path micro-optimizations and per-command private data support
2014-02-20 22:20 [PATCH 0/9] I/O path micro-optimizations and per-command private data support Christoph Hellwig
` (8 preceding siblings ...)
2014-02-20 22:21 ` [PATCH 9/9] scsi: add support for per-host cmd pools Christoph Hellwig
@ 2014-03-12 7:27 ` Christoph Hellwig
9 siblings, 0 replies; 13+ messages in thread
From: Christoph Hellwig @ 2014-03-12 7:27 UTC (permalink / raw)
To: James Bottomley; +Cc: linux-scsi
I specificly sent this set of patches because it were those deemed
easily mergeable 4 weeks ago. Any progress on it?
On Thu, Feb 20, 2014 at 02:20:52PM -0800, Christoph Hellwig wrote:
> This is a resend of the easily acceptable subset of the previously sent
> patches. The first two patches avoid taking the host_lock needlessly for
> fast path operations, patches 3 to 5 avoid useless manipulations of the
> device reference count, and the remaining ones allow a driver specifying
> an extra command size so drivers don't have to allocate memory for driver
> specific data additionally, as well as converting virtio-scsi to use this
> feature.
>
> Changes from the first version are limited to reordering the patch series,
> fixing patch subjects and attribution and adding some boilerplate commands
> back.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
---end quoted text---
^ permalink raw reply [flat|nested] 13+ messages in thread