diff options
author | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-01-13 15:15:28 -0500 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2008-01-28 04:54:49 -0500 |
commit | 7cedb1f17fb7f4374d11501f61656ae9d3ba47e9 (patch) | |
tree | d6257751445618b827c3e41e5b8fde2704c9d716 | |
parent | 5ed7959ede0936c55e50421a53f153b17080e876 (diff) |
SG: work with the SCSI fixed maximum allocations.
SCSI sg table allocation has a maximum size (of SCSI_MAX_SG_SEGMENTS,
currently 128) and this will cause a BUG_ON() in SCSI if something
tries an allocation over it. This patch adds a size limit to the
chaining allocator to allow the specification of the maximum
allocation size for chaining, so we always chain in units of the
maximum SCSI allocation size.
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
-rw-r--r-- | drivers/scsi/scsi_lib.c | 8 | ||||
-rw-r--r-- | include/linux/scatterlist.h | 5 | ||||
-rw-r--r-- | lib/scatterlist.c | 41 |
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 | ||
774 | void scsi_free_sgtable(struct scsi_cmnd *cmd) | 776 | void 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 | ||
779 | EXPORT_SYMBOL(scsi_free_sgtable); | 781 | EXPORT_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); | |||
207 | typedef struct scatterlist *(sg_alloc_fn)(unsigned int, gfp_t); | 207 | typedef struct scatterlist *(sg_alloc_fn)(unsigned int, gfp_t); |
208 | typedef void (sg_free_fn)(struct scatterlist *, unsigned int); | 208 | typedef void (sg_free_fn)(struct scatterlist *, unsigned int); |
209 | 209 | ||
210 | void __sg_free_table(struct sg_table *, sg_free_fn *); | 210 | void __sg_free_table(struct sg_table *, unsigned int, sg_free_fn *); |
211 | void sg_free_table(struct sg_table *); | 211 | void sg_free_table(struct sg_table *); |
212 | int __sg_alloc_table(struct sg_table *, unsigned int, gfp_t, sg_alloc_fn *); | 212 | int __sg_alloc_table(struct sg_table *, unsigned int, unsigned int, gfp_t, |
213 | sg_alloc_fn *); | ||
213 | int sg_alloc_table(struct sg_table *, unsigned int, gfp_t); | 214 | int 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 | **/ |
139 | void __sg_free_table(struct sg_table *table, sg_free_fn *free_fn) | 142 | void __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 | **/ |
180 | void sg_free_table(struct sg_table *table) | 184 | void 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 | } |
184 | EXPORT_SYMBOL(sg_free_table); | 188 | EXPORT_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 | **/ |
198 | int __sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask, | 209 | int __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 | } |