summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Petter Selasky <hselasky@FreeBSD.org>2018-06-01 12:09:07 +0000
committerHans Petter Selasky <hselasky@FreeBSD.org>2018-06-01 12:09:07 +0000
commit57a865f8088a544a3a25bb1a9b0072f5c42fa102 (patch)
tree440b41f9cf258001524034e8f9b8e7f46971cffe
parent6fad8d171af89087752738c9048058c991008876 (diff)
Notes
-rw-r--r--sys/compat/linuxkpi/common/include/linux/scatterlist.h35
1 files changed, 29 insertions, 6 deletions
diff --git a/sys/compat/linuxkpi/common/include/linux/scatterlist.h b/sys/compat/linuxkpi/common/include/linux/scatterlist.h
index 125b1acb7a33..5a19cd25b0b0 100644
--- a/sys/compat/linuxkpi/common/include/linux/scatterlist.h
+++ b/sys/compat/linuxkpi/common/include/linux/scatterlist.h
@@ -64,6 +64,8 @@ struct sg_page_iter {
} internal;
};
+#define SCATTERLIST_MAX_SEGMENT (-1U & ~(PAGE_SIZE - 1))
+
#define SG_MAX_SINGLE_ALLOC (PAGE_SIZE / sizeof(struct scatterlist))
#define SG_MAGIC 0x87654321UL
@@ -286,18 +288,26 @@ sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask)
}
static inline int
-sg_alloc_table_from_pages(struct sg_table *sgt,
+__sg_alloc_table_from_pages(struct sg_table *sgt,
struct page **pages, unsigned int count,
unsigned long off, unsigned long size,
- gfp_t gfp_mask)
+ unsigned int max_segment, gfp_t gfp_mask)
{
- unsigned int i, segs, cur;
+ unsigned int i, segs, cur, len;
int rc;
struct scatterlist *s;
+ if (__predict_false(!max_segment || offset_in_page(max_segment)))
+ return (-EINVAL);
+
+ len = 0;
for (segs = i = 1; i < count; ++i) {
- if (page_to_pfn(pages[i]) != page_to_pfn(pages[i - 1]) + 1)
+ len += PAGE_SIZE;
+ if (len >= max_segment ||
+ page_to_pfn(pages[i]) != page_to_pfn(pages[i - 1]) + 1) {
++segs;
+ len = 0;
+ }
}
if (__predict_false((rc = sg_alloc_table(sgt, segs, gfp_mask))))
return (rc);
@@ -307,10 +317,13 @@ sg_alloc_table_from_pages(struct sg_table *sgt,
unsigned long seg_size;
unsigned int j;
- for (j = cur + 1; j < count; ++j)
- if (page_to_pfn(pages[j]) !=
+ len = 0;
+ for (j = cur + 1; j < count; ++j) {
+ len += PAGE_SIZE;
+ if (len >= max_segment || page_to_pfn(pages[j]) !=
page_to_pfn(pages[j - 1]) + 1)
break;
+ }
seg_size = ((j - cur) << PAGE_SHIFT) - off;
sg_set_page(s, pages[cur], min(size, seg_size), off);
@@ -321,6 +334,16 @@ sg_alloc_table_from_pages(struct sg_table *sgt,
return (0);
}
+static inline int
+sg_alloc_table_from_pages(struct sg_table *sgt,
+ struct page **pages, unsigned int count,
+ unsigned long off, unsigned long size,
+ gfp_t gfp_mask)
+{
+
+ return (__sg_alloc_table_from_pages(sgt, pages, count, off, size,
+ SCATTERLIST_MAX_SEGMENT, gfp_mask));
+}
static inline int
sg_nents(struct scatterlist *sg)