Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 89673
b: refs/heads/master
c: b1adaf6
h: refs/heads/master
i:
  89671: 3bb4e67
v: v3
  • Loading branch information
FUJITA Tomonori authored and James Bottomley committed Apr 7, 2008
1 parent 2b755ff commit 0deebc2
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 78b4b05db57b04b3ed17dc71259bf1402c04abfa
refs/heads/master: b1adaf65ba0398c9a1adc8f3a274533165a4df61
5 changes: 5 additions & 0 deletions trunk/include/linux/scatterlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,11 @@ int __sg_alloc_table(struct sg_table *, unsigned int, unsigned int, gfp_t,
sg_alloc_fn *);
int sg_alloc_table(struct sg_table *, unsigned int, gfp_t);

size_t sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents,
void *buf, size_t buflen);
size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
void *buf, size_t buflen);

/*
* Maximum number of entries that will be allocated in one piece, if
* a list larger than this is required then chaining will be utilized.
Expand Down
102 changes: 102 additions & 0 deletions trunk/lib/scatterlist.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/
#include <linux/module.h>
#include <linux/scatterlist.h>
#include <linux/highmem.h>

/**
* sg_next - return the next scatterlist entry in a list
Expand Down Expand Up @@ -292,3 +293,104 @@ int sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask)
return ret;
}
EXPORT_SYMBOL(sg_alloc_table);

/**
* sg_copy_buffer - Copy data between a linear buffer and an SG list
* @sgl: The SG list
* @nents: Number of SG entries
* @buf: Where to copy from
* @buflen: The number of bytes to copy
* @to_buffer: transfer direction (non zero == from an sg list to a
* buffer, 0 == from a buffer to an sg list
*
* Returns the number of copied bytes.
*
**/
static size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents,
void *buf, size_t buflen, int to_buffer)
{
struct scatterlist *sg;
size_t buf_off = 0;
int i;

WARN_ON(!irqs_disabled());

for_each_sg(sgl, sg, nents, i) {
struct page *page;
int n = 0;
unsigned int sg_off = sg->offset;
unsigned int sg_copy = sg->length;

if (sg_copy > buflen)
sg_copy = buflen;
buflen -= sg_copy;

while (sg_copy > 0) {
unsigned int page_copy;
void *p;

page_copy = PAGE_SIZE - sg_off;
if (page_copy > sg_copy)
page_copy = sg_copy;

page = nth_page(sg_page(sg), n);
p = kmap_atomic(page, KM_BIO_SRC_IRQ);

if (to_buffer)
memcpy(buf + buf_off, p + sg_off, page_copy);
else {
memcpy(p + sg_off, buf + buf_off, page_copy);
flush_kernel_dcache_page(page);
}

kunmap_atomic(p, KM_BIO_SRC_IRQ);

buf_off += page_copy;
sg_off += page_copy;
if (sg_off == PAGE_SIZE) {
sg_off = 0;
n++;
}
sg_copy -= page_copy;
}

if (!buflen)
break;
}

return buf_off;
}

/**
* sg_copy_from_buffer - Copy from a linear buffer to an SG list
* @sgl: The SG list
* @nents: Number of SG entries
* @buf: Where to copy from
* @buflen: The number of bytes to copy
*
* Returns the number of copied bytes.
*
**/
size_t sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents,
void *buf, size_t buflen)
{
return sg_copy_buffer(sgl, nents, buf, buflen, 0);
}
EXPORT_SYMBOL(sg_copy_from_buffer);

/**
* sg_copy_to_buffer - Copy from an SG list to a linear buffer
* @sgl: The SG list
* @nents: Number of SG entries
* @buf: Where to copy to
* @buflen: The number of bytes to copy
*
* Returns the number of copied bytes.
*
**/
size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
void *buf, size_t buflen)
{
return sg_copy_buffer(sgl, nents, buf, buflen, 1);
}
EXPORT_SYMBOL(sg_copy_to_buffer);

0 comments on commit 0deebc2

Please sign in to comment.