summaryrefslogtreecommitdiffstats
path: root/lib/sg_pool.c
diff options
context:
space:
mode:
authorMing Lei <ming.lei@redhat.com>2019-04-28 03:39:30 -0400
committerMartin K. Petersen <martin.petersen@oracle.com>2019-06-20 15:21:33 -0400
commit4635873c561ac57b66adfcc2487c38106b1c916c (patch)
tree328c277fd811943ccf9e8b619e13397009c7f3e6 /lib/sg_pool.c
parentee5a1dbfec57cc1ffdedf2bd767c84d5e0498ed8 (diff)
scsi: lib/sg_pool.c: improve APIs for allocating sg pool
sg_alloc_table_chained() currently allows the caller to provide one preallocated SGL and returns if the requested number isn't bigger than size of that SGL. This is used to inline an SGL for an IO request. However, scattergather code only allows that size of the 1st preallocated SGL to be SG_CHUNK_SIZE(128). This means a substantial amount of memory (4KB) is claimed for the SGL for each IO request. If the I/O is small, it would be prudent to allocate a smaller SGL. Introduce an extra parameter to sg_alloc_table_chained() and sg_free_table_chained() for specifying size of the preallocated SGL. Both __sg_free_table() and __sg_alloc_table() assume that each SGL has the same size except for the last one. Change the code to allow both functions to accept a variable size for the 1st preallocated SGL. [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> Cc: Sagi Grimberg <sagi@grimberg.me> Cc: Chuck Lever <chuck.lever@oracle.com> Cc: netdev@vger.kernel.org Cc: linux-nvme@lists.infradead.org Suggested-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Ming Lei <ming.lei@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'lib/sg_pool.c')
-rw-r--r--lib/sg_pool.c37
1 files changed, 27 insertions, 10 deletions
diff --git a/lib/sg_pool.c b/lib/sg_pool.c
index d1c1e6388eaa..b3b8cf62ff49 100644
--- a/lib/sg_pool.c
+++ b/lib/sg_pool.c
@@ -69,18 +69,27 @@ static struct scatterlist *sg_pool_alloc(unsigned int nents, gfp_t gfp_mask)
69/** 69/**
70 * sg_free_table_chained - Free a previously mapped sg table 70 * sg_free_table_chained - Free a previously mapped sg table
71 * @table: The sg table header to use 71 * @table: The sg table header to use
72 * @first_chunk: was first_chunk not NULL in sg_alloc_table_chained? 72 * @nents_first_chunk: size of the first_chunk SGL passed to
73 * sg_alloc_table_chained
73 * 74 *
74 * Description: 75 * Description:
75 * Free an sg table previously allocated and setup with 76 * Free an sg table previously allocated and setup with
76 * sg_alloc_table_chained(). 77 * sg_alloc_table_chained().
77 * 78 *
79 * @nents_first_chunk has to be same with that same parameter passed
80 * to sg_alloc_table_chained().
81 *
78 **/ 82 **/
79void sg_free_table_chained(struct sg_table *table, bool first_chunk) 83void sg_free_table_chained(struct sg_table *table,
84 unsigned nents_first_chunk)
80{ 85{
81 if (first_chunk && table->orig_nents <= SG_CHUNK_SIZE) 86 if (table->orig_nents <= nents_first_chunk)
82 return; 87 return;
83 __sg_free_table(table, SG_CHUNK_SIZE, first_chunk, sg_pool_free); 88
89 if (nents_first_chunk == 1)
90 nents_first_chunk = 0;
91
92 __sg_free_table(table, SG_CHUNK_SIZE, nents_first_chunk, sg_pool_free);
84} 93}
85EXPORT_SYMBOL_GPL(sg_free_table_chained); 94EXPORT_SYMBOL_GPL(sg_free_table_chained);
86 95
@@ -89,31 +98,39 @@ EXPORT_SYMBOL_GPL(sg_free_table_chained);
89 * @table: The sg table header to use 98 * @table: The sg table header to use
90 * @nents: Number of entries in sg list 99 * @nents: Number of entries in sg list
91 * @first_chunk: first SGL 100 * @first_chunk: first SGL
101 * @nents_first_chunk: number of the SGL of @first_chunk
92 * 102 *
93 * Description: 103 * Description:
94 * Allocate and chain SGLs in an sg table. If @nents@ is larger than 104 * Allocate and chain SGLs in an sg table. If @nents@ is larger than
95 * SG_CHUNK_SIZE a chained sg table will be setup. 105 * @nents_first_chunk a chained sg table will be setup.
96 * 106 *
97 **/ 107 **/
98int sg_alloc_table_chained(struct sg_table *table, int nents, 108int sg_alloc_table_chained(struct sg_table *table, int nents,
99 struct scatterlist *first_chunk) 109 struct scatterlist *first_chunk, unsigned nents_first_chunk)
100{ 110{
101 int ret; 111 int ret;
102 112
103 BUG_ON(!nents); 113 BUG_ON(!nents);
104 114
105 if (first_chunk) { 115 if (first_chunk && nents_first_chunk) {
106 if (nents <= SG_CHUNK_SIZE) { 116 if (nents <= nents_first_chunk) {
107 table->nents = table->orig_nents = nents; 117 table->nents = table->orig_nents = nents;
108 sg_init_table(table->sgl, nents); 118 sg_init_table(table->sgl, nents);
109 return 0; 119 return 0;
110 } 120 }
111 } 121 }
112 122
123 /* User supposes that the 1st SGL includes real entry */
124 if (nents_first_chunk == 1) {
125 first_chunk = NULL;
126 nents_first_chunk = 0;
127 }
128
113 ret = __sg_alloc_table(table, nents, SG_CHUNK_SIZE, 129 ret = __sg_alloc_table(table, nents, SG_CHUNK_SIZE,
114 first_chunk, GFP_ATOMIC, sg_pool_alloc); 130 first_chunk, nents_first_chunk,
131 GFP_ATOMIC, sg_pool_alloc);
115 if (unlikely(ret)) 132 if (unlikely(ret))
116 sg_free_table_chained(table, (bool)first_chunk); 133 sg_free_table_chained(table, nents_first_chunk);
117 return ret; 134 return ret;
118} 135}
119EXPORT_SYMBOL_GPL(sg_alloc_table_chained); 136EXPORT_SYMBOL_GPL(sg_alloc_table_chained);