Commit 0db9299f48ebd4a860d6ad4e1d36ac50671d48e7
1 parent
91525300ba
Exists in
master
and in
39 other branches
SG: Move functions to lib/scatterlist.c and add sg chaining allocator helpers
Manually doing chained sg lists is not trivial, so add some helpers to make sure that drivers get it right. Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Showing 3 changed files with 307 additions and 101 deletions Side-by-side Diff
include/linux/scatterlist.h
... | ... | @@ -7,6 +7,12 @@ |
7 | 7 | #include <linux/string.h> |
8 | 8 | #include <asm/io.h> |
9 | 9 | |
10 | +struct sg_table { | |
11 | + struct scatterlist *sgl; /* the list */ | |
12 | + unsigned int nents; /* number of mapped entries */ | |
13 | + unsigned int orig_nents; /* original size of list */ | |
14 | +}; | |
15 | + | |
10 | 16 | /* |
11 | 17 | * Notes on SG table design. |
12 | 18 | * |
... | ... | @@ -106,31 +112,6 @@ |
106 | 112 | sg_set_page(sg, virt_to_page(buf), buflen, offset_in_page(buf)); |
107 | 113 | } |
108 | 114 | |
109 | -/** | |
110 | - * sg_next - return the next scatterlist entry in a list | |
111 | - * @sg: The current sg entry | |
112 | - * | |
113 | - * Description: | |
114 | - * Usually the next entry will be @sg@ + 1, but if this sg element is part | |
115 | - * of a chained scatterlist, it could jump to the start of a new | |
116 | - * scatterlist array. | |
117 | - * | |
118 | - **/ | |
119 | -static inline struct scatterlist *sg_next(struct scatterlist *sg) | |
120 | -{ | |
121 | -#ifdef CONFIG_DEBUG_SG | |
122 | - BUG_ON(sg->sg_magic != SG_MAGIC); | |
123 | -#endif | |
124 | - if (sg_is_last(sg)) | |
125 | - return NULL; | |
126 | - | |
127 | - sg++; | |
128 | - if (unlikely(sg_is_chain(sg))) | |
129 | - sg = sg_chain_ptr(sg); | |
130 | - | |
131 | - return sg; | |
132 | -} | |
133 | - | |
134 | 115 | /* |
135 | 116 | * Loop over each sg element, following the pointer to a new list if necessary |
136 | 117 | */ |
... | ... | @@ -138,40 +119,6 @@ |
138 | 119 | for (__i = 0, sg = (sglist); __i < (nr); __i++, sg = sg_next(sg)) |
139 | 120 | |
140 | 121 | /** |
141 | - * sg_last - return the last scatterlist entry in a list | |
142 | - * @sgl: First entry in the scatterlist | |
143 | - * @nents: Number of entries in the scatterlist | |
144 | - * | |
145 | - * Description: | |
146 | - * Should only be used casually, it (currently) scan the entire list | |
147 | - * to get the last entry. | |
148 | - * | |
149 | - * Note that the @sgl@ pointer passed in need not be the first one, | |
150 | - * the important bit is that @nents@ denotes the number of entries that | |
151 | - * exist from @sgl@. | |
152 | - * | |
153 | - **/ | |
154 | -static inline struct scatterlist *sg_last(struct scatterlist *sgl, | |
155 | - unsigned int nents) | |
156 | -{ | |
157 | -#ifndef ARCH_HAS_SG_CHAIN | |
158 | - struct scatterlist *ret = &sgl[nents - 1]; | |
159 | -#else | |
160 | - struct scatterlist *sg, *ret = NULL; | |
161 | - unsigned int i; | |
162 | - | |
163 | - for_each_sg(sgl, sg, nents, i) | |
164 | - ret = sg; | |
165 | - | |
166 | -#endif | |
167 | -#ifdef CONFIG_DEBUG_SG | |
168 | - BUG_ON(sgl[0].sg_magic != SG_MAGIC); | |
169 | - BUG_ON(!sg_is_last(ret)); | |
170 | -#endif | |
171 | - return ret; | |
172 | -} | |
173 | - | |
174 | -/** | |
175 | 122 | * sg_chain - Chain two sglists together |
176 | 123 | * @prv: First scatterlist |
177 | 124 | * @prv_nents: Number of entries in prv |
... | ... | @@ -223,47 +170,6 @@ |
223 | 170 | } |
224 | 171 | |
225 | 172 | /** |
226 | - * sg_init_table - Initialize SG table | |
227 | - * @sgl: The SG table | |
228 | - * @nents: Number of entries in table | |
229 | - * | |
230 | - * Notes: | |
231 | - * If this is part of a chained sg table, sg_mark_end() should be | |
232 | - * used only on the last table part. | |
233 | - * | |
234 | - **/ | |
235 | -static inline void sg_init_table(struct scatterlist *sgl, unsigned int nents) | |
236 | -{ | |
237 | - memset(sgl, 0, sizeof(*sgl) * nents); | |
238 | -#ifdef CONFIG_DEBUG_SG | |
239 | - { | |
240 | - unsigned int i; | |
241 | - for (i = 0; i < nents; i++) | |
242 | - sgl[i].sg_magic = SG_MAGIC; | |
243 | - } | |
244 | -#endif | |
245 | - sg_mark_end(&sgl[nents - 1]); | |
246 | -} | |
247 | - | |
248 | -/** | |
249 | - * sg_init_one - Initialize a single entry sg list | |
250 | - * @sg: SG entry | |
251 | - * @buf: Virtual address for IO | |
252 | - * @buflen: IO length | |
253 | - * | |
254 | - * Notes: | |
255 | - * This should not be used on a single entry that is part of a larger | |
256 | - * table. Use sg_init_table() for that. | |
257 | - * | |
258 | - **/ | |
259 | -static inline void sg_init_one(struct scatterlist *sg, const void *buf, | |
260 | - unsigned int buflen) | |
261 | -{ | |
262 | - sg_init_table(sg, 1); | |
263 | - sg_set_buf(sg, buf, buflen); | |
264 | -} | |
265 | - | |
266 | -/** | |
267 | 173 | * sg_phys - Return physical address of an sg entry |
268 | 174 | * @sg: SG entry |
269 | 175 | * |
... | ... | @@ -292,6 +198,25 @@ |
292 | 198 | { |
293 | 199 | return page_address(sg_page(sg)) + sg->offset; |
294 | 200 | } |
201 | + | |
202 | +struct scatterlist *sg_next(struct scatterlist *); | |
203 | +struct scatterlist *sg_last(struct scatterlist *s, unsigned int); | |
204 | +void sg_init_table(struct scatterlist *, unsigned int); | |
205 | +void sg_init_one(struct scatterlist *, const void *, unsigned int); | |
206 | + | |
207 | +typedef struct scatterlist *(sg_alloc_fn)(unsigned int, gfp_t); | |
208 | +typedef void (sg_free_fn)(struct scatterlist *, unsigned int); | |
209 | + | |
210 | +void __sg_free_table(struct sg_table *, sg_free_fn *); | |
211 | +void sg_free_table(struct sg_table *); | |
212 | +int __sg_alloc_table(struct sg_table *, unsigned int, gfp_t, sg_alloc_fn *); | |
213 | +int sg_alloc_table(struct sg_table *, unsigned int, gfp_t); | |
214 | + | |
215 | +/* | |
216 | + * Maximum number of entries that will be allocated in one piece, if | |
217 | + * a list larger than this is required then chaining will be utilized. | |
218 | + */ | |
219 | +#define SG_MAX_SINGLE_ALLOC (PAGE_SIZE / sizeof(struct scatterlist)) | |
295 | 220 | |
296 | 221 | #endif /* _LINUX_SCATTERLIST_H */ |
lib/Makefile
... | ... | @@ -6,7 +6,7 @@ |
6 | 6 | rbtree.o radix-tree.o dump_stack.o \ |
7 | 7 | idr.o int_sqrt.o extable.o prio_tree.o \ |
8 | 8 | sha1.o irq_regs.o reciprocal_div.o argv_split.o \ |
9 | - proportions.o prio_heap.o | |
9 | + proportions.o prio_heap.o scatterlist.o | |
10 | 10 | |
11 | 11 | lib-$(CONFIG_MMU) += ioremap.o |
12 | 12 | lib-$(CONFIG_SMP) += cpumask.o |
lib/scatterlist.c
1 | +/* | |
2 | + * Copyright (C) 2007 Jens Axboe <jens.axboe@oracle.com> | |
3 | + * | |
4 | + * Scatterlist handling helpers. | |
5 | + * | |
6 | + * This source code is licensed under the GNU General Public License, | |
7 | + * Version 2. See the file COPYING for more details. | |
8 | + */ | |
9 | +#include <linux/module.h> | |
10 | +#include <linux/scatterlist.h> | |
11 | + | |
12 | +/** | |
13 | + * sg_next - return the next scatterlist entry in a list | |
14 | + * @sg: The current sg entry | |
15 | + * | |
16 | + * Description: | |
17 | + * Usually the next entry will be @sg@ + 1, but if this sg element is part | |
18 | + * of a chained scatterlist, it could jump to the start of a new | |
19 | + * scatterlist array. | |
20 | + * | |
21 | + **/ | |
22 | +struct scatterlist *sg_next(struct scatterlist *sg) | |
23 | +{ | |
24 | +#ifdef CONFIG_DEBUG_SG | |
25 | + BUG_ON(sg->sg_magic != SG_MAGIC); | |
26 | +#endif | |
27 | + if (sg_is_last(sg)) | |
28 | + return NULL; | |
29 | + | |
30 | + sg++; | |
31 | + if (unlikely(sg_is_chain(sg))) | |
32 | + sg = sg_chain_ptr(sg); | |
33 | + | |
34 | + return sg; | |
35 | +} | |
36 | +EXPORT_SYMBOL(sg_next); | |
37 | + | |
38 | +/** | |
39 | + * sg_last - return the last scatterlist entry in a list | |
40 | + * @sgl: First entry in the scatterlist | |
41 | + * @nents: Number of entries in the scatterlist | |
42 | + * | |
43 | + * Description: | |
44 | + * Should only be used casually, it (currently) scans the entire list | |
45 | + * to get the last entry. | |
46 | + * | |
47 | + * Note that the @sgl@ pointer passed in need not be the first one, | |
48 | + * the important bit is that @nents@ denotes the number of entries that | |
49 | + * exist from @sgl@. | |
50 | + * | |
51 | + **/ | |
52 | +struct scatterlist *sg_last(struct scatterlist *sgl, unsigned int nents) | |
53 | +{ | |
54 | +#ifndef ARCH_HAS_SG_CHAIN | |
55 | + struct scatterlist *ret = &sgl[nents - 1]; | |
56 | +#else | |
57 | + struct scatterlist *sg, *ret = NULL; | |
58 | + unsigned int i; | |
59 | + | |
60 | + for_each_sg(sgl, sg, nents, i) | |
61 | + ret = sg; | |
62 | + | |
63 | +#endif | |
64 | +#ifdef CONFIG_DEBUG_SG | |
65 | + BUG_ON(sgl[0].sg_magic != SG_MAGIC); | |
66 | + BUG_ON(!sg_is_last(ret)); | |
67 | +#endif | |
68 | + return ret; | |
69 | +} | |
70 | +EXPORT_SYMBOL(sg_last); | |
71 | + | |
72 | +/** | |
73 | + * sg_init_table - Initialize SG table | |
74 | + * @sgl: The SG table | |
75 | + * @nents: Number of entries in table | |
76 | + * | |
77 | + * Notes: | |
78 | + * If this is part of a chained sg table, sg_mark_end() should be | |
79 | + * used only on the last table part. | |
80 | + * | |
81 | + **/ | |
82 | +void sg_init_table(struct scatterlist *sgl, unsigned int nents) | |
83 | +{ | |
84 | + memset(sgl, 0, sizeof(*sgl) * nents); | |
85 | +#ifdef CONFIG_DEBUG_SG | |
86 | + { | |
87 | + unsigned int i; | |
88 | + for (i = 0; i < nents; i++) | |
89 | + sgl[i].sg_magic = SG_MAGIC; | |
90 | + } | |
91 | +#endif | |
92 | + sg_mark_end(&sgl[nents - 1]); | |
93 | +} | |
94 | +EXPORT_SYMBOL(sg_init_table); | |
95 | + | |
96 | +/** | |
97 | + * sg_init_one - Initialize a single entry sg list | |
98 | + * @sg: SG entry | |
99 | + * @buf: Virtual address for IO | |
100 | + * @buflen: IO length | |
101 | + * | |
102 | + **/ | |
103 | +void sg_init_one(struct scatterlist *sg, const void *buf, unsigned int buflen) | |
104 | +{ | |
105 | + sg_init_table(sg, 1); | |
106 | + sg_set_buf(sg, buf, buflen); | |
107 | +} | |
108 | +EXPORT_SYMBOL(sg_init_one); | |
109 | + | |
110 | +/* | |
111 | + * The default behaviour of sg_alloc_table() is to use these kmalloc/kfree | |
112 | + * helpers. | |
113 | + */ | |
114 | +static struct scatterlist *sg_kmalloc(unsigned int nents, gfp_t gfp_mask) | |
115 | +{ | |
116 | + if (nents == SG_MAX_SINGLE_ALLOC) | |
117 | + return (struct scatterlist *) __get_free_page(gfp_mask); | |
118 | + else | |
119 | + return kmalloc(nents * sizeof(struct scatterlist), gfp_mask); | |
120 | +} | |
121 | + | |
122 | +static void sg_kfree(struct scatterlist *sg, unsigned int nents) | |
123 | +{ | |
124 | + if (nents == SG_MAX_SINGLE_ALLOC) | |
125 | + free_page((unsigned long) sg); | |
126 | + else | |
127 | + kfree(sg); | |
128 | +} | |
129 | + | |
130 | +/** | |
131 | + * __sg_free_table - Free a previously mapped sg table | |
132 | + * @table: The sg table header to use | |
133 | + * @free_fn: Free function | |
134 | + * | |
135 | + * Description: | |
136 | + * Free an sg table previously allocated and setup with __sg_alloc_table(). | |
137 | + * | |
138 | + **/ | |
139 | +void __sg_free_table(struct sg_table *table, sg_free_fn *free_fn) | |
140 | +{ | |
141 | + struct scatterlist *sgl, *next; | |
142 | + | |
143 | + if (unlikely(!table->sgl)) | |
144 | + return; | |
145 | + | |
146 | + sgl = table->sgl; | |
147 | + while (table->orig_nents) { | |
148 | + unsigned int alloc_size = table->orig_nents; | |
149 | + unsigned int sg_size; | |
150 | + | |
151 | + /* | |
152 | + * If we have more than SG_MAX_SINGLE_ALLOC segments left, | |
153 | + * then assign 'next' to the sg table after the current one. | |
154 | + * sg_size is then one less than alloc size, since the last | |
155 | + * element is the chain pointer. | |
156 | + */ | |
157 | + if (alloc_size > SG_MAX_SINGLE_ALLOC) { | |
158 | + next = sg_chain_ptr(&sgl[SG_MAX_SINGLE_ALLOC - 1]); | |
159 | + alloc_size = SG_MAX_SINGLE_ALLOC; | |
160 | + sg_size = alloc_size - 1; | |
161 | + } else { | |
162 | + sg_size = alloc_size; | |
163 | + next = NULL; | |
164 | + } | |
165 | + | |
166 | + table->orig_nents -= sg_size; | |
167 | + free_fn(sgl, alloc_size); | |
168 | + sgl = next; | |
169 | + } | |
170 | + | |
171 | + table->sgl = NULL; | |
172 | +} | |
173 | +EXPORT_SYMBOL(__sg_free_table); | |
174 | + | |
175 | +/** | |
176 | + * sg_free_table - Free a previously allocated sg table | |
177 | + * @table: The mapped sg table header | |
178 | + * | |
179 | + **/ | |
180 | +void sg_free_table(struct sg_table *table) | |
181 | +{ | |
182 | + __sg_free_table(table, sg_kfree); | |
183 | +} | |
184 | +EXPORT_SYMBOL(sg_free_table); | |
185 | + | |
186 | +/** | |
187 | + * __sg_alloc_table - Allocate and initialize an sg table with given allocator | |
188 | + * @table: The sg table header to use | |
189 | + * @nents: Number of entries in sg list | |
190 | + * @gfp_mask: GFP allocation mask | |
191 | + * @alloc_fn: Allocator to use | |
192 | + * | |
193 | + * Notes: | |
194 | + * If this function returns non-0 (eg failure), the caller must call | |
195 | + * __sg_free_table() to cleanup any leftover allocations. | |
196 | + * | |
197 | + **/ | |
198 | +int __sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask, | |
199 | + sg_alloc_fn *alloc_fn) | |
200 | +{ | |
201 | + struct scatterlist *sg, *prv; | |
202 | + unsigned int left; | |
203 | + | |
204 | +#ifndef ARCH_HAS_SG_CHAIN | |
205 | + BUG_ON(nents > SG_MAX_SINGLE_ALLOC); | |
206 | +#endif | |
207 | + | |
208 | + memset(table, 0, sizeof(*table)); | |
209 | + | |
210 | + left = nents; | |
211 | + prv = NULL; | |
212 | + do { | |
213 | + unsigned int sg_size, alloc_size = left; | |
214 | + | |
215 | + if (alloc_size > SG_MAX_SINGLE_ALLOC) { | |
216 | + alloc_size = SG_MAX_SINGLE_ALLOC; | |
217 | + sg_size = alloc_size - 1; | |
218 | + } else | |
219 | + sg_size = alloc_size; | |
220 | + | |
221 | + left -= sg_size; | |
222 | + | |
223 | + sg = alloc_fn(alloc_size, gfp_mask); | |
224 | + if (unlikely(!sg)) | |
225 | + return -ENOMEM; | |
226 | + | |
227 | + sg_init_table(sg, alloc_size); | |
228 | + table->nents = table->orig_nents += sg_size; | |
229 | + | |
230 | + /* | |
231 | + * If this is the first mapping, assign the sg table header. | |
232 | + * If this is not the first mapping, chain previous part. | |
233 | + */ | |
234 | + if (prv) | |
235 | + sg_chain(prv, SG_MAX_SINGLE_ALLOC, sg); | |
236 | + else | |
237 | + table->sgl = sg; | |
238 | + | |
239 | + /* | |
240 | + * If no more entries after this one, mark the end | |
241 | + */ | |
242 | + if (!left) | |
243 | + sg_mark_end(&sg[sg_size - 1]); | |
244 | + | |
245 | + /* | |
246 | + * only really needed for mempool backed sg allocations (like | |
247 | + * SCSI), a possible improvement here would be to pass the | |
248 | + * table pointer into the allocator and let that clear these | |
249 | + * flags | |
250 | + */ | |
251 | + gfp_mask &= ~__GFP_WAIT; | |
252 | + gfp_mask |= __GFP_HIGH; | |
253 | + prv = sg; | |
254 | + } while (left); | |
255 | + | |
256 | + return 0; | |
257 | +} | |
258 | +EXPORT_SYMBOL(__sg_alloc_table); | |
259 | + | |
260 | +/** | |
261 | + * sg_alloc_table - Allocate and initialize an sg table | |
262 | + * @table: The sg table header to use | |
263 | + * @nents: Number of entries in sg list | |
264 | + * @gfp_mask: GFP allocation mask | |
265 | + * | |
266 | + * Description: | |
267 | + * Allocate and initialize an sg table. If @nents@ is larger than | |
268 | + * SG_MAX_SINGLE_ALLOC a chained sg table will be setup. | |
269 | + * | |
270 | + **/ | |
271 | +int sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask) | |
272 | +{ | |
273 | + int ret; | |
274 | + | |
275 | + ret = __sg_alloc_table(table, nents, gfp_mask, sg_kmalloc); | |
276 | + if (unlikely(ret)) | |
277 | + __sg_free_table(table, sg_kfree); | |
278 | + | |
279 | + return ret; | |
280 | +} | |
281 | +EXPORT_SYMBOL(sg_alloc_table); |