lib/scatterlist: add a flags to signalize mapping direction
authorSebastian Andrzej Siewior <sebastian@breakpoint.cc>
Thu, 18 Jun 2009 08:19:12 +0000 (10:19 +0200)
committerPierre Ossman <pierre@ossman.eu>
Fri, 31 Jul 2009 10:28:45 +0000 (12:28 +0200)
sg_miter_start() is currently unaware of the direction of the copy
process (to or from the scatter list). It is important to know the
direction because the page has to be flushed in case the data written
is seen on a different mapping in user land on cache incoherent
architectures.

Signed-off-by: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
Acked-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Acked-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Pierre Ossman <pierre@ossman.eu>
include/linux/scatterlist.h
lib/scatterlist.c

index e5996984ddd0f9d8b242f9b7219e6f9006c35548..9aaf5bfdad1afcb5e85b39482ea0458a0ea6b83c 100644 (file)
@@ -242,6 +242,8 @@ size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
  */
 
 #define SG_MITER_ATOMIC                (1 << 0)         /* use kmap_atomic */
+#define SG_MITER_TO_SG         (1 << 1)        /* flush back to phys on unmap */
+#define SG_MITER_FROM_SG       (1 << 2)        /* nop */
 
 struct sg_mapping_iter {
        /* the following three fields can be accessed directly */
index a295e404e9087edc5eb5dff3d4a9746c07f59e63..0d475d8167bfd7f4f9909424ea29a72653b581fe 100644 (file)
@@ -314,6 +314,7 @@ void sg_miter_start(struct sg_mapping_iter *miter, struct scatterlist *sgl,
        miter->__sg = sgl;
        miter->__nents = nents;
        miter->__offset = 0;
+       WARN_ON(!(flags & (SG_MITER_TO_SG | SG_MITER_FROM_SG)));
        miter->__flags = flags;
 }
 EXPORT_SYMBOL(sg_miter_start);
@@ -394,6 +395,9 @@ void sg_miter_stop(struct sg_mapping_iter *miter)
        if (miter->addr) {
                miter->__offset += miter->consumed;
 
+               if (miter->__flags & SG_MITER_TO_SG)
+                       flush_kernel_dcache_page(miter->page);
+
                if (miter->__flags & SG_MITER_ATOMIC) {
                        WARN_ON(!irqs_disabled());
                        kunmap_atomic(miter->addr, KM_BIO_SRC_IRQ);
@@ -426,8 +430,14 @@ static size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents,
        unsigned int offset = 0;
        struct sg_mapping_iter miter;
        unsigned long flags;
+       unsigned int sg_flags = SG_MITER_ATOMIC;
+
+       if (to_buffer)
+               sg_flags |= SG_MITER_FROM_SG;
+       else
+               sg_flags |= SG_MITER_TO_SG;
 
-       sg_miter_start(&miter, sgl, nents, SG_MITER_ATOMIC);
+       sg_miter_start(&miter, sgl, nents, sg_flags);
 
        local_irq_save(flags);
 
@@ -438,10 +448,8 @@ static size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents,
 
                if (to_buffer)
                        memcpy(buf + offset, miter.addr, len);
-               else {
+               else
                        memcpy(miter.addr, buf + offset, len);
-                       flush_kernel_dcache_page(miter.page);
-               }
 
                offset += len;
        }