scsi: core: avoid preallocating big SGL for data
authorMing Lei <ming.lei@redhat.com>
Sun, 28 Apr 2019 07:39:32 +0000 (15:39 +0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Thu, 20 Jun 2019 19:21:33 +0000 (15:21 -0400)
scsi_mq_setup_tags() preallocates a big buffer for the IO SGL. The size is
based on scsi_mq_sgl_size() which is determined based on
shost->sg_tablesize and SG_CHUNK_SIZE.

Modern DMA engines are often capable of dealing with very big segments so
the resulting scsi_mq_sgl_size() is often too big. SG_CHUNK_SIZE results in
a static 4KB SGL allocation per command.

If an HBA has lots of deep queues, preallocation for the sg list can
consume substantial amounts of memory. For lpfc, nr_hw_queues can be 70
and each queue's depth 3781. This means the resulting preallocation for
the data SGL is 70*3781*2K = 517MB.

Switch to runtime allocation for SGL for lists longer than 2 entries. This
is the approach used by NVMe PCI so it should be reasonable for SCSI as
well. Runtime SGL allocation has always been the case for the legacy I/O
path so this is nothing new.

[mkp: attempted to clarify commit desc]

Cc: Christoph Hellwig <hch@lst.de>
Cc: Bart Van Assche <bvanassche@acm.org>
Cc: Ewan D. Milne <emilne@redhat.com>
Cc: Hannes Reinecke <hare@suse.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Ming Lei <ming.lei@redhat.com>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/scsi_lib.c

index c115458..45b43e9 100644 (file)
@@ -45,6 +45,8 @@
  */
 #define  SCSI_INLINE_PROT_SG_CNT  1
 
+#define  SCSI_INLINE_SG_CNT  2
+
 static struct kmem_cache *scsi_sdb_cache;
 static struct kmem_cache *scsi_sense_cache;
 static struct kmem_cache *scsi_sense_isadma_cache;
@@ -547,7 +549,8 @@ static void scsi_uninit_cmd(struct scsi_cmnd *cmd)
 static void scsi_mq_free_sgtables(struct scsi_cmnd *cmd)
 {
        if (cmd->sdb.table.nents)
-               sg_free_table_chained(&cmd->sdb.table, SG_CHUNK_SIZE);
+               sg_free_table_chained(&cmd->sdb.table,
+                               SCSI_INLINE_SG_CNT);
        if (scsi_prot_sg_count(cmd))
                sg_free_table_chained(&cmd->prot_sdb->table,
                                SCSI_INLINE_PROT_SG_CNT);
@@ -984,7 +987,7 @@ static blk_status_t scsi_init_sgtable(struct request *req,
         */
        if (unlikely(sg_alloc_table_chained(&sdb->table,
                        blk_rq_nr_phys_segments(req), sdb->table.sgl,
-                       SG_CHUNK_SIZE)))
+                       SCSI_INLINE_SG_CNT)))
                return BLK_STS_RESOURCE;
 
        /* 
@@ -1550,9 +1553,9 @@ static int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
 }
 
 /* Size in bytes of the sg-list stored in the scsi-mq command-private data. */
-static unsigned int scsi_mq_sgl_size(struct Scsi_Host *shost)
+static unsigned int scsi_mq_inline_sgl_size(struct Scsi_Host *shost)
 {
-       return min_t(unsigned int, shost->sg_tablesize, SG_CHUNK_SIZE) *
+       return min_t(unsigned int, shost->sg_tablesize, SCSI_INLINE_SG_CNT) *
                sizeof(struct scatterlist);
 }
 
@@ -1734,7 +1737,7 @@ static int scsi_mq_init_request(struct blk_mq_tag_set *set, struct request *rq,
        if (scsi_host_get_prot(shost)) {
                sg = (void *)cmd + sizeof(struct scsi_cmnd) +
                        shost->hostt->cmd_size;
-               cmd->prot_sdb = (void *)sg + scsi_mq_sgl_size(shost);
+               cmd->prot_sdb = (void *)sg + scsi_mq_inline_sgl_size(shost);
        }
 
        return 0;
@@ -1828,7 +1831,7 @@ int scsi_mq_setup_tags(struct Scsi_Host *shost)
 {
        unsigned int cmd_size, sgl_size;
 
-       sgl_size = scsi_mq_sgl_size(shost);
+       sgl_size = scsi_mq_inline_sgl_size(shost);
        cmd_size = sizeof(struct scsi_cmnd) + shost->hostt->cmd_size + sgl_size;
        if (scsi_host_get_prot(shost))
                cmd_size += sizeof(struct scsi_data_buffer) +