summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/target/target_core_transport.c2
-rw-r--r--include/linux/scatterlist.h1
-rw-r--r--lib/scatterlist.c32
3 files changed, 29 insertions, 6 deletions
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index a001ba711cca..c03a78ee26cd 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -2300,7 +2300,7 @@ queue_full:
2300 2300
2301void target_free_sgl(struct scatterlist *sgl, int nents) 2301void target_free_sgl(struct scatterlist *sgl, int nents)
2302{ 2302{
2303 sgl_free(sgl); 2303 sgl_free_n_order(sgl, nents, 0);
2304} 2304}
2305EXPORT_SYMBOL(target_free_sgl); 2305EXPORT_SYMBOL(target_free_sgl);
2306 2306
diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h
index b8a7c1d1dbe3..22b2131bcdcd 100644
--- a/include/linux/scatterlist.h
+++ b/include/linux/scatterlist.h
@@ -282,6 +282,7 @@ struct scatterlist *sgl_alloc_order(unsigned long long length,
282 gfp_t gfp, unsigned int *nent_p); 282 gfp_t gfp, unsigned int *nent_p);
283struct scatterlist *sgl_alloc(unsigned long long length, gfp_t gfp, 283struct scatterlist *sgl_alloc(unsigned long long length, gfp_t gfp,
284 unsigned int *nent_p); 284 unsigned int *nent_p);
285void sgl_free_n_order(struct scatterlist *sgl, int nents, int order);
285void sgl_free_order(struct scatterlist *sgl, int order); 286void sgl_free_order(struct scatterlist *sgl, int order);
286void sgl_free(struct scatterlist *sgl); 287void sgl_free(struct scatterlist *sgl);
287#endif /* CONFIG_SGL_ALLOC */ 288#endif /* CONFIG_SGL_ALLOC */
diff --git a/lib/scatterlist.c b/lib/scatterlist.c
index 9afc9b432083..53728d391d3a 100644
--- a/lib/scatterlist.c
+++ b/lib/scatterlist.c
@@ -512,7 +512,7 @@ struct scatterlist *sgl_alloc_order(unsigned long long length,
512 if (!sgl) 512 if (!sgl)
513 return NULL; 513 return NULL;
514 514
515 sg_init_table(sgl, nent); 515 sg_init_table(sgl, nalloc);
516 sg = sgl; 516 sg = sgl;
517 while (length) { 517 while (length) {
518 elem_len = min_t(u64, length, PAGE_SIZE << order); 518 elem_len = min_t(u64, length, PAGE_SIZE << order);
@@ -526,7 +526,7 @@ struct scatterlist *sgl_alloc_order(unsigned long long length,
526 length -= elem_len; 526 length -= elem_len;
527 sg = sg_next(sg); 527 sg = sg_next(sg);
528 } 528 }
529 WARN_ON_ONCE(sg); 529 WARN_ONCE(length, "length = %lld\n", length);
530 if (nent_p) 530 if (nent_p)
531 *nent_p = nent; 531 *nent_p = nent;
532 return sgl; 532 return sgl;
@@ -549,22 +549,44 @@ struct scatterlist *sgl_alloc(unsigned long long length, gfp_t gfp,
549EXPORT_SYMBOL(sgl_alloc); 549EXPORT_SYMBOL(sgl_alloc);
550 550
551/** 551/**
552 * sgl_free_order - free a scatterlist and its pages 552 * sgl_free_n_order - free a scatterlist and its pages
553 * @sgl: Scatterlist with one or more elements 553 * @sgl: Scatterlist with one or more elements
554 * @nents: Maximum number of elements to free
554 * @order: Second argument for __free_pages() 555 * @order: Second argument for __free_pages()
556 *
557 * Notes:
558 * - If several scatterlists have been chained and each chain element is
559 * freed separately then it's essential to set nents correctly to avoid that a
560 * page would get freed twice.
561 * - All pages in a chained scatterlist can be freed at once by setting @nents
562 * to a high number.
555 */ 563 */
556void sgl_free_order(struct scatterlist *sgl, int order) 564void sgl_free_n_order(struct scatterlist *sgl, int nents, int order)
557{ 565{
558 struct scatterlist *sg; 566 struct scatterlist *sg;
559 struct page *page; 567 struct page *page;
568 int i;
560 569
561 for (sg = sgl; sg; sg = sg_next(sg)) { 570 for_each_sg(sgl, sg, nents, i) {
571 if (!sg)
572 break;
562 page = sg_page(sg); 573 page = sg_page(sg);
563 if (page) 574 if (page)
564 __free_pages(page, order); 575 __free_pages(page, order);
565 } 576 }
566 kfree(sgl); 577 kfree(sgl);
567} 578}
579EXPORT_SYMBOL(sgl_free_n_order);
580
581/**
582 * sgl_free_order - free a scatterlist and its pages
583 * @sgl: Scatterlist with one or more elements
584 * @order: Second argument for __free_pages()
585 */
586void sgl_free_order(struct scatterlist *sgl, int order)
587{
588 sgl_free_n_order(sgl, INT_MAX, order);
589}
568EXPORT_SYMBOL(sgl_free_order); 590EXPORT_SYMBOL(sgl_free_order);
569 591
570/** 592/**