2013-06-18 13:31:30

by Akinobu Mita

[permalink] [raw]
Subject: [PATCH v2 0/4] introduce sg_pcopy_from_buffer() and sg_pcopy_to_buffer()

This patch set introduces sg_pcopy_from_buffer() and sg_pcopy_to_buffer(),
which copy data between a linear buffer and an SG list.

The only difference between sg_pcopy_{from,to}_buffer() and
sg_copy_{from,to}_buffer() is an additional argument that specifies
the number of bytes to skip the SG list before copying.

The main reason for introducing these functions is to fix a problem
in scsi_debug module. And there is a local function in crypto/talitos
module, which can be replaced by sg_pcopy_to_buffer().

* Changes from v1
- Separate the change that factors out sg_miter_get_next_page() from
the patch "introduce sg_pcopy_from_buffer() and sg_pcopy_to_buffer()"
- Add function comment for internal function sg_miter_seek()
- Simplify the assignment of sdb->resid in fill_from_dev_buffer() in
scsi_debug

Akinobu Mita (4):
lib/scatterlist: factor out sg_miter_get_next_page() from
sg_miter_next()
lib/scatterlist: introduce sg_pcopy_from_buffer() and
sg_pcopy_to_buffer()
crypto: talitos: use sg_pcopy_to_buffer()
scsi_debug: fix do_device_access() with wrap around range

drivers/crypto/talitos.c | 60 +--------------------
drivers/scsi/scsi_debug.c | 48 +++++++++++++----
include/linux/scatterlist.h | 5 ++
lib/scatterlist.c | 127 +++++++++++++++++++++++++++++++++++++-------
4 files changed, 150 insertions(+), 90 deletions(-)

Cc: Tejun Heo <[email protected]>
Cc: Imre Deak <[email protected]>
Cc: Herbert Xu <[email protected]>
Cc: "David S. Miller" <[email protected]>
Cc: [email protected]
Cc: "James E.J. Bottomley" <[email protected]>
Cc: Douglas Gilbert <dgilber[email protected]>
Cc: [email protected]

--
1.8.1.4


2013-06-18 13:31:32

by Akinobu Mita

[permalink] [raw]
Subject: [PATCH v2 2/4] lib/scatterlist: introduce sg_pcopy_from_buffer() and sg_pcopy_to_buffer()

The only difference between sg_pcopy_{from,to}_buffer() and
sg_copy_{from,to}_buffer() is an additional argument that specifies
the number of bytes to skip the SG list before copying.

Signed-off-by: Akinobu Mita <[email protected]>
Cc: Tejun Heo <[email protected]>
Cc: Imre Deak <[email protected]>
Cc: Herbert Xu <[email protected]>
Cc: "David S. Miller" <[email protected]>
Cc: [email protected]
Cc: "James E.J. Bottomley" <[email protected]>
Cc: Douglas Gilbert <[email protected]>
Cc: [email protected]
---

* Change from v2
- Separate the change that factors out sg_miter_get_next_page()
- Add function comment for internal function sg_miter_seek()

include/linux/scatterlist.h | 5 +++
lib/scatterlist.c | 88 ++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 88 insertions(+), 5 deletions(-)

diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h
index 2680677..adae88f 100644
--- a/include/linux/scatterlist.h
+++ b/include/linux/scatterlist.h
@@ -244,6 +244,11 @@ size_t sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents,
size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
void *buf, size_t buflen);

+size_t sg_pcopy_from_buffer(struct scatterlist *sgl, unsigned int nents,
+ void *buf, size_t buflen, off_t skip);
+size_t sg_pcopy_to_buffer(struct scatterlist *sgl, unsigned int nents,
+ void *buf, size_t buflen, off_t skip);
+
/*
* Maximum number of entries that will be allocated in one piece, if
* a list larger than this is required then chaining will be utilized.
diff --git a/lib/scatterlist.c b/lib/scatterlist.c
index c35b929..f167392 100644
--- a/lib/scatterlist.c
+++ b/lib/scatterlist.c
@@ -476,6 +476,43 @@ static bool sg_miter_get_next_page(struct sg_mapping_iter *miter)
}

/**
+ * sg_miter_seek - reposition mapping iterator
+ * @miter: sg mapping iter to be seeked
+ * @offset: number of bytes to plus the current location
+ *
+ * Description:
+ * Sets the offset of @miter to its current location plus @offset bytes.
+ *
+ * Notes:
+ * This function must be called just after sg_miter_start() or sg_miter_stop()
+ *
+ * Context:
+ * Don't care.
+ *
+ * Returns:
+ * true if @miter contains the valid mapping. false if end of sg
+ * list is reached.
+ */
+static bool sg_miter_seek(struct sg_mapping_iter *miter, off_t offset)
+{
+ WARN_ON(miter->addr);
+
+ while (offset) {
+ off_t consumed;
+
+ if (!sg_miter_get_next_page(miter))
+ return false;
+
+ consumed = min_t(off_t, offset, miter->__remaining);
+ miter->__offset += consumed;
+ miter->__remaining -= consumed;
+ offset -= consumed;
+ }
+
+ return true;
+}
+
+/**
* sg_miter_next - proceed mapping iterator to the next mapping
* @miter: sg mapping iter to proceed
*
@@ -561,14 +598,16 @@ EXPORT_SYMBOL(sg_miter_stop);
* @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
+ * @skip: Number of bytes to skip before copying
+ * @to_buffer: transfer direction (true == from an sg list to a
+ * buffer, false == 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)
+ void *buf, size_t buflen, off_t skip,
+ bool to_buffer)
{
unsigned int offset = 0;
struct sg_mapping_iter miter;
@@ -582,6 +621,9 @@ static size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents,

sg_miter_start(&miter, sgl, nents, sg_flags);

+ if (!sg_miter_seek(&miter, skip))
+ return false;
+
local_irq_save(flags);

while (sg_miter_next(&miter) && offset < buflen) {
@@ -616,7 +658,7 @@ static size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents,
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);
+ return sg_copy_buffer(sgl, nents, buf, buflen, 0, false);
}
EXPORT_SYMBOL(sg_copy_from_buffer);

@@ -633,6 +675,42 @@ EXPORT_SYMBOL(sg_copy_from_buffer);
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);
+ return sg_copy_buffer(sgl, nents, buf, buflen, 0, true);
}
EXPORT_SYMBOL(sg_copy_to_buffer);
+
+/**
+ * sg_pcopy_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
+ * @skip: Number of bytes to skip before copying
+ * @buflen: The number of bytes to copy
+ *
+ * Returns the number of copied bytes.
+ *
+ **/
+size_t sg_pcopy_from_buffer(struct scatterlist *sgl, unsigned int nents,
+ void *buf, size_t buflen, off_t skip)
+{
+ return sg_copy_buffer(sgl, nents, buf, buflen, skip, false);
+}
+EXPORT_SYMBOL(sg_pcopy_from_buffer);
+
+/**
+ * sg_pcopy_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
+ * @skip: Number of bytes to skip before copying
+ * @buflen: The number of bytes to copy
+ *
+ * Returns the number of copied bytes.
+ *
+ **/
+size_t sg_pcopy_to_buffer(struct scatterlist *sgl, unsigned int nents,
+ void *buf, size_t buflen, off_t skip)
+{
+ return sg_copy_buffer(sgl, nents, buf, buflen, skip, true);
+}
+EXPORT_SYMBOL(sg_pcopy_to_buffer);
--
1.8.1.4

2013-06-18 13:31:33

by Akinobu Mita

[permalink] [raw]
Subject: [PATCH v2 3/4] crypto: talitos: use sg_pcopy_to_buffer()

Use sg_pcopy_to_buffer() which is better than the function previously used.
Because it doesn't do kmap/kunmap for skipped pages.

Signed-off-by: Akinobu Mita <[email protected]>
Cc: Herbert Xu <[email protected]>
Cc: Horia Geanta <[email protected]>
Cc: "David S. Miller" <[email protected]>
Cc: [email protected]
---

* No change from v1

drivers/crypto/talitos.c | 60 +-----------------------------------------------
1 file changed, 1 insertion(+), 59 deletions(-)

diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
index 5b2b5e6..661dc3e 100644
--- a/drivers/crypto/talitos.c
+++ b/drivers/crypto/talitos.c
@@ -1112,64 +1112,6 @@ static int sg_count(struct scatterlist *sg_list, int nbytes, bool *chained)
return sg_nents;
}

-/**
- * sg_copy_end_to_buffer - Copy end data from 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
- * @skip: The number of bytes to skip before copying.
- * Note: skip + buflen should equal SG total size.
- *
- * Returns the number of copied bytes.
- *
- **/
-static size_t sg_copy_end_to_buffer(struct scatterlist *sgl, unsigned int nents,
- void *buf, size_t buflen, unsigned int skip)
-{
- unsigned int offset = 0;
- unsigned int boffset = 0;
- struct sg_mapping_iter miter;
- unsigned long flags;
- unsigned int sg_flags = SG_MITER_ATOMIC;
- size_t total_buffer = buflen + skip;
-
- sg_flags |= SG_MITER_FROM_SG;
-
- sg_miter_start(&miter, sgl, nents, sg_flags);
-
- local_irq_save(flags);
-
- while (sg_miter_next(&miter) && offset < total_buffer) {
- unsigned int len;
- unsigned int ignore;
-
- if ((offset + miter.length) > skip) {
- if (offset < skip) {
- /* Copy part of this segment */
- ignore = skip - offset;
- len = miter.length - ignore;
- if (boffset + len > buflen)
- len = buflen - boffset;
- memcpy(buf + boffset, miter.addr + ignore, len);
- } else {
- /* Copy all of this segment (up to buflen) */
- len = miter.length;
- if (boffset + len > buflen)
- len = buflen - boffset;
- memcpy(buf + boffset, miter.addr, len);
- }
- boffset += len;
- }
- offset += miter.length;
- }
-
- sg_miter_stop(&miter);
-
- local_irq_restore(flags);
- return boffset;
-}
-
/*
* allocate and map the extended descriptor
*/
@@ -1800,7 +1742,7 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)

if (to_hash_later) {
int nents = sg_count(areq->src, nbytes, &chained);
- sg_copy_end_to_buffer(areq->src, nents,
+ sg_pcopy_to_buffer(areq->src, nents,
req_ctx->bufnext,
to_hash_later,
nbytes - to_hash_later);
--
1.8.1.4

2013-06-18 13:31:31

by Akinobu Mita

[permalink] [raw]
Subject: [PATCH v2 1/4] lib/scatterlist: factor out sg_miter_get_next_page() from sg_miter_next()

This function is used to proceed page iterator to the next page if
necessary, and will be used to implement the variants of
sg_copy_{from,to}_buffer() later.

Signed-off-by: Akinobu Mita <[email protected]>
Cc: Tejun Heo <[email protected]>
Cc: Imre Deak <[email protected]>
Cc: Herbert Xu <[email protected]>
Cc: "David S. Miller" <[email protected]>
Cc: [email protected]
Cc: "James E.J. Bottomley" <[email protected]>
Cc: Douglas Gilbert <[email protected]>
Cc: [email protected]
---

* New patch from v2

lib/scatterlist.c | 39 ++++++++++++++++++++++++---------------
1 file changed, 24 insertions(+), 15 deletions(-)

diff --git a/lib/scatterlist.c b/lib/scatterlist.c
index a1cf8ca..c35b929 100644
--- a/lib/scatterlist.c
+++ b/lib/scatterlist.c
@@ -453,6 +453,28 @@ void sg_miter_start(struct sg_mapping_iter *miter, struct scatterlist *sgl,
}
EXPORT_SYMBOL(sg_miter_start);

+static bool sg_miter_get_next_page(struct sg_mapping_iter *miter)
+{
+ if (!miter->__remaining) {
+ struct scatterlist *sg;
+ unsigned long pgoffset;
+
+ if (!__sg_page_iter_next(&miter->piter))
+ return false;
+
+ sg = miter->piter.sg;
+ pgoffset = miter->piter.sg_pgoffset;
+
+ miter->__offset = pgoffset ? 0 : sg->offset;
+ miter->__remaining = sg->offset + sg->length -
+ (pgoffset << PAGE_SHIFT) - miter->__offset;
+ miter->__remaining = min_t(unsigned long, miter->__remaining,
+ PAGE_SIZE - miter->__offset);
+ }
+
+ return true;
+}
+
/**
* sg_miter_next - proceed mapping iterator to the next mapping
* @miter: sg mapping iter to proceed
@@ -478,22 +500,9 @@ bool sg_miter_next(struct sg_mapping_iter *miter)
* Get to the next page if necessary.
* __remaining, __offset is adjusted by sg_miter_stop
*/
- if (!miter->__remaining) {
- struct scatterlist *sg;
- unsigned long pgoffset;
-
- if (!__sg_page_iter_next(&miter->piter))
- return false;
-
- sg = miter->piter.sg;
- pgoffset = miter->piter.sg_pgoffset;
+ if (!sg_miter_get_next_page(miter))
+ return false;

- miter->__offset = pgoffset ? 0 : sg->offset;
- miter->__remaining = sg->offset + sg->length -
- (pgoffset << PAGE_SHIFT) - miter->__offset;
- miter->__remaining = min_t(unsigned long, miter->__remaining,
- PAGE_SIZE - miter->__offset);
- }
miter->page = sg_page_iter_page(&miter->piter);
miter->consumed = miter->length = miter->__remaining;

--
1.8.1.4

2013-06-18 14:35:09

by Tejun Heo

[permalink] [raw]
Subject: Re: [PATCH v2 1/4] lib/scatterlist: factor out sg_miter_get_next_page() from sg_miter_next()

On Tue, Jun 18, 2013 at 10:31:31PM +0900, Akinobu Mita wrote:
> This function is used to proceed page iterator to the next page if
> necessary, and will be used to implement the variants of
> sg_copy_{from,to}_buffer() later.
>
> Signed-off-by: Akinobu Mita <[email protected]>
> Cc: Tejun Heo <[email protected]>
> Cc: Imre Deak <[email protected]>
> Cc: Herbert Xu <[email protected]>
> Cc: "David S. Miller" <[email protected]>
> Cc: [email protected]
> Cc: "James E.J. Bottomley" <[email protected]>
> Cc: Douglas Gilbert <[email protected]>
> Cc: [email protected]

Acked-by: Tejun Heo <[email protected]>

Thanks.

--
tejun

2013-06-18 14:37:28

by Tejun Heo

[permalink] [raw]
Subject: Re: [PATCH v2 2/4] lib/scatterlist: introduce sg_pcopy_from_buffer() and sg_pcopy_to_buffer()

On Tue, Jun 18, 2013 at 10:31:32PM +0900, Akinobu Mita wrote:
> /**
> + * sg_miter_seek - reposition mapping iterator
> + * @miter: sg mapping iter to be seeked
> + * @offset: number of bytes to plus the current location
> + *
> + * Description:
> + * Sets the offset of @miter to its current location plus @offset bytes.
> + *
> + * Notes:
> + * This function must be called just after sg_miter_start() or sg_miter_stop()

It's not gonna be hard to make this function to handle any state,
right? Wouldn't it be better to do that? It's a pretty generic
feature after all. Also, maybe a better name is sg_miter_skip()?

Thanks.

--
tejun

2013-06-19 13:12:30

by Akinobu Mita

[permalink] [raw]
Subject: Re: [PATCH v2 2/4] lib/scatterlist: introduce sg_pcopy_from_buffer() and sg_pcopy_to_buffer()

2013/6/18 Tejun Heo <[email protected]>:
> On Tue, Jun 18, 2013 at 10:31:32PM +0900, Akinobu Mita wrote:
>> /**
>> + * sg_miter_seek - reposition mapping iterator
>> + * @miter: sg mapping iter to be seeked
>> + * @offset: number of bytes to plus the current location
>> + *
>> + * Description:
>> + * Sets the offset of @miter to its current location plus @offset bytes.
>> + *
>> + * Notes:
>> + * This function must be called just after sg_miter_start() or sg_miter_stop()
>
> It's not gonna be hard to make this function to handle any state,
> right? Wouldn't it be better to do that? It's a pretty generic
> feature after all. Also, maybe a better name is sg_miter_skip()?

Yes. This limitation can be removed by calling sg_miter_stop() at
the front of sg_miter_seek(). Also, renaming it to sg_miter_skip()
sounds good.