diff options
-rw-r--r-- | include/linux/scatterlist.h | 35 | ||||
-rw-r--r-- | lib/scatterlist.c | 38 |
2 files changed, 73 insertions, 0 deletions
diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h index 4bd6c06eb28e..788a853aa7a7 100644 --- a/include/linux/scatterlist.h +++ b/include/linux/scatterlist.h | |||
@@ -231,6 +231,41 @@ size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents, | |||
231 | */ | 231 | */ |
232 | #define SG_MAX_SINGLE_ALLOC (PAGE_SIZE / sizeof(struct scatterlist)) | 232 | #define SG_MAX_SINGLE_ALLOC (PAGE_SIZE / sizeof(struct scatterlist)) |
233 | 233 | ||
234 | /* | ||
235 | * sg page iterator | ||
236 | * | ||
237 | * Iterates over sg entries page-by-page. On each successful iteration, | ||
238 | * @piter->page points to the current page, @piter->sg to the sg holding this | ||
239 | * page and @piter->sg_pgoffset to the page's page offset within the sg. The | ||
240 | * iteration will stop either when a maximum number of sg entries was reached | ||
241 | * or a terminating sg (sg_last(sg) == true) was reached. | ||
242 | */ | ||
243 | struct sg_page_iter { | ||
244 | struct page *page; /* current page */ | ||
245 | struct scatterlist *sg; /* sg holding the page */ | ||
246 | unsigned int sg_pgoffset; /* page offset within the sg */ | ||
247 | |||
248 | /* these are internal states, keep away */ | ||
249 | unsigned int __nents; /* remaining sg entries */ | ||
250 | int __pg_advance; /* nr pages to advance at the | ||
251 | * next step */ | ||
252 | }; | ||
253 | |||
254 | bool __sg_page_iter_next(struct sg_page_iter *piter); | ||
255 | void __sg_page_iter_start(struct sg_page_iter *piter, | ||
256 | struct scatterlist *sglist, unsigned int nents, | ||
257 | unsigned long pgoffset); | ||
258 | |||
259 | /** | ||
260 | * for_each_sg_page - iterate over the pages of the given sg list | ||
261 | * @sglist: sglist to iterate over | ||
262 | * @piter: page iterator to hold current page, sg, sg_pgoffset | ||
263 | * @nents: maximum number of sg entries to iterate over | ||
264 | * @pgoffset: starting page offset | ||
265 | */ | ||
266 | #define for_each_sg_page(sglist, piter, nents, pgoffset) \ | ||
267 | for (__sg_page_iter_start((piter), (sglist), (nents), (pgoffset)); \ | ||
268 | __sg_page_iter_next(piter);) | ||
234 | 269 | ||
235 | /* | 270 | /* |
236 | * Mapping sg iterator | 271 | * Mapping sg iterator |
diff --git a/lib/scatterlist.c b/lib/scatterlist.c index 7874b01e816e..a1d15647d7db 100644 --- a/lib/scatterlist.c +++ b/lib/scatterlist.c | |||
@@ -394,6 +394,44 @@ int sg_alloc_table_from_pages(struct sg_table *sgt, | |||
394 | } | 394 | } |
395 | EXPORT_SYMBOL(sg_alloc_table_from_pages); | 395 | EXPORT_SYMBOL(sg_alloc_table_from_pages); |
396 | 396 | ||
397 | void __sg_page_iter_start(struct sg_page_iter *piter, | ||
398 | struct scatterlist *sglist, unsigned int nents, | ||
399 | unsigned long pgoffset) | ||
400 | { | ||
401 | piter->__pg_advance = 0; | ||
402 | piter->__nents = nents; | ||
403 | |||
404 | piter->page = NULL; | ||
405 | piter->sg = sglist; | ||
406 | piter->sg_pgoffset = pgoffset; | ||
407 | } | ||
408 | EXPORT_SYMBOL(__sg_page_iter_start); | ||
409 | |||
410 | static int sg_page_count(struct scatterlist *sg) | ||
411 | { | ||
412 | return PAGE_ALIGN(sg->offset + sg->length) >> PAGE_SHIFT; | ||
413 | } | ||
414 | |||
415 | bool __sg_page_iter_next(struct sg_page_iter *piter) | ||
416 | { | ||
417 | if (!piter->__nents || !piter->sg) | ||
418 | return false; | ||
419 | |||
420 | piter->sg_pgoffset += piter->__pg_advance; | ||
421 | piter->__pg_advance = 1; | ||
422 | |||
423 | while (piter->sg_pgoffset >= sg_page_count(piter->sg)) { | ||
424 | piter->sg_pgoffset -= sg_page_count(piter->sg); | ||
425 | piter->sg = sg_next(piter->sg); | ||
426 | if (!--piter->__nents || !piter->sg) | ||
427 | return false; | ||
428 | } | ||
429 | piter->page = nth_page(sg_page(piter->sg), piter->sg_pgoffset); | ||
430 | |||
431 | return true; | ||
432 | } | ||
433 | EXPORT_SYMBOL(__sg_page_iter_next); | ||
434 | |||
397 | /** | 435 | /** |
398 | * sg_miter_start - start mapping iteration over a sg list | 436 | * sg_miter_start - start mapping iteration over a sg list |
399 | * @miter: sg mapping iter to be started | 437 | * @miter: sg mapping iter to be started |