|
@@ -394,17 +394,22 @@ int sg_alloc_table_from_pages(struct sg_table *sgt,
|
|
|
unsigned int offset, unsigned long size,
|
|
|
gfp_t gfp_mask)
|
|
|
{
|
|
|
- unsigned int chunks;
|
|
|
- unsigned int i;
|
|
|
- unsigned int cur_page;
|
|
|
+ const unsigned int max_segment = SCATTERLIST_MAX_SEGMENT;
|
|
|
+ unsigned int chunks, cur_page, seg_len, i;
|
|
|
int ret;
|
|
|
struct scatterlist *s;
|
|
|
|
|
|
/* compute number of contiguous chunks */
|
|
|
chunks = 1;
|
|
|
- for (i = 1; i < n_pages; ++i)
|
|
|
- if (page_to_pfn(pages[i]) != page_to_pfn(pages[i - 1]) + 1)
|
|
|
- ++chunks;
|
|
|
+ seg_len = 0;
|
|
|
+ for (i = 1; i < n_pages; i++) {
|
|
|
+ seg_len += PAGE_SIZE;
|
|
|
+ if (seg_len >= max_segment ||
|
|
|
+ page_to_pfn(pages[i]) != page_to_pfn(pages[i - 1]) + 1) {
|
|
|
+ chunks++;
|
|
|
+ seg_len = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
ret = sg_alloc_table(sgt, chunks, gfp_mask);
|
|
|
if (unlikely(ret))
|
|
@@ -413,17 +418,21 @@ int sg_alloc_table_from_pages(struct sg_table *sgt,
|
|
|
/* merging chunks and putting them into the scatterlist */
|
|
|
cur_page = 0;
|
|
|
for_each_sg(sgt->sgl, s, sgt->orig_nents, i) {
|
|
|
- unsigned long chunk_size;
|
|
|
- unsigned int j;
|
|
|
+ unsigned int j, chunk_size;
|
|
|
|
|
|
/* look for the end of the current chunk */
|
|
|
- for (j = cur_page + 1; j < n_pages; ++j)
|
|
|
- if (page_to_pfn(pages[j]) !=
|
|
|
+ seg_len = 0;
|
|
|
+ for (j = cur_page + 1; j < n_pages; j++) {
|
|
|
+ seg_len += PAGE_SIZE;
|
|
|
+ if (seg_len >= max_segment ||
|
|
|
+ page_to_pfn(pages[j]) !=
|
|
|
page_to_pfn(pages[j - 1]) + 1)
|
|
|
break;
|
|
|
+ }
|
|
|
|
|
|
chunk_size = ((j - cur_page) << PAGE_SHIFT) - offset;
|
|
|
- sg_set_page(s, pages[cur_page], min(size, chunk_size), offset);
|
|
|
+ sg_set_page(s, pages[cur_page],
|
|
|
+ min_t(unsigned long, size, chunk_size), offset);
|
|
|
size -= chunk_size;
|
|
|
offset = 0;
|
|
|
cur_page = j;
|