aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/scsi_lib.c8
-rw-r--r--include/linux/scatterlist.h5
-rw-r--r--lib/scatterlist.c41
3 files changed, 35 insertions, 19 deletions
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 3b5121c4c081..eb4911a61641 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -761,9 +761,11 @@ int scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_mask)
761 761
762 BUG_ON(!cmd->use_sg); 762 BUG_ON(!cmd->use_sg);
763 763
764 ret = __sg_alloc_table(&cmd->sg_table, cmd->use_sg, gfp_mask, scsi_sg_alloc); 764 ret = __sg_alloc_table(&cmd->sg_table, cmd->use_sg,
765 SCSI_MAX_SG_SEGMENTS, gfp_mask, scsi_sg_alloc);
765 if (unlikely(ret)) 766 if (unlikely(ret))
766 __sg_free_table(&cmd->sg_table, scsi_sg_free); 767 __sg_free_table(&cmd->sg_table, SCSI_MAX_SG_SEGMENTS,
768 scsi_sg_free);
767 769
768 cmd->request_buffer = cmd->sg_table.sgl; 770 cmd->request_buffer = cmd->sg_table.sgl;
769 return ret; 771 return ret;
@@ -773,7 +775,7 @@ EXPORT_SYMBOL(scsi_alloc_sgtable);
773 775
774void scsi_free_sgtable(struct scsi_cmnd *cmd) 776void scsi_free_sgtable(struct scsi_cmnd *cmd)
775{ 777{
776 __sg_free_table(&cmd->sg_table, scsi_sg_free); 778 __sg_free_table(&cmd->sg_table, SCSI_MAX_SG_SEGMENTS, scsi_sg_free);
777} 779}
778 780
779EXPORT_SYMBOL(scsi_free_sgtable); 781EXPORT_SYMBOL(scsi_free_sgtable);
diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h
index e9cb103417b2..a3d567a974e8 100644
--- a/include/linux/scatterlist.h
+++ b/include/linux/scatterlist.h
@@ -207,9 +207,10 @@ void sg_init_one(struct scatterlist *, const void *, unsigned int);
207typedef struct scatterlist *(sg_alloc_fn)(unsigned int, gfp_t); 207typedef struct scatterlist *(sg_alloc_fn)(unsigned int, gfp_t);
208typedef void (sg_free_fn)(struct scatterlist *, unsigned int); 208typedef void (sg_free_fn)(struct scatterlist *, unsigned int);
209 209
210void __sg_free_table(struct sg_table *, sg_free_fn *); 210void __sg_free_table(struct sg_table *, unsigned int, sg_free_fn *);
211void sg_free_table(struct sg_table *); 211void sg_free_table(struct sg_table *);
212int __sg_alloc_table(struct sg_table *, unsigned int, gfp_t, sg_alloc_fn *); 212int __sg_alloc_table(struct sg_table *, unsigned int, unsigned int, gfp_t,
213 sg_alloc_fn *);
213int sg_alloc_table(struct sg_table *, unsigned int, gfp_t); 214int sg_alloc_table(struct sg_table *, unsigned int, gfp_t);
214 215
215/* 216/*
diff --git a/lib/scatterlist.c b/lib/scatterlist.c
index 02aaa27e010e..acca4901046c 100644
--- a/lib/scatterlist.c
+++ b/lib/scatterlist.c
@@ -130,13 +130,17 @@ static void sg_kfree(struct scatterlist *sg, unsigned int nents)
130/** 130/**
131 * __sg_free_table - Free a previously mapped sg table 131 * __sg_free_table - Free a previously mapped sg table
132 * @table: The sg table header to use 132 * @table: The sg table header to use
133 * @max_ents: The maximum number of entries per single scatterlist
133 * @free_fn: Free function 134 * @free_fn: Free function
134 * 135 *
135 * Description: 136 * Description:
136 * Free an sg table previously allocated and setup with __sg_alloc_table(). 137 * Free an sg table previously allocated and setup with
138 * __sg_alloc_table(). The @max_ents value must be identical to
139 * that previously used with __sg_alloc_table().
137 * 140 *
138 **/ 141 **/
139void __sg_free_table(struct sg_table *table, sg_free_fn *free_fn) 142void __sg_free_table(struct sg_table *table, unsigned int max_ents,
143 sg_free_fn *free_fn)
140{ 144{
141 struct scatterlist *sgl, *next; 145 struct scatterlist *sgl, *next;
142 146
@@ -149,14 +153,14 @@ void __sg_free_table(struct sg_table *table, sg_free_fn *free_fn)
149 unsigned int sg_size; 153 unsigned int sg_size;
150 154
151 /* 155 /*
152 * If we have more than SG_MAX_SINGLE_ALLOC segments left, 156 * If we have more than max_ents segments left,
153 * then assign 'next' to the sg table after the current one. 157 * then assign 'next' to the sg table after the current one.
154 * sg_size is then one less than alloc size, since the last 158 * sg_size is then one less than alloc size, since the last
155 * element is the chain pointer. 159 * element is the chain pointer.
156 */ 160 */
157 if (alloc_size > SG_MAX_SINGLE_ALLOC) { 161 if (alloc_size > max_ents) {
158 next = sg_chain_ptr(&sgl[SG_MAX_SINGLE_ALLOC - 1]); 162 next = sg_chain_ptr(&sgl[max_ents - 1]);
159 alloc_size = SG_MAX_SINGLE_ALLOC; 163 alloc_size = max_ents;
160 sg_size = alloc_size - 1; 164 sg_size = alloc_size - 1;
161 } else { 165 } else {
162 sg_size = alloc_size; 166 sg_size = alloc_size;
@@ -179,7 +183,7 @@ EXPORT_SYMBOL(__sg_free_table);
179 **/ 183 **/
180void sg_free_table(struct sg_table *table) 184void sg_free_table(struct sg_table *table)
181{ 185{
182 __sg_free_table(table, sg_kfree); 186 __sg_free_table(table, SG_MAX_SINGLE_ALLOC, sg_kfree);
183} 187}
184EXPORT_SYMBOL(sg_free_table); 188EXPORT_SYMBOL(sg_free_table);
185 189
@@ -187,22 +191,30 @@ EXPORT_SYMBOL(sg_free_table);
187 * __sg_alloc_table - Allocate and initialize an sg table with given allocator 191 * __sg_alloc_table - Allocate and initialize an sg table with given allocator
188 * @table: The sg table header to use 192 * @table: The sg table header to use
189 * @nents: Number of entries in sg list 193 * @nents: Number of entries in sg list
194 * @max_ents: The maximum number of entries the allocator returns per call
190 * @gfp_mask: GFP allocation mask 195 * @gfp_mask: GFP allocation mask
191 * @alloc_fn: Allocator to use 196 * @alloc_fn: Allocator to use
192 * 197 *
198 * Description:
199 * This function returns a @table @nents long. The allocator is
200 * defined to return scatterlist chunks of maximum size @max_ents.
201 * Thus if @nents is bigger than @max_ents, the scatterlists will be
202 * chained in units of @max_ents.
203 *
193 * Notes: 204 * Notes:
194 * If this function returns non-0 (eg failure), the caller must call 205 * If this function returns non-0 (eg failure), the caller must call
195 * __sg_free_table() to cleanup any leftover allocations. 206 * __sg_free_table() to cleanup any leftover allocations.
196 * 207 *
197 **/ 208 **/
198int __sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask, 209int __sg_alloc_table(struct sg_table *table, unsigned int nents,
210 unsigned int max_ents, gfp_t gfp_mask,
199 sg_alloc_fn *alloc_fn) 211 sg_alloc_fn *alloc_fn)
200{ 212{
201 struct scatterlist *sg, *prv; 213 struct scatterlist *sg, *prv;
202 unsigned int left; 214 unsigned int left;
203 215
204#ifndef ARCH_HAS_SG_CHAIN 216#ifndef ARCH_HAS_SG_CHAIN
205 BUG_ON(nents > SG_MAX_SINGLE_ALLOC); 217 BUG_ON(nents > max_ents);
206#endif 218#endif
207 219
208 memset(table, 0, sizeof(*table)); 220 memset(table, 0, sizeof(*table));
@@ -212,8 +224,8 @@ int __sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask,
212 do { 224 do {
213 unsigned int sg_size, alloc_size = left; 225 unsigned int sg_size, alloc_size = left;
214 226
215 if (alloc_size > SG_MAX_SINGLE_ALLOC) { 227 if (alloc_size > max_ents) {
216 alloc_size = SG_MAX_SINGLE_ALLOC; 228 alloc_size = max_ents;
217 sg_size = alloc_size - 1; 229 sg_size = alloc_size - 1;
218 } else 230 } else
219 sg_size = alloc_size; 231 sg_size = alloc_size;
@@ -232,7 +244,7 @@ int __sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask,
232 * If this is not the first mapping, chain previous part. 244 * If this is not the first mapping, chain previous part.
233 */ 245 */
234 if (prv) 246 if (prv)
235 sg_chain(prv, SG_MAX_SINGLE_ALLOC, sg); 247 sg_chain(prv, max_ents, sg);
236 else 248 else
237 table->sgl = sg; 249 table->sgl = sg;
238 250
@@ -272,9 +284,10 @@ int sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask)
272{ 284{
273 int ret; 285 int ret;
274 286
275 ret = __sg_alloc_table(table, nents, gfp_mask, sg_kmalloc); 287 ret = __sg_alloc_table(table, nents, SG_MAX_SINGLE_ALLOC,
288 gfp_mask, sg_kmalloc);
276 if (unlikely(ret)) 289 if (unlikely(ret))
277 __sg_free_table(table, sg_kfree); 290 __sg_free_table(table, SG_MAX_SINGLE_ALLOC, sg_kfree);
278 291
279 return ret; 292 return ret;
280} 293}