[PATCH 2/2] use dynamically allocated sense buffer

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This removes static array sense_buffer in scsi_cmnd and uses
dynamically allocated sense_buffer (with GFP_DMA).

scsi_add_host allocates as many buffers as
scsi_host->can_queue. __scsi_get_command attaches sense_buffer to a
scsi_cmnd and __scsi_put_command detaches the sense_buffer from it.

There is a small possibility that a host need more sense buffers than
can_queue. The failure of the buffer allocation works just like the
failure of scsi_cmnd allocation. So everything should work as before.

Signed-off-by: FUJITA Tomonori <fujita.tomonori@xxxxxxxxxxxxx>
---
 drivers/scsi/hosts.c     |   10 ++++++-
 drivers/scsi/scsi.c      |   67 +++++++++++++++++++++++++++++++++++++++++++++-
 drivers/scsi/scsi_priv.h |    2 +
 include/scsi/scsi_cmnd.h |    2 +-
 include/scsi/scsi_host.h |    3 ++
 5 files changed, 81 insertions(+), 3 deletions(-)

diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 9a10b43..35c5f0e 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -205,10 +205,14 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev)
 	if (!shost->shost_gendev.parent)
 		shost->shost_gendev.parent = dev ? dev : &platform_bus;
 
-	error = device_add(&shost->shost_gendev);
+	error = scsi_setup_command_sense_buffer(shost);
 	if (error)
 		goto out;
 
+	error = device_add(&shost->shost_gendev);
+	if (error)
+		goto destroy_pool;
+
 	scsi_host_set_state(shost, SHOST_RUNNING);
 	get_device(shost->shost_gendev.parent);
 
@@ -248,6 +252,8 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev)
 	class_device_del(&shost->shost_classdev);
  out_del_gendev:
 	device_del(&shost->shost_gendev);
+ destroy_pool:
+	scsi_destroy_command_sense_buffer(shost);
  out:
 	return error;
 }
@@ -267,6 +273,8 @@ static void scsi_host_dev_release(struct device *dev)
 		scsi_free_queue(shost->uspace_req_q);
 	}
 
+	scsi_destroy_command_sense_buffer(shost);
+
 	scsi_destroy_command_freelist(shost);
 	if (shost->bqt)
 		blk_free_tags(shost->bqt);
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index ebc0193..91306a5 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -161,6 +161,9 @@ static struct scsi_host_cmd_pool scsi_cmd_dma_pool = {
 
 static DEFINE_MUTEX(host_cmd_pool_mutex);
 
+static struct kmem_cache *sense_buffer_slab;
+static int sense_buffer_slab_users;
+
 /**
  * __scsi_get_command - Allocate a struct scsi_cmnd
  * @shost: host to transmit command
@@ -172,6 +175,11 @@ static DEFINE_MUTEX(host_cmd_pool_mutex);
 struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask)
 {
 	struct scsi_cmnd *cmd;
+	unsigned char *buf;
+
+	buf = mempool_alloc(shost->sense_buffer_pool, __GFP_DMA|gfp_mask);
+	if (!buf)
+		return NULL;
 
 	cmd = kmem_cache_alloc(shost->cmd_pool->slab,
 			gfp_mask | shost->cmd_pool->gfp_mask);
@@ -188,6 +196,14 @@ struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask)
 		spin_unlock_irqrestore(&shost->free_list_lock, flags);
 	}
 
+	if (cmd) {
+		memset(cmd, 0, sizeof(*cmd));
+		cmd->sense_buffer = buf;
+		/* probably unnecessary */
+		memset(buf, 0, SCSI_SENSE_BUFFERSIZE);
+	} else
+		mempool_free(buf, shost->sense_buffer_pool);
+
 	return cmd;
 }
 EXPORT_SYMBOL_GPL(__scsi_get_command);
@@ -212,7 +228,6 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask)
 	if (likely(cmd != NULL)) {
 		unsigned long flags;
 
-		memset(cmd, 0, sizeof(*cmd));
 		cmd->device = dev;
 		init_timer(&cmd->eh_timeout);
 		INIT_LIST_HEAD(&cmd->list);
@@ -238,6 +253,8 @@ void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd,
 {
 	unsigned long flags;
 
+	mempool_free(cmd->sense_buffer, shost->sense_buffer_pool);
+
 	/* 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))) {
@@ -352,6 +369,54 @@ void scsi_destroy_command_freelist(struct Scsi_Host *shost)
 	mutex_unlock(&host_cmd_pool_mutex);
 }
 
+int scsi_setup_command_sense_buffer(struct Scsi_Host *shost)
+{
+	int ret;
+
+	mutex_lock(&host_cmd_pool_mutex);
+	if (!sense_buffer_slab) {
+		sense_buffer_slab = kmem_cache_create("scsi_sense_buffer",
+						      SCSI_SENSE_BUFFERSIZE,
+						      0, SLAB_CACHE_DMA, NULL);
+		if (!sense_buffer_slab) {
+			mutex_unlock(&host_cmd_pool_mutex);
+			return -ENOMEM;
+		}
+	}
+	sense_buffer_slab_users++;
+	mutex_unlock(&host_cmd_pool_mutex);
+
+	shost->sense_buffer_pool =
+		mempool_create_slab_pool(0, sense_buffer_slab);
+	if (!shost->sense_buffer_pool)
+		goto fail;
+
+	ret = mempool_resize(shost->sense_buffer_pool, shost->can_queue,
+			     __GFP_DMA|GFP_KERNEL);
+	if (ret) {
+		mempool_destroy(shost->sense_buffer_pool);
+		goto fail;
+	}
+
+	return 0;
+fail:
+	mutex_lock(&host_cmd_pool_mutex);
+	if (!--sense_buffer_slab_users)
+			kmem_cache_destroy(sense_buffer_slab);
+	mutex_unlock(&host_cmd_pool_mutex);
+	return -ENOMEM;
+}
+
+void scsi_destroy_command_sense_buffer(struct Scsi_Host *shost)
+{
+	mempool_destroy(shost->sense_buffer_pool);
+
+	mutex_lock(&host_cmd_pool_mutex);
+	if (!--sense_buffer_slab_users)
+		kmem_cache_destroy(sense_buffer_slab);
+	mutex_unlock(&host_cmd_pool_mutex);
+}
+
 #ifdef CONFIG_SCSI_LOGGING
 void scsi_log_send(struct scsi_cmnd *cmd)
 {
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index eff0059..88b20f0 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -27,6 +27,8 @@ extern void scsi_exit_hosts(void);
 extern int scsi_dispatch_cmd(struct scsi_cmnd *cmd);
 extern int scsi_setup_command_freelist(struct Scsi_Host *shost);
 extern void scsi_destroy_command_freelist(struct Scsi_Host *shost);
+extern int scsi_setup_command_sense_buffer(struct Scsi_Host *shost);
+extern void scsi_destroy_command_sense_buffer(struct Scsi_Host *shost);
 extern void __scsi_done(struct scsi_cmnd *cmd);
 #ifdef CONFIG_SCSI_LOGGING
 void scsi_log_send(struct scsi_cmnd *cmd);
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index a7be605..753da55 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -88,7 +88,7 @@ struct scsi_cmnd {
 				   	   working on */
 
 #define SCSI_SENSE_BUFFERSIZE 	96
-	unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE];
+	unsigned char *sense_buffer;
 				/* obtained by REQUEST SENSE when
 				 * CHECK CONDITION is received on original
 				 * command (auto-sense) */
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 0fd4746..3f4bae3 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -6,6 +6,7 @@
 #include <linux/types.h>
 #include <linux/workqueue.h>
 #include <linux/mutex.h>
+#include <linux/mempool.h>
 
 struct request_queue;
 struct block_device;
@@ -520,6 +521,8 @@ struct Scsi_Host {
 	struct list_head	free_list; /* backup store of cmd structs */
 	struct list_head	starved_list;
 
+	mempool_t *sense_buffer_pool;
+
 	spinlock_t		default_lock;
 	spinlock_t		*host_lock;
 
-- 
1.5.3.4

-
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux