[PATCH v3] scatterlist: add sg_alloc_table_from_pages function

Andrew Morton akpm at linux-foundation.org
Thu May 17 16:56:14 PDT 2012


On Tue, 08 May 2012 11:50:33 +0200
Tomasz Stanislawski <t.stanislaws at samsung.com> wrote:

> This patch adds a new constructor for an sg table. The table is constructed
> from an array of struct pages. All contiguous chunks of the pages are merged
> into a single sg nodes. A user may provide an offset and a size of a buffer if
> the buffer is not page-aligned.
> 
> The function is dedicated for DMABUF exporters which often perform conversion
> from an page array to a scatterlist. Moreover the scatterlist should be
> squashed in order to save memory and to speed-up the process of DMA mapping
> using dma_map_sg.
> 
> The code is based on the patch 'v4l: vb2-dma-contig: add support for
> scatterlist in userptr mode' and hints from Laurent Pinchart.
> 
> ...
>
>  /**
> + * sg_alloc_table_from_pages - Allocate and initialize an sg table from
> + *			       an array of pages
> + * @sgt:	The sg table header to use
> + * @pages:	Pointer to an array of page pointers
> + * @n_pages:	Number of pages in the pages array
> + * @offset:     Offset from start of the first page to the start of a buffer
> + * @size:       Number of valid bytes in the buffer (after offset)
> + * @gfp_mask:	GFP allocation mask
> + *
> + *  Description:
> + *    Allocate and initialize an sg table from a list of pages. Continuous

s/Continuous/Contiguous/

> + *    ranges of the pages are squashed into a single scatterlist node. A user
> + *    may provide an offset at a start and a size of valid data in a buffer
> + *    specified by the page array. The returned sg table is released by
> + *    sg_free_table.
> + *
> + * Returns:
> + *   0 on success, negative error on failure
> + **/

nit: Use */, not **/ here.

> +int sg_alloc_table_from_pages(struct sg_table *sgt,
> +	struct page **pages, unsigned int n_pages,
> +	unsigned long offset, unsigned long size,
> +	gfp_t gfp_mask)

I guess a 32-bit n_pages is OK.  A 16TB IO seems enough ;)

> +{
> +	unsigned int chunks;
> +	unsigned int i;

erk, please choose a different name for this.  When a C programmer sees
"i", he very much assumes it has type "int".  Making it unsigned causes
surprise.

And don't rename it to "u"!  Let's give it a nice meaningful name.  pageno?

> +	unsigned int cur_page;
> +	int ret;
> +	struct scatterlist *s;
> +
> +	/* compute number of contiguous chunks */
> +	chunks = 1;
> +	for (i = 1; i < n_pages; ++i)
> +		if (page_to_pfn(pages[i]) != page_to_pfn(pages[i - 1]) + 1)

This assumes that if two pages have contiguous pfn's then they are
physically contiguous.  Is that true for all architectures and memory
models, including sparsemem?  See sparse_encode_mem_map().

> +			++chunks;
> +
> +	ret = sg_alloc_table(sgt, chunks, gfp_mask);
> +	if (unlikely(ret))
> +		return ret;
> +
> +	/* merging chunks and putting them into the scatterlist */
> +	cur_page = 0;
> +	for_each_sg(sgt->sgl, s, sgt->orig_nents, i) {
> +		unsigned long chunk_size;
> +		unsigned int j;

"j" is an "int", too.

> +
> +		/* looking for the end of the current chunk */

s/looking/look/

> +		for (j = cur_page + 1; j < n_pages; ++j)
> +			if (page_to_pfn(pages[j]) !=
> +			    page_to_pfn(pages[j - 1]) + 1)
> +				break;
> +
> +		chunk_size = ((j - cur_page) << PAGE_SHIFT) - offset;
> +		sg_set_page(s, pages[cur_page], min(size, chunk_size), offset);
> +		size -= chunk_size;
> +		offset = 0;
> +		cur_page = j;
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(sg_alloc_table_from_pages);



More information about the dri-devel mailing list