VisionFive2 Linux kernel

StarFive Tech Linux Kernel for VisionFive (JH7110) boards (mirror)

More than 9999 Commits   32 Branches   54 Tags
author: Bart Van Assche <bart.vanassche@wdc.com> 2018-01-19 11:00:54 -0800 committer: Jens Axboe <axboe@kernel.dk> 2018-01-19 12:31:03 -0700 commit: 8c7a8d1c4b9c30a2be3b31a2e6af1cefd45574eb parent: 9b9c63f71bddf3dc897aaaa46c0593abc3e09932
Commit Summary:
lib/scatterlist: Fix chaining support in sgl_alloc_order()
Diffstat:
1 file changed, 26 insertions, 5 deletions
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,
 	if (!sgl)
 		return NULL;
 
-	sg_init_table(sgl, nent);
+	sg_init_table(sgl, nalloc);
 	sg = sgl;
 	while (length) {
 		elem_len = min_t(u64, length, PAGE_SIZE << order);
@@ -526,7 +526,7 @@ struct scatterlist *sgl_alloc_order(unsigned long long length,
 		length -= elem_len;
 		sg = sg_next(sg);
 	}
-	WARN_ON_ONCE(sg);
+	WARN_ONCE(length, "length = %lld\n", length);
 	if (nent_p)
 		*nent_p = nent;
 	return sgl;
@@ -549,22 +549,44 @@ struct scatterlist *sgl_alloc(unsigned long long length, gfp_t gfp,
 EXPORT_SYMBOL(sgl_alloc);
 
 /**
- * sgl_free_order - free a scatterlist and its pages
+ * sgl_free_n_order - free a scatterlist and its pages
  * @sgl: Scatterlist with one or more elements
+ * @nents: Maximum number of elements to free
  * @order: Second argument for __free_pages()
+ *
+ * Notes:
+ * - If several scatterlists have been chained and each chain element is
+ *   freed separately then it's essential to set nents correctly to avoid that a
+ *   page would get freed twice.
+ * - All pages in a chained scatterlist can be freed at once by setting @nents
+ *   to a high number.
  */
-void sgl_free_order(struct scatterlist *sgl, int order)
+void sgl_free_n_order(struct scatterlist *sgl, int nents, int order)
 {
 	struct scatterlist *sg;
 	struct page *page;
+	int i;
 
-	for (sg = sgl; sg; sg = sg_next(sg)) {
+	for_each_sg(sgl, sg, nents, i) {
+		if (!sg)
+			break;
 		page = sg_page(sg);
 		if (page)
 			__free_pages(page, order);
 	}
 	kfree(sgl);
 }
+EXPORT_SYMBOL(sgl_free_n_order);
+
+/**
+ * sgl_free_order - free a scatterlist and its pages
+ * @sgl: Scatterlist with one or more elements
+ * @order: Second argument for __free_pages()
+ */
+void sgl_free_order(struct scatterlist *sgl, int order)
+{
+	sgl_free_n_order(sgl, INT_MAX, order);
+}
 EXPORT_SYMBOL(sgl_free_order);
 
 /**