@@ -365,6 +365,37 @@ int sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask)
365365}
366366EXPORT_SYMBOL (sg_alloc_table );
367367
368+ static struct scatterlist * get_next_sg (struct sg_table * table ,
369+ struct scatterlist * cur ,
370+ unsigned long needed_sges ,
371+ gfp_t gfp_mask )
372+ {
373+ struct scatterlist * new_sg , * next_sg ;
374+ unsigned int alloc_size ;
375+
376+ if (cur ) {
377+ next_sg = sg_next (cur );
378+ /* Check if last entry should be keeped for chainning */
379+ if (!sg_is_last (next_sg ) || needed_sges == 1 )
380+ return next_sg ;
381+ }
382+
383+ alloc_size = min_t (unsigned long , needed_sges , SG_MAX_SINGLE_ALLOC );
384+ new_sg = sg_kmalloc (alloc_size , gfp_mask );
385+ if (!new_sg )
386+ return ERR_PTR (- ENOMEM );
387+ sg_init_table (new_sg , alloc_size );
388+ if (cur ) {
389+ __sg_chain (next_sg , new_sg );
390+ table -> orig_nents += alloc_size - 1 ;
391+ } else {
392+ table -> sgl = new_sg ;
393+ table -> orig_nents = alloc_size ;
394+ table -> nents = 0 ;
395+ }
396+ return new_sg ;
397+ }
398+
368399/**
369400 * __sg_alloc_table_from_pages - Allocate and initialize an sg table from
370401 * an array of pages
@@ -374,29 +405,63 @@ EXPORT_SYMBOL(sg_alloc_table);
374405 * @offset: Offset from start of the first page to the start of a buffer
375406 * @size: Number of valid bytes in the buffer (after offset)
376407 * @max_segment: Maximum size of a scatterlist node in bytes (page aligned)
408+ * @prv: Last populated sge in sgt
409+ * @left_pages: Left pages caller have to set after this call
377410 * @gfp_mask: GFP allocation mask
378411 *
379- * Description:
380- * Allocate and initialize an sg table from a list of pages. Contiguous
381- * ranges of the pages are squashed into a single scatterlist node up to the
382- * maximum size specified in @max_segment. An user may provide an offset at a
383- * start and a size of valid data in a buffer specified by the page array.
384- * The returned sg table is released by sg_free_table.
412+ * Description:
413+ * If @prv is NULL, allocate and initialize an sg table from a list of pages,
414+ * else reuse the scatterlist passed in at @prv.
415+ * Contiguous ranges of the pages are squashed into a single scatterlist
416+ * entry up to the maximum size specified in @max_segment. A user may
417+ * provide an offset at a start and a size of valid data in a buffer
418+ * specified by the page array.
385419 *
386420 * Returns:
387- * 0 on success, negative error on failure
421+ * Last SGE in sgt on success, PTR_ERR on otherwise.
422+ * The allocation in @sgt must be released by sg_free_table.
423+ *
424+ * Notes:
425+ * If this function returns non-0 (eg failure), the caller must call
426+ * sg_free_table() to cleanup any leftover allocations.
388427 */
389- int __sg_alloc_table_from_pages (struct sg_table * sgt , struct page * * pages ,
390- unsigned int n_pages , unsigned int offset ,
391- unsigned long size , unsigned int max_segment ,
392- gfp_t gfp_mask )
428+ struct scatterlist * __sg_alloc_table_from_pages (struct sg_table * sgt ,
429+ struct page * * pages , unsigned int n_pages , unsigned int offset ,
430+ unsigned long size , unsigned int max_segment ,
431+ struct scatterlist * prv , unsigned int left_pages ,
432+ gfp_t gfp_mask )
393433{
394- unsigned int chunks , cur_page , seg_len , i ;
395- int ret ;
396- struct scatterlist * s ;
434+ unsigned int chunks , cur_page , seg_len , i , prv_len = 0 ;
435+ unsigned int added_nents = 0 ;
436+ struct scatterlist * s = prv ;
397437
398438 if (WARN_ON (!max_segment || offset_in_page (max_segment )))
399- return - EINVAL ;
439+ return ERR_PTR (- EINVAL );
440+
441+ if (IS_ENABLED (CONFIG_ARCH_NO_SG_CHAIN ) && prv )
442+ return ERR_PTR (- EOPNOTSUPP );
443+
444+ if (prv ) {
445+ unsigned long paddr = (page_to_pfn (sg_page (prv )) * PAGE_SIZE +
446+ prv -> offset + prv -> length ) /
447+ PAGE_SIZE ;
448+
449+ if (WARN_ON (offset ))
450+ return ERR_PTR (- EINVAL );
451+
452+ /* Merge contiguous pages into the last SG */
453+ prv_len = prv -> length ;
454+ while (n_pages && page_to_pfn (pages [0 ]) == paddr ) {
455+ if (prv -> length + PAGE_SIZE > max_segment )
456+ break ;
457+ prv -> length += PAGE_SIZE ;
458+ paddr ++ ;
459+ pages ++ ;
460+ n_pages -- ;
461+ }
462+ if (!n_pages )
463+ goto out ;
464+ }
400465
401466 /* compute number of contiguous chunks */
402467 chunks = 1 ;
@@ -410,13 +475,9 @@ int __sg_alloc_table_from_pages(struct sg_table *sgt, struct page **pages,
410475 }
411476 }
412477
413- ret = sg_alloc_table (sgt , chunks , gfp_mask );
414- if (unlikely (ret ))
415- return ret ;
416-
417478 /* merging chunks and putting them into the scatterlist */
418479 cur_page = 0 ;
419- for_each_sg ( sgt -> sgl , s , sgt -> orig_nents , i ) {
480+ for ( i = 0 ; i < chunks ; i ++ ) {
420481 unsigned int j , chunk_size ;
421482
422483 /* look for the end of the current chunk */
@@ -429,15 +490,30 @@ int __sg_alloc_table_from_pages(struct sg_table *sgt, struct page **pages,
429490 break ;
430491 }
431492
493+ /* Pass how many chunks might be left */
494+ s = get_next_sg (sgt , s , chunks - i + left_pages , gfp_mask );
495+ if (IS_ERR (s )) {
496+ /*
497+ * Adjust entry length to be as before function was
498+ * called.
499+ */
500+ if (prv )
501+ prv -> length = prv_len ;
502+ return s ;
503+ }
432504 chunk_size = ((j - cur_page ) << PAGE_SHIFT ) - offset ;
433505 sg_set_page (s , pages [cur_page ],
434506 min_t (unsigned long , size , chunk_size ), offset );
507+ added_nents ++ ;
435508 size -= chunk_size ;
436509 offset = 0 ;
437510 cur_page = j ;
438511 }
439-
440- return 0 ;
512+ sgt -> nents += added_nents ;
513+ out :
514+ if (!left_pages )
515+ sg_mark_end (s );
516+ return s ;
441517}
442518EXPORT_SYMBOL (__sg_alloc_table_from_pages );
443519
@@ -465,8 +541,9 @@ int sg_alloc_table_from_pages(struct sg_table *sgt, struct page **pages,
465541 unsigned int n_pages , unsigned int offset ,
466542 unsigned long size , gfp_t gfp_mask )
467543{
468- return __sg_alloc_table_from_pages (sgt , pages , n_pages , offset , size ,
469- SCATTERLIST_MAX_SEGMENT , gfp_mask );
544+ return PTR_ERR_OR_ZERO (__sg_alloc_table_from_pages (sgt , pages , n_pages ,
545+ offset , size , SCATTERLIST_MAX_SEGMENT ,
546+ NULL , 0 , gfp_mask ));
470547}
471548EXPORT_SYMBOL (sg_alloc_table_from_pages );
472549
0 commit comments