aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/scatterlist.c64
1 files changed, 64 insertions, 0 deletions
diff --git a/lib/scatterlist.c b/lib/scatterlist.c
index 6096e89bee55..e719adf695bf 100644
--- a/lib/scatterlist.c
+++ b/lib/scatterlist.c
@@ -319,6 +319,70 @@ int sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask)
319EXPORT_SYMBOL(sg_alloc_table); 319EXPORT_SYMBOL(sg_alloc_table);
320 320
321/** 321/**
322 * sg_alloc_table_from_pages - Allocate and initialize an sg table from
323 * an array of pages
324 * @sgt: The sg table header to use
325 * @pages: Pointer to an array of page pointers
326 * @n_pages: Number of pages in the pages array
327 * @offset: Offset from start of the first page to the start of a buffer
328 * @size: Number of valid bytes in the buffer (after offset)
329 * @gfp_mask: GFP allocation mask
330 *
331 * Description:
332 * Allocate and initialize an sg table from a list of pages. Contiguous
333 * ranges of the pages are squashed into a single scatterlist node. A user
334 * may provide an offset at a start and a size of valid data in a buffer
335 * specified by the page array. The returned sg table is released by
336 * sg_free_table.
337 *
338 * Returns:
339 * 0 on success, negative error on failure
340 */
341int sg_alloc_table_from_pages(struct sg_table *sgt,
342 struct page **pages, unsigned int n_pages,
343 unsigned long offset, unsigned long size,
344 gfp_t gfp_mask)
345{
346 unsigned int chunks;
347 unsigned int i;
348 unsigned int cur_page;
349 int ret;
350 struct scatterlist *s;
351
352 /* compute number of contiguous chunks */
353 chunks = 1;
354 for (i = 1; i < n_pages; ++i)
355 if (page_to_pfn(pages[i]) != page_to_pfn(pages[i - 1]) + 1)
356 ++chunks;
357
358 ret = sg_alloc_table(sgt, chunks, gfp_mask);
359 if (unlikely(ret))
360 return ret;
361
362 /* merging chunks and putting them into the scatterlist */
363 cur_page = 0;
364 for_each_sg(sgt->sgl, s, sgt->orig_nents, i) {
365 unsigned long chunk_size;
366 unsigned int j;
367
368 /* look for the end of the current chunk */
369 for (j = cur_page + 1; j < n_pages; ++j)
370 if (page_to_pfn(pages[j]) !=
371 page_to_pfn(pages[j - 1]) + 1)
372 break;
373
374 chunk_size = ((j - cur_page) << PAGE_SHIFT) - offset;
375 sg_set_page(s, pages[cur_page], min(size, chunk_size), offset);
376 size -= chunk_size;
377 offset = 0;
378 cur_page = j;
379 }
380
381 return 0;
382}
383EXPORT_SYMBOL(sg_alloc_table_from_pages);
384
385/**
322 * sg_miter_start - start mapping iteration over a sg list 386 * sg_miter_start - start mapping iteration over a sg list
323 * @miter: sg mapping iter to be started 387 * @miter: sg mapping iter to be started
324 * @sgl: sg list to iterate over 388 * @sgl: sg list to iterate over