diff options
-rw-r--r-- | drivers/target/target_core_transport.c | 2 | ||||
-rw-r--r-- | include/linux/scatterlist.h | 1 | ||||
-rw-r--r-- | lib/scatterlist.c | 32 |
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 | ||
2301 | void target_free_sgl(struct scatterlist *sgl, int nents) | 2301 | void target_free_sgl(struct scatterlist *sgl, int nents) |
2302 | { | 2302 | { |
2303 | sgl_free(sgl); | 2303 | sgl_free_n_order(sgl, nents, 0); |
2304 | } | 2304 | } |
2305 | EXPORT_SYMBOL(target_free_sgl); | 2305 | EXPORT_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); |
283 | struct scatterlist *sgl_alloc(unsigned long long length, gfp_t gfp, | 283 | struct scatterlist *sgl_alloc(unsigned long long length, gfp_t gfp, |
284 | unsigned int *nent_p); | 284 | unsigned int *nent_p); |
285 | void sgl_free_n_order(struct scatterlist *sgl, int nents, int order); | ||
285 | void sgl_free_order(struct scatterlist *sgl, int order); | 286 | void sgl_free_order(struct scatterlist *sgl, int order); |
286 | void sgl_free(struct scatterlist *sgl); | 287 | void 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, | |||
549 | EXPORT_SYMBOL(sgl_alloc); | 549 | EXPORT_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 | */ |
556 | void sgl_free_order(struct scatterlist *sgl, int order) | 564 | void 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 | } |
579 | EXPORT_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 | */ | ||
586 | void sgl_free_order(struct scatterlist *sgl, int order) | ||
587 | { | ||
588 | sgl_free_n_order(sgl, INT_MAX, order); | ||
589 | } | ||
568 | EXPORT_SYMBOL(sgl_free_order); | 590 | EXPORT_SYMBOL(sgl_free_order); |
569 | 591 | ||
570 | /** | 592 | /** |