Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3dccdf53 authored by Ming Lei's avatar Ming Lei Committed by Martin K. Petersen
Browse files

scsi: core: avoid preallocating big SGL for data



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: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarMing Lei <ming.lei@redhat.com>
Reviewed-by: default avatarBart Van Assche <bvanassche@acm.org>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 92524fa1
Loading
Loading
Loading
Loading
+9 −6
Original line number Original line Diff line number Diff line
@@ -45,6 +45,8 @@
 */
 */
#define  SCSI_INLINE_PROT_SG_CNT  1
#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_sdb_cache;
static struct kmem_cache *scsi_sense_cache;
static struct kmem_cache *scsi_sense_cache;
static struct kmem_cache *scsi_sense_isadma_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)
static void scsi_mq_free_sgtables(struct scsi_cmnd *cmd)
{
{
	if (cmd->sdb.table.nents)
	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))
	if (scsi_prot_sg_count(cmd))
		sg_free_table_chained(&cmd->prot_sdb->table,
		sg_free_table_chained(&cmd->prot_sdb->table,
				SCSI_INLINE_PROT_SG_CNT);
				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,
	if (unlikely(sg_alloc_table_chained(&sdb->table,
			blk_rq_nr_phys_segments(req), sdb->table.sgl,
			blk_rq_nr_phys_segments(req), sdb->table.sgl,
			SG_CHUNK_SIZE)))
			SCSI_INLINE_SG_CNT)))
		return BLK_STS_RESOURCE;
		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. */
/* 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);
		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)) {
	if (scsi_host_get_prot(shost)) {
		sg = (void *)cmd + sizeof(struct scsi_cmnd) +
		sg = (void *)cmd + sizeof(struct scsi_cmnd) +
			shost->hostt->cmd_size;
			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;
	return 0;
@@ -1828,7 +1831,7 @@ int scsi_mq_setup_tags(struct Scsi_Host *shost)
{
{
	unsigned int cmd_size, sgl_size;
	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;
	cmd_size = sizeof(struct scsi_cmnd) + shost->hostt->cmd_size + sgl_size;
	if (scsi_host_get_prot(shost))
	if (scsi_host_get_prot(shost))
		cmd_size += sizeof(struct scsi_data_buffer) +
		cmd_size += sizeof(struct scsi_data_buffer) +