lib/scatterlist: add a flags to signalize mapping direction

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>
This commit is contained in:
Sebastian Andrzej Siewior 2009-06-18 10:19:12 +02:00 committed by Pierre Ossman
parent b592972493
commit 6de7e356fa
2 changed files with 14 additions and 4 deletions

View 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_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 { struct sg_mapping_iter {
/* the following three fields can be accessed directly */ /* the following three fields can be accessed directly */

View file

@ -314,6 +314,7 @@ void sg_miter_start(struct sg_mapping_iter *miter, struct scatterlist *sgl,
miter->__sg = sgl; miter->__sg = sgl;
miter->__nents = nents; miter->__nents = nents;
miter->__offset = 0; miter->__offset = 0;
WARN_ON(!(flags & (SG_MITER_TO_SG | SG_MITER_FROM_SG)));
miter->__flags = flags; miter->__flags = flags;
} }
EXPORT_SYMBOL(sg_miter_start); EXPORT_SYMBOL(sg_miter_start);
@ -394,6 +395,9 @@ void sg_miter_stop(struct sg_mapping_iter *miter)
if (miter->addr) { if (miter->addr) {
miter->__offset += miter->consumed; miter->__offset += miter->consumed;
if (miter->__flags & SG_MITER_TO_SG)
flush_kernel_dcache_page(miter->page);
if (miter->__flags & SG_MITER_ATOMIC) { if (miter->__flags & SG_MITER_ATOMIC) {
WARN_ON(!irqs_disabled()); WARN_ON(!irqs_disabled());
kunmap_atomic(miter->addr, KM_BIO_SRC_IRQ); 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; unsigned int offset = 0;
struct sg_mapping_iter miter; struct sg_mapping_iter miter;
unsigned long flags; unsigned long flags;
unsigned int sg_flags = SG_MITER_ATOMIC;
sg_miter_start(&miter, sgl, nents, 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_flags);
local_irq_save(flags); local_irq_save(flags);
@ -438,10 +448,8 @@ static size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents,
if (to_buffer) if (to_buffer)
memcpy(buf + offset, miter.addr, len); memcpy(buf + offset, miter.addr, len);
else { else
memcpy(miter.addr, buf + offset, len); memcpy(miter.addr, buf + offset, len);
flush_kernel_dcache_page(miter.page);
}
offset += len; offset += len;
} }