Implement the __sg_alloc_table_from_pages() function based on the existing

sg_alloc_table_from_pages() function in the LinuxKPI.

This basically allow segments to have a limit, max_segment.

Submitted by:	Johannes Lundberg <johalun0@gmail.com>
MFC after:	1 week
Sponsored by:	Mellanox Technologies
Sponsored by:	Limelight Networks
This commit is contained in:
Hans Petter Selasky 2018-06-01 12:09:07 +00:00
parent 6fad8d171a
commit 57a865f808

View File

@ -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)