All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] mtd: fix mtd_blkdevs problem with caches on some architectures (2.6.31)
@ 2009-11-18 14:08 Ilya Loginov
  2009-11-21  0:37 ` Andrew Morton
  0 siblings, 1 reply; 18+ messages in thread
From: Ilya Loginov @ 2009-11-18 14:08 UTC (permalink / raw)
  To: David Woodhouse; +Cc: linux-kernel

	Mtdblock driver doesn't call flush_dcache_page for pages in request.
	This may cause problem on architectures where icache doesn't fill from
dcache or with dcache aliases.
	This patch resolves this issue.

Signed-off-by: Ilya Loginov <isloginov@gmail.com>
---
mtd_blkdevs.c |    7 +++++++
1 file changed, 7 insertions(+)

diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
index 7baba40..59d5d25 100644
--- a/drivers/mtd/mtd_blkdevs.c
+++ b/drivers/mtd/mtd_blkdevs.c
@@ -46,6 +46,8 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
 {
 	unsigned long block, nsect;
 	char *buf;
+	struct req_iterator iter;
+	struct bio_vec *bvec;
 
 	block = blk_rq_pos(req) << 9 >> tr->blkshift;
 	nsect = blk_rq_cur_bytes(req) >> tr->blkshift;
@@ -68,12 +70,17 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
 		for (; nsect > 0; nsect--, block++, buf += tr->blksize)
 			if (tr->readsect(dev, block, buf))
 				return -EIO;
+		rq_for_each_segment(bvec, req, iter)
+			flush_dcache_page(bvec->bv_page);
 		return 0;
 
 	case WRITE:
 		if (!tr->writesect)
 			return -EIO;
 
+		rq_for_each_segment(bvec, req, iter)
+			flush_dcache_page(bvec->bv_page);
+		
 		for (; nsect > 0; nsect--, block++, buf += tr->blksize)
 			if (tr->writesect(dev, block, buf))
 				return -EIO;

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH] mtd: fix mtd_blkdevs problem with caches on some architectures (2.6.31)
  2009-11-18 14:08 [PATCH] mtd: fix mtd_blkdevs problem with caches on some architectures (2.6.31) Ilya Loginov
@ 2009-11-21  0:37 ` Andrew Morton
  2009-11-21 14:04   ` Ilya Loginov
  0 siblings, 1 reply; 18+ messages in thread
From: Andrew Morton @ 2009-11-21  0:37 UTC (permalink / raw)
  To: Ilya Loginov
  Cc: David Woodhouse, linux-kernel, Peter Horton, Ed L. Cashin, Jens Axboe

On Wed, 18 Nov 2009 17:08:10 +0300
Ilya Loginov <isloginov@gmail.com> wrote:

> 	Mtdblock driver doesn't call flush_dcache_page for pages in request.
> 	This may cause problem on architectures where icache doesn't fill from
> dcache or with dcache aliases.
> 	This patch resolves this issue.
> 
> Signed-off-by: Ilya Loginov <isloginov@gmail.com>
> ---
> mtd_blkdevs.c |    7 +++++++
> 1 file changed, 7 insertions(+)
> 
> diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
> index 7baba40..59d5d25 100644
> --- a/drivers/mtd/mtd_blkdevs.c
> +++ b/drivers/mtd/mtd_blkdevs.c
> @@ -46,6 +46,8 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
>  {
>  	unsigned long block, nsect;
>  	char *buf;
> +	struct req_iterator iter;
> +	struct bio_vec *bvec;
>  
>  	block = blk_rq_pos(req) << 9 >> tr->blkshift;
>  	nsect = blk_rq_cur_bytes(req) >> tr->blkshift;
> @@ -68,12 +70,17 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
>  		for (; nsect > 0; nsect--, block++, buf += tr->blksize)
>  			if (tr->readsect(dev, block, buf))
>  				return -EIO;
> +		rq_for_each_segment(bvec, req, iter)
> +			flush_dcache_page(bvec->bv_page);
>  		return 0;
>  
>  	case WRITE:
>  		if (!tr->writesect)
>  			return -EIO;
>  
> +		rq_for_each_segment(bvec, req, iter)
> +			flush_dcache_page(bvec->bv_page);
> +		
>  		for (; nsect > 0; nsect--, block++, buf += tr->blksize)
>  			if (tr->writesect(dev, block, buf))
>  				return -EIO;

Please see the recent linux-kernel thread "prevent AoE causing cache
aliases".

Your patch fixes bascially the same problem in MTD as we have in AOE. 
And it introduces the same problem as well - pointless empty
cache-thrashing loops on architectures for which flush_dcache_page() is
a no-op.

What would be better here would be for block core to add a new
rq_flush_dcache_pages() and bio_flush_dcache_pages() which the drivers
can call.  Those functions would be a no-op on architectures which
don't need them.

Jens has made noises about implementing this, but he is working on his
suntan this week.


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] mtd: fix mtd_blkdevs problem with caches on some architectures (2.6.31)
  2009-11-21  0:37 ` Andrew Morton
@ 2009-11-21 14:04   ` Ilya Loginov
  2009-11-21 17:54     ` Andrew Morton
  0 siblings, 1 reply; 18+ messages in thread
From: Ilya Loginov @ 2009-11-21 14:04 UTC (permalink / raw)
  To: Andrew Morton
  Cc: David Woodhouse, linux-kernel, Peter Horton, Ed L. Cashin, Jens Axboe

On Fri, 20 Nov 2009 16:37:51 -0800
Andrew Morton <akpm@linux-foundation.org> wrote:

> Your patch fixes bascially the same problem in MTD as we have in AOE. 
> And it introduces the same problem as well - pointless empty
> cache-thrashing loops on architectures for which flush_dcache_page() is
> a no-op.
> 
> What would be better here would be for block core to add a new
> rq_flush_dcache_pages() and bio_flush_dcache_pages() which the drivers
> can call.  Those functions would be a no-op on architectures which
> don't need them.

Do you mean something like this?

in include/linux/bio.h

#ifdef SOMETHING_LIKE_CONFIG_CPU_HAS_DCACHE_ALIAS
extern void bio_flush_dcache_pages(struct bio *bi);
#else
static inline void bio_flush_dcache_pages(struct bio *bi)
{
}
#endif /* SOMETHING_LIKE_CONFIG_CPU_HAS_DCACHE_ALIAS */

in fs/bio.c

void bio_flush_dcache_pages(struct bio *bi)
{
	int i;
	struct bio_vec* bvec;

	rq_for_each_segment(bvec, bio, i)
		flush_dcache_page(bvec->bv_page);
}

in include/linux/blkdev.h

#ifdef SOMETHING_LIKE_CONFIG_CPU_HAS_DCACHE_ALIAS
extern void rq_flush_dcache_pages(struct request *rq);
#else
static inline void rq_flush_dcache_pages(struct request *rq)
{
}
#endif

in block/blk-core.c

void rq_flush_dcache_pages(struct request *rq)
{
	struct req_iterator iter;
	struct bio_vec* bvec;

	rq_for_each_segment(bvec, bio, iter)
		flush_dcache_page(bvec->bv_page);
}

And SOMETHING_LIKE_CONFIG_CPU_HAS_DCACHE_ALIAS should be defined
in Kconfigs for each architecture that requires this fix. I think 
this is good solution and if you think the same I can create the
patch.

-- 
Ilya Loginov <isloginov@gmail.com>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] mtd: fix mtd_blkdevs problem with caches on some architectures (2.6.31)
  2009-11-21 14:04   ` Ilya Loginov
@ 2009-11-21 17:54     ` Andrew Morton
  2009-11-21 23:11       ` Ilya Loginov
  0 siblings, 1 reply; 18+ messages in thread
From: Andrew Morton @ 2009-11-21 17:54 UTC (permalink / raw)
  To: Ilya Loginov
  Cc: David Woodhouse, linux-kernel, Peter Horton, Ed L. Cashin, Jens Axboe

On Sat, 21 Nov 2009 17:04:37 +0300 Ilya Loginov <isloginov@gmail.com> wrote:

> On Fri, 20 Nov 2009 16:37:51 -0800
> Andrew Morton <akpm@linux-foundation.org> wrote:
> 
> > Your patch fixes bascially the same problem in MTD as we have in AOE. 
> > And it introduces the same problem as well - pointless empty
> > cache-thrashing loops on architectures for which flush_dcache_page() is
> > a no-op.
> > 
> > What would be better here would be for block core to add a new
> > rq_flush_dcache_pages() and bio_flush_dcache_pages() which the drivers
> > can call.  Those functions would be a no-op on architectures which
> > don't need them.
> 
> Do you mean something like this?
> 
> in include/linux/bio.h
> 
> #ifdef SOMETHING_LIKE_CONFIG_CPU_HAS_DCACHE_ALIAS
> extern void bio_flush_dcache_pages(struct bio *bi);
> #else
> static inline void bio_flush_dcache_pages(struct bio *bi)
> {
> }
> #endif /* SOMETHING_LIKE_CONFIG_CPU_HAS_DCACHE_ALIAS */
> 
> in fs/bio.c
> 
> void bio_flush_dcache_pages(struct bio *bi)
> {
> 	int i;
> 	struct bio_vec* bvec;
> 
> 	rq_for_each_segment(bvec, bio, i)
> 		flush_dcache_page(bvec->bv_page);
> }
> 
> in include/linux/blkdev.h
> 
> #ifdef SOMETHING_LIKE_CONFIG_CPU_HAS_DCACHE_ALIAS
> extern void rq_flush_dcache_pages(struct request *rq);
> #else
> static inline void rq_flush_dcache_pages(struct request *rq)
> {
> }
> #endif
> 
> in block/blk-core.c
> 
> void rq_flush_dcache_pages(struct request *rq)
> {
> 	struct req_iterator iter;
> 	struct bio_vec* bvec;
> 
> 	rq_for_each_segment(bvec, bio, iter)
> 		flush_dcache_page(bvec->bv_page);
> }
> 
> And SOMETHING_LIKE_CONFIG_CPU_HAS_DCACHE_ALIAS should be defined
> in Kconfigs for each architecture that requires this fix.

yep, that would work.

The one somewhat fragile thing is that we'll end up in a situation
where an architecture could implement a real flush_dcache_page(), but
would forget to set SOMETHING_LIKE_CONFIG_CPU_HAS_DCACHE_ALIAS.  Or
vice versa.  To make things reliable it would be good to cause a
compilation failure in that case.

One way of addressing this is to

- change every arch/*/include/asm/cacheflush.h to include asm-generic/cacheflush.h

- put #ifndef SOMETHING_LIKE_CONFIG_CPU_HAS_DCACHE_ALIAS wrappers around all content
  in asm-generic/cacheflush

So it the above mistake happens, we'll get lots of duplicated
definitions, or no definitions at all (I think).

> I think 
> this is good solution and if you think the same I can create the
> patch.

Thanks.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] mtd: fix mtd_blkdevs problem with caches on some architectures (2.6.31)
  2009-11-21 17:54     ` Andrew Morton
@ 2009-11-21 23:11       ` Ilya Loginov
  2009-11-21 23:26         ` Andrew Morton
  0 siblings, 1 reply; 18+ messages in thread
From: Ilya Loginov @ 2009-11-21 23:11 UTC (permalink / raw)
  To: Andrew Morton
  Cc: David Woodhouse, linux-kernel, Peter Horton, Ed L. Cashin, Jens Axboe

> The one somewhat fragile thing is that we'll end up in a situation
> where an architecture could implement a real flush_dcache_page(), but
> would forget to set SOMETHING_LIKE_CONFIG_CPU_HAS_DCACHE_ALIAS.  Or
> vice versa.  To make things reliable it would be good to cause a
> compilation failure in that case.

Yes, I do understand this.

> One way of addressing this is to
> 
> - change every arch/*/include/asm/cacheflush.h to include
> asm-generic/cacheflush.h
> 
> - put #ifndef SOMETHING_LIKE_CONFIG_CPU_HAS_DCACHE_ALIAS wrappers
> around all content in asm-generic/cacheflush
> 
> So it the above mistake happens, we'll get lots of duplicated
> definitions, or no definitions at all (I think).

Actually I don't think that it is the best solution. Let me explain.

1) The problem is that flush_dcache_page is defined for a bunch of
different architectures. (x86, ia64, etc). But in most of the cases
flush_dcache_page is empty, but should be defined anyway. Just see the
review:

	h8300 -- empty. All cache defines like asm-generic, but worse
(without do {} while(0)).
	blackfin -- empty for architectures which do not define
CONFIG_BFIN_EXTMEM_WRITEBACK or CONFIG_BFIN_L2_WRITEBACK.
	frv
	x86 -- empty. All cache defines like asm-generic, but it was
implemented throught inline.
	ia64
	sh -- in case if ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE was defined
most flash operations are empty, but there no this define anywhere in
kernel. 
	alpha -- empty, like most cache operations.
	avr32 -- empty. But many other operations are defined.
	arm
	sparc
	powerpc
	m32r -- empty for all chips, like most kernel operations.
	microblaze -- empty.
	cris -- empty. cacheflush is equal to asm-generic, except
define change_page_attr function.
	s390 -- empty. cacheflush is equal to asm-generic, except
define kernel_map_pages function if CONFIG_DEBUG_PAGEALLOC was defined.
	mips -- different for different boards and architectures.
	parisc 
	mn10300 -- empty. But there are functions like
mn10300_dcache_flush_page. I think this is bad.
	m68k -- empty if __uClinux__ is using.
	xtensa -- empty if DCACHE_WAY_SIZE < PAGE_SIZE

So you see, it is a real mess. Only in 8 of 20 architectures
this call don't empty! 


2) In the asm-generic/cacheflush.h also was defined a lot of functions
that could have a conflict and we don't want to have this conflict
anyway. So we will meet here the same problem that was described in you
letter:

> we'll get lots of duplicated
> definitions, or no definitions at all

3) I want to mention that flush_dcache_page depends on the type of
process and chipset as well, so in order to make such things workable
developers usually set different flags in Kconfig. For example
SYS_HAS_EARLY_PRINTK or DMA_NONCOHERENT. And this is the most effective
way of doing this, as far as I see this.

I've just checked most of the places in the kernel where
flush_dcache_page is used. See the summary:

1)
drivers/staging/rspiusb/rspiusb.c

for (i = 0; i < pdx->maplist_numPagesMapped[frameInfo]; i++)
	flush_dcache_page(maplist_p[i]);

2)(is equal to 3))
fs/reiserfs/super.c
fs/reiserfs/inode.c
fs/ufs/super.c
fs/ext2/super.c
fs/nilfs2/mdt.c
fs/jfs/super.c
fs/ocfs2/quota_global.c
fs/ext3/super.c
fs/ext4/super.c

This operation is executed into a loop (big enought).
flush_dcache_page(bh->b_page);

3)
in all other cases there is

flush_dcache_page(page);

4)*
fs/bio.c
mm/bounce.c
net/sunrpc/xprtrdma/rpc_rdma.c

These files call flush_dcache_page in bio_for_each_segment. But
there are another work. So we have no pointless empty loops.

I think we should select SYS_HAS_FLUSH_DCACHE_PAGE for those
architectures which requires it(to fix the bug) (and implement empty
flush_dcache_page throught inline like in x86(to avoid pointless do
{} while(0))).

What do you think about this?


-- 
Ilya Loginov <isloginov@gmail.com>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] mtd: fix mtd_blkdevs problem with caches on some architectures (2.6.31)
  2009-11-21 23:11       ` Ilya Loginov
@ 2009-11-21 23:26         ` Andrew Morton
  2009-11-21 23:36           ` Ilya Loginov
  2009-11-22  9:46           ` Ilya Loginov
  0 siblings, 2 replies; 18+ messages in thread
From: Andrew Morton @ 2009-11-21 23:26 UTC (permalink / raw)
  To: Ilya Loginov
  Cc: David Woodhouse, linux-kernel, Peter Horton, Ed L. Cashin, Jens Axboe

On Sun, 22 Nov 2009 02:11:28 +0300 Ilya Loginov <isloginov@gmail.com> wrote:

> I think we should select SYS_HAS_FLUSH_DCACHE_PAGE for those
> architectures which requires it(to fix the bug) (and implement empty
> flush_dcache_page throught inline like in x86(to avoid pointless do
> {} while(0))).
> 
> What do you think about this?

Well, rather that defining CONFIG_SYS_HAS_FLUSH_DCACHE_PAGE in
Kconfig (which is what I think your were thinking of), we could do:

--- a/arch/x86/include/asm/cacheflush.h~a
+++ a/arch/x86/include/asm/cacheflush.h
@@ -13,6 +13,7 @@ static inline void flush_cache_range(str
 static inline void flush_cache_page(struct vm_area_struct *vma,
 				    unsigned long vmaddr, unsigned long pfn) { }
 static inline void flush_dcache_page(struct page *page) { }
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 static inline void flush_dcache_mmap_lock(struct address_space *mapping) { }
 static inline void flush_dcache_mmap_unlock(struct address_space *mapping) { }
 static inline void flush_icache_range(unsigned long start,
--- a/arch/arm/include/asm/cacheflush.h~a
+++ a/arch/arm/include/asm/cacheflush.h
@@ -409,6 +409,7 @@ extern void flush_ptrace_access(struct v
  * See update_mmu_cache for the user space part.
  */
 extern void flush_dcache_page(struct page *);
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 
 extern void __flush_dcache_page(struct address_space *mapping, struct page *page);
 
(etc)

And then, in a .c file:

#ifndef ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
#error "you lose"
#endif

and, of course:

#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
<implement real code>
#else
<implement empty stubs>
#endif


This way

a) the definition site for ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE is
   right next to the definition site for flush_dcache_page(), instead
   of being in some random remote file and

b) people can't forget to implement ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE.


Generally we prefer to avoid defining ARCH_HAS_FOO in header files and
we prefer to control the definition in Kconfig.  But it sounds like we
have a special case here..


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] mtd: fix mtd_blkdevs problem with caches on some architectures (2.6.31)
  2009-11-21 23:26         ` Andrew Morton
@ 2009-11-21 23:36           ` Ilya Loginov
  2009-11-22  9:46           ` Ilya Loginov
  1 sibling, 0 replies; 18+ messages in thread
From: Ilya Loginov @ 2009-11-21 23:36 UTC (permalink / raw)
  To: Andrew Morton
  Cc: David Woodhouse, linux-kernel, Peter Horton, Ed L. Cashin, Jens Axboe

> And then, in a .c file:
> 
> #ifndef ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
> #error "you lose"
> #endif
> 
> and, of course:
> 
> #if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
> <implement real code>
> #else
> <implement empty stubs>
> #endif
> 
> 
> This way
> 
> a) the definition site for ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE is
>    right next to the definition site for flush_dcache_page(), instead
>    of being in some random remote file and
> 
> b) people can't forget to implement ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE.
> 
> 
> Generally we prefer to avoid defining ARCH_HAS_FOO in header files and
> we prefer to control the definition in Kconfig.  But it sounds like we
> have a special case here..
> 

I agree. I think this is the best way. I will rewrite the patch.
Thank you!

-- 
Ilya Loginov <isloginov@gmail.com>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] mtd: fix mtd_blkdevs problem with caches on some architectures (2.6.31)
  2009-11-21 23:26         ` Andrew Morton
  2009-11-21 23:36           ` Ilya Loginov
@ 2009-11-22  9:46           ` Ilya Loginov
  2009-11-22  9:53             ` David Woodhouse
  2009-11-22 13:29             ` Ingo Molnar
  1 sibling, 2 replies; 18+ messages in thread
From: Ilya Loginov @ 2009-11-22  9:46 UTC (permalink / raw)
  To: Andrew Morton
  Cc: David Woodhouse, linux-kernel, Peter Horton, Ed L. Cashin, Jens Axboe

What do you think about this version of patch?
Is it good enought?

Signed-off-by: Ilya Loginov <isloginov@gmail.com>
---
 arch/alpha/include/asm/cacheflush.h         |    1 +
 arch/arm/include/asm/cacheflush.h           |    1 +
 arch/avr32/include/asm/cacheflush.h         |    1 +
 arch/blackfin/include/asm/cacheflush.h      |    2 ++
 arch/cris/include/asm/cacheflush.h          |    1 +
 arch/frv/include/asm/cacheflush.h           |    1 +
 arch/h8300/include/asm/cacheflush.h         |    1 +
 arch/ia64/include/asm/cacheflush.h          |    1 +
 arch/m32r/include/asm/cacheflush.h          |    3 +++
 arch/m68k/include/asm/cacheflush_mm.h       |    1 +
 arch/m68k/include/asm/cacheflush_no.h       |    1 +
 arch/microblaze/include/asm/cacheflush.h    |    1 +
 arch/mips/include/asm/cacheflush.h          |    1 +
 arch/mn10300/include/asm/cacheflush.h       |    1 +
 arch/parisc/include/asm/cacheflush.h        |    1 +
 arch/powerpc/include/asm/cacheflush.h       |    1 +
 arch/s390/include/asm/cacheflush.h          |    1 +
 arch/sh/include/asm/cacheflush.h            |    1 +
 arch/sh/include/cpu-common/cpu/cacheflush.h |    1 +
 arch/sh/include/cpu-sh2a/cpu/cacheflush.h   |    1 +
 arch/sh/include/cpu-sh3/cpu/cacheflush.h    |    1 +
 arch/sh/include/cpu-sh4/cpu/cacheflush.h    |    1 +
 arch/sh/include/cpu-sh5/cpu/cacheflush.h    |    1 +
 arch/sparc/include/asm/cacheflush_32.h      |    1 +
 arch/sparc/include/asm/cacheflush_64.h      |    1 +
 arch/x86/include/asm/cacheflush.h           |    1 +
 arch/xtensa/include/asm/cacheflush.h        |    2 ++
 drivers/mtd/mtd_blkdevs.c                   |    2 ++
 include/linux/bio.h                         |   19 +++++++++++++++++++
 include/linux/blkdev.h                      |   18 ++++++++++++++++++
 30 files changed, 70 insertions(+)

diff --git a/arch/alpha/include/asm/cacheflush.h
b/arch/alpha/include/asm/cacheflush.h index b686cc7..01d71e1 100644
--- a/arch/alpha/include/asm/cacheflush.h
+++ b/arch/alpha/include/asm/cacheflush.h
@@ -9,6 +9,7 @@
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/arm/include/asm/cacheflush.h
b/arch/arm/include/asm/cacheflush.h index 1a711ea..2420f91 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -408,6 +408,7 @@ extern void flush_ptrace_access(struct
vm_area_struct *vma, struct page *page,
  * about to change to user space.  This is the same method as used on
SPARC64.
  * See update_mmu_cache for the user space part.
  */
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *);
 
 extern void __flush_dcache_page(struct address_space *mapping, struct
page *page); diff --git a/arch/avr32/include/asm/cacheflush.h
b/arch/avr32/include/asm/cacheflush.h index 6706747..96e5382 100644
--- a/arch/avr32/include/asm/cacheflush.h
+++ b/arch/avr32/include/asm/cacheflush.h
@@ -107,6 +107,7 @@ extern void flush_icache_page(struct vm_area_struct
*vma, struct page *page);
  * do something here, but only for certain configurations.  No such
  * configurations exist at this time.
  */
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(page)		do { } while (0)
 #define flush_dcache_mmap_unlock(page)		do { } while (0)
diff --git a/arch/blackfin/include/asm/cacheflush.h
b/arch/blackfin/include/asm/cacheflush.h index 7e55549..0a7d14b 100644
--- a/arch/blackfin/include/asm/cacheflush.h
+++ b/arch/blackfin/include/asm/cacheflush.h
@@ -89,9 +89,11 @@ do { memcpy(dst, src,
len);						\ #endif
 #if defined(CONFIG_BFIN_EXTMEM_WRITEBACK) || defined
(CONFIG_BFIN_L2_WRITEBACK) # define flush_dcache_range
(start,end)		blackfin_dcache_flush_range((start), (end))
+# define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1 # define flush_dcache_page
(page)		blackfin_dflush_page(page_address(page)) #else
 # define flush_dcache_range(start,end)		do { } while (0)
+# define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 # define flush_dcache_page(page)		do { } while (0)
 #endif
 
diff --git a/arch/cris/include/asm/cacheflush.h
b/arch/cris/include/asm/cacheflush.h index cf60e3f..36795bc 100644
--- a/arch/cris/include/asm/cacheflush.h
+++ b/arch/cris/include/asm/cacheflush.h
@@ -12,6 +12,7 @@
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/frv/include/asm/cacheflush.h
b/arch/frv/include/asm/cacheflush.h index 432a69e..edbac54 100644
--- a/arch/frv/include/asm/cacheflush.h
+++ b/arch/frv/include/asm/cacheflush.h
@@ -47,6 +47,7 @@ static inline void __flush_cache_all(void)
 }
 
 /* dcache/icache coherency... */
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 #ifdef CONFIG_MMU
 extern void flush_dcache_page(struct page *page);
 #else
diff --git a/arch/h8300/include/asm/cacheflush.h
b/arch/h8300/include/asm/cacheflush.h index 5ffdca2..4cf2df2 100644
--- a/arch/h8300/include/asm/cacheflush.h
+++ b/arch/h8300/include/asm/cacheflush.h
@@ -15,6 +15,7 @@
 #define	flush_cache_dup_mm(mm)		do { } while (0)
 #define	flush_cache_range(vma,a,b)
 #define	flush_cache_page(vma,p,pfn)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define	flush_dcache_page(page)
 #define	flush_dcache_mmap_lock(mapping)
 #define	flush_dcache_mmap_unlock(mapping)
diff --git a/arch/ia64/include/asm/cacheflush.h
b/arch/ia64/include/asm/cacheflush.h index c8ce271..429eefc 100644
--- a/arch/ia64/include/asm/cacheflush.h
+++ b/arch/ia64/include/asm/cacheflush.h
@@ -25,6 +25,7 @@
 #define flush_cache_vmap(start, end)		do { } while (0)
 #define flush_cache_vunmap(start, end)		do { } while (0)
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 #define flush_dcache_page(page)			\
 do {						\
 	clear_bit(PG_arch_1, &(page)->flags);	\
diff --git a/arch/m32r/include/asm/cacheflush.h
b/arch/m32r/include/asm/cacheflush.h index 78587c9..8e8e045 100644
--- a/arch/m32r/include/asm/cacheflush.h
+++ b/arch/m32r/include/asm/cacheflush.h
@@ -12,6 +12,7 @@ extern void _flush_cache_copyback_all(void);
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
@@ -33,6 +34,7 @@ extern void smp_flush_cache_all(void);
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
@@ -46,6 +48,7 @@ extern void smp_flush_cache_all(void);
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/m68k/include/asm/cacheflush_mm.h
b/arch/m68k/include/asm/cacheflush_mm.h index 16bf375..73de7c8 100644
--- a/arch/m68k/include/asm/cacheflush_mm.h
+++ b/arch/m68k/include/asm/cacheflush_mm.h
@@ -128,6 +128,7 @@ static inline void __flush_page_to_ram(void *vaddr)
 	}
 }
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 #define flush_dcache_page(page)		__flush_page_to_ram
(page_address(page)) #define flush_dcache_mmap_lock
(mapping)		do { } while (0) #define
flush_dcache_mmap_unlock(mapping)	do { } while (0) diff --git
a/arch/m68k/include/asm/cacheflush_no.h
b/arch/m68k/include/asm/cacheflush_no.h index c65f00a..89f1956 100644
--- a/arch/m68k/include/asm/cacheflush_no.h
+++ b/arch/m68k/include/asm/cacheflush_no.h
@@ -12,6 +12,7 @@
 #define flush_cache_range(vma, start, end)	__flush_cache_all()
 #define flush_cache_page(vma, vmaddr)		do { } while (0)
 #define flush_dcache_range(start,len)		__flush_cache_all
() +#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/microblaze/include/asm/cacheflush.h
b/arch/microblaze/include/asm/cacheflush.h index f989d6a..088076e 100644
--- a/arch/microblaze/include/asm/cacheflush.h
+++ b/arch/microblaze/include/asm/cacheflush.h
@@ -37,6 +37,7 @@
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
 
 #define flush_dcache_range(start, end)	__invalidate_dcache_range
(start, end) +#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/mips/include/asm/cacheflush.h
b/arch/mips/include/asm/cacheflush.h index 03b1d69..40bb9fd 100644
--- a/arch/mips/include/asm/cacheflush.h
+++ b/arch/mips/include/asm/cacheflush.h
@@ -38,6 +38,7 @@ extern void (*flush_cache_range)(struct
vm_area_struct *vma, extern void (*flush_cache_page)(struct
vm_area_struct *vma, unsigned long page, unsigned long pfn); extern
void __flush_dcache_page(struct page *page); 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 static inline void flush_dcache_page(struct page *page)
 {
 	if (cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc)
diff --git a/arch/mn10300/include/asm/cacheflush.h
b/arch/mn10300/include/asm/cacheflush.h index 2db746a..4a15067 100644
--- a/arch/mn10300/include/asm/cacheflush.h
+++ b/arch/mn10300/include/asm/cacheflush.h
@@ -26,6 +26,7 @@
 #define flush_cache_page(vma, vmaddr, pfn)	do {} while (0)
 #define flush_cache_vmap(start, end)		do {} while (0)
 #define flush_cache_vunmap(start, end)		do {} while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do {} while (0)
 #define flush_dcache_mmap_lock(mapping)		do {} while (0)
 #define flush_dcache_mmap_unlock(mapping)	do {} while (0)
diff --git a/arch/parisc/include/asm/cacheflush.h
b/arch/parisc/include/asm/cacheflush.h index 7243951..7a73b61 100644
--- a/arch/parisc/include/asm/cacheflush.h
+++ b/arch/parisc/include/asm/cacheflush.h
@@ -42,6 +42,7 @@ void flush_cache_mm(struct mm_struct *mm);
 #define flush_cache_vmap(start, end)		flush_cache_all()
 #define flush_cache_vunmap(start, end)		flush_cache_all()
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *page);
 
 #define flush_dcache_mmap_lock(mapping) \
diff --git a/arch/powerpc/include/asm/cacheflush.h
b/arch/powerpc/include/asm/cacheflush.h index ba667a3..ab9e402 100644
--- a/arch/powerpc/include/asm/cacheflush.h
+++ b/arch/powerpc/include/asm/cacheflush.h
@@ -25,6 +25,7 @@
 #define flush_cache_vmap(start, end)		do { } while (0)
 #define flush_cache_vunmap(start, end)		do { } while (0)
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *page);
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/s390/include/asm/cacheflush.h
b/arch/s390/include/asm/cacheflush.h index 49d5af9..405cc97 100644
--- a/arch/s390/include/asm/cacheflush.h
+++ b/arch/s390/include/asm/cacheflush.h
@@ -10,6 +10,7 @@
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/sh/include/asm/cacheflush.h
b/arch/sh/include/asm/cacheflush.h index 4c5462d..46ba64c 100644
--- a/arch/sh/include/asm/cacheflush.h
+++ b/arch/sh/include/asm/cacheflush.h
@@ -16,6 +16,7 @@
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_icache_range(start, end)		do { } while (0)
 #define flush_icache_page(vma,pg)		do { } while (0)
diff --git a/arch/sh/include/cpu-common/cpu/cacheflush.h
b/arch/sh/include/cpu-common/cpu/cacheflush.h index c3db00b..bd508bd
100644
--- a/arch/sh/include/cpu-common/cpu/cacheflush.h
+++ b/arch/sh/include/cpu-common/cpu/cacheflush.h
@@ -31,6 +31,7 @@
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/sh/include/cpu-sh2a/cpu/cacheflush.h
b/arch/sh/include/cpu-sh2a/cpu/cacheflush.h index 3d3b920..56c8c88
100644
--- a/arch/sh/include/cpu-sh2a/cpu/cacheflush.h
+++ b/arch/sh/include/cpu-sh2a/cpu/cacheflush.h
@@ -22,6 +22,7 @@
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/sh/include/cpu-sh3/cpu/cacheflush.h
b/arch/sh/include/cpu-sh3/cpu/cacheflush.h index 1ac27aa..e03e964 100644
--- a/arch/sh/include/cpu-sh3/cpu/cacheflush.h
+++ b/arch/sh/include/cpu-sh3/cpu/cacheflush.h
@@ -26,6 +26,7 @@ void flush_cache_mm(struct mm_struct *mm);
 void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
                               unsigned long end);
 void flush_cache_page(struct vm_area_struct *vma, unsigned long addr,
unsigned long pfn); +#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 void flush_dcache_page(struct page *pg);
 void flush_icache_range(unsigned long start, unsigned long end);
 void flush_icache_page(struct vm_area_struct *vma, struct page *page);
diff --git a/arch/sh/include/cpu-sh4/cpu/cacheflush.h
b/arch/sh/include/cpu-sh4/cpu/cacheflush.h index 065306d..1789e3e 100644
--- a/arch/sh/include/cpu-sh4/cpu/cacheflush.h
+++ b/arch/sh/include/cpu-sh4/cpu/cacheflush.h
@@ -24,6 +24,7 @@ void flush_cache_range(struct vm_area_struct *vma,
unsigned long start, unsigned long end);
 void flush_cache_page(struct vm_area_struct *vma, unsigned long addr,
 		      unsigned long pfn);
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 void flush_dcache_page(struct page *pg);
 
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
diff --git a/arch/sh/include/cpu-sh5/cpu/cacheflush.h
b/arch/sh/include/cpu-sh5/cpu/cacheflush.h index 5a11f0b..cd098a3 100644
--- a/arch/sh/include/cpu-sh5/cpu/cacheflush.h
+++ b/arch/sh/include/cpu-sh5/cpu/cacheflush.h
@@ -13,6 +13,7 @@ extern void flush_cache_sigtramp(unsigned long vaddr);
 extern void flush_cache_range(struct vm_area_struct *vma, unsigned
long start, unsigned long end);
 extern void flush_cache_page(struct vm_area_struct *vma, unsigned long
addr, unsigned long pfn); +#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *pg);
 extern void flush_icache_range(unsigned long start, unsigned long end);
 extern void flush_icache_user_range(struct vm_area_struct *vma,
diff --git a/arch/sparc/include/asm/cacheflush_32.h
b/arch/sparc/include/asm/cacheflush_32.h index 68ac109..2e46877 100644
--- a/arch/sparc/include/asm/cacheflush_32.h
+++ b/arch/sparc/include/asm/cacheflush_32.h
@@ -75,6 +75,7 @@ BTFIXUPDEF_CALL(void, flush_sig_insns, struct
mm_struct *, unsigned long) 
 extern void sparc_flush_page_to_ram(struct page *page);
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 #define flush_dcache_page(page)
sparc_flush_page_to_ram(page) #define flush_dcache_mmap_lock
(mapping)		do { } while (0) #define
flush_dcache_mmap_unlock(mapping)	do { } while (0) diff --git
a/arch/sparc/include/asm/cacheflush_64.h
b/arch/sparc/include/asm/cacheflush_64.h index c433217..b953840 100644
--- a/arch/sparc/include/asm/cacheflush_64.h
+++ b/arch/sparc/include/asm/cacheflush_64.h
@@ -37,6 +37,7 @@ extern void flush_dcache_page_all(struct mm_struct
*mm, struct page *page); #endif
 
 extern void __flush_dcache_range(unsigned long start, unsigned long
end); +#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *page);
 
 #define flush_icache_page(vma, pg)	do { } while(0)
diff --git a/arch/x86/include/asm/cacheflush.h
b/arch/x86/include/asm/cacheflush.h index e55dfc1..7631500 100644
--- a/arch/x86/include/asm/cacheflush.h
+++ b/arch/x86/include/asm/cacheflush.h
@@ -12,6 +12,7 @@ static inline void flush_cache_range(struct
vm_area_struct *vma, unsigned long start, unsigned long end) { }
 static inline void flush_cache_page(struct vm_area_struct *vma,
 				    unsigned long vmaddr, unsigned
long pfn) { } +#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 static inline void flush_dcache_page(struct page *page) { }
 static inline void flush_dcache_mmap_lock(struct address_space
*mapping) { } static inline void flush_dcache_mmap_unlock(struct
address_space *mapping) { } diff --git
a/arch/xtensa/include/asm/cacheflush.h
b/arch/xtensa/include/asm/cacheflush.h index b7b8fbe..376cd9d 100644
--- a/arch/xtensa/include/asm/cacheflush.h
+++ b/arch/xtensa/include/asm/cacheflush.h
@@ -101,6 +101,7 @@ static inline void __invalidate_icache_page_alias
(unsigned long virt, #define flush_cache_vmap(start,end)
flush_cache_all() #define flush_cache_vunmap(start,end)
flush_cache_all() 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page*);
 extern void flush_cache_range(struct vm_area_struct*, ulong, ulong);
 extern void flush_cache_page(struct vm_area_struct*, unsigned long,
unsigned long); @@ -114,6 +115,7 @@ extern void flush_cache_page(struct
vm_area_struct*, unsigned long, unsigned lon #define flush_cache_vmap
(start,end)			do { } while (0) #define
flush_cache_vunmap(start,end)			do { } while (0) 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)				do { }
while (0) 
 #define flush_cache_page(vma,addr,pfn)			do { }
while (0) diff --git a/drivers/mtd/mtd_blkdevs.c
b/drivers/mtd/mtd_blkdevs.c index 7baba40..abddc60 100644
--- a/drivers/mtd/mtd_blkdevs.c
+++ b/drivers/mtd/mtd_blkdevs.c
@@ -68,12 +68,14 @@ static int do_blktrans_request(struct
mtd_blktrans_ops *tr, for (; nsect > 0; nsect--, block++, buf +=
tr->blksize) if (tr->readsect(dev, block, buf))
 				return -EIO;
+		rq_flush_dcache_pages(req);
 		return 0;
 
 	case WRITE:
 		if (!tr->writesect)
 			return -EIO;
 
+		rq_flush_dcache_pages(req);
 		for (; nsect > 0; nsect--, block++, buf += tr->blksize)
 			if (tr->writesect(dev, block, buf))
 				return -EIO;
diff --git a/include/linux/bio.h b/include/linux/bio.h
index 2892b71..ecafedc 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -396,6 +396,25 @@ extern struct bio *bio_copy_kern(struct
request_queue *, void *, unsigned int, gfp_t, int);
 extern void bio_set_pages_dirty(struct bio *bio);
 extern void bio_check_pages_dirty(struct bio *bio);
+
+#ifndef ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
+# error	"You should to define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
for your platform." +#endif
+#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
+static inline void bio_flush_dcache_pages(struct bio *bi)
+{
+	int i;
+	struct bio_vec* bvec;
+
+	bio_for_each_segment(bvec, bi, i)
+		flush_dcache_page(bvec->bv_page);
+}
+#else
+static inline void bio_flush_dcache_pages(struct bio *bi)
+{
+}
+#endif
+
 extern struct bio *bio_copy_user(struct request_queue *, struct
rq_map_data *, unsigned long, unsigned int, int, gfp_t);
 extern struct bio *bio_copy_user_iov(struct request_queue *,
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 69103e0..9b5214c 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -740,6 +740,24 @@ struct req_iterator {
 #define rq_iter_last(rq, _iter)
\ (_iter.bio->bi_next == NULL && _iter.i == _iter.bio->bi_vcnt-1)
 
+#ifndef ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
+# error	"You should to define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
for your platform." +#endif
+#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
+static inline void rq_flush_dcache_pages(struct request *rq)
+{
+	struct req_iterator iter;
+	struct bio_vec* bvec;
+
+	rq_for_each_segment(bvec, rq, iter)
+		flush_dcache_page(bvec->bv_page);
+}
+#else
+static inline void rq_flush_dcache_pages(struct request *rq)
+{
+}
+#endif
+
 extern int blk_register_queue(struct gendisk *disk);
 extern void blk_unregister_queue(struct gendisk *disk);
 extern void register_disk(struct gendisk *dev);


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH] mtd: fix mtd_blkdevs problem with caches on some architectures (2.6.31)
  2009-11-22  9:46           ` Ilya Loginov
@ 2009-11-22  9:53             ` David Woodhouse
  2009-11-22 18:49               ` Ilya Loginov
  2009-11-22 13:29             ` Ingo Molnar
  1 sibling, 1 reply; 18+ messages in thread
From: David Woodhouse @ 2009-11-22  9:53 UTC (permalink / raw)
  To: Ilya Loginov
  Cc: Andrew Morton, linux-kernel, Peter Horton, Ed L. Cashin, Jens Axboe

On Sun, 2009-11-22 at 12:46 +0300, Ilya Loginov wrote:
> 
> +#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
>  #define flush_dcache_page(page)                        do { } while (0)
>  #define flush_dcache_mmap_lock(mapping)                do { } while (0)
>  #define flush_dcache_mmap_unlock(mapping)      do { } while (0) 

The thing is, having a function called flush_dcache_page() which doesn't
actually flush a page of the dcache is just blatantly stupid.

It's misnamed -- it should probably be called something like
'flush_valiased_dcache_page()' or 'unalias_dcache_page()' instead, since
I believe it's only supposed to cope with aliasing issues with virtually
indexed caches.

If you're talking about _extending_ the existing silly name to a new
ARCH_IMPLEMENTS_FOO macro or Kconfig option, perhaps this would be a
good time to fix the nomenclature, rather than propagating the error?

-- 
David Woodhouse                            Open Source Technology Centre
David.Woodhouse@intel.com                              Intel Corporation


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] mtd: fix mtd_blkdevs problem with caches on some architectures (2.6.31)
  2009-11-22  9:46           ` Ilya Loginov
  2009-11-22  9:53             ` David Woodhouse
@ 2009-11-22 13:29             ` Ingo Molnar
  2009-11-22 13:55               ` Ilya Loginov
  1 sibling, 1 reply; 18+ messages in thread
From: Ingo Molnar @ 2009-11-22 13:29 UTC (permalink / raw)
  To: Ilya Loginov
  Cc: Andrew Morton, David Woodhouse, linux-kernel, Peter Horton,
	Ed L. Cashin, Jens Axboe


* Ilya Loginov <isloginov@gmail.com> wrote:

> What do you think about this version of patch?
> Is it good enought?
> 
> Signed-off-by: Ilya Loginov <isloginov@gmail.com>
> ---
>  arch/alpha/include/asm/cacheflush.h         |    1 +
>  arch/arm/include/asm/cacheflush.h           |    1 +
>  arch/avr32/include/asm/cacheflush.h         |    1 +
>  arch/blackfin/include/asm/cacheflush.h      |    2 ++
>  arch/cris/include/asm/cacheflush.h          |    1 +
>  arch/frv/include/asm/cacheflush.h           |    1 +
>  arch/h8300/include/asm/cacheflush.h         |    1 +
>  arch/ia64/include/asm/cacheflush.h          |    1 +
>  arch/m32r/include/asm/cacheflush.h          |    3 +++
>  arch/m68k/include/asm/cacheflush_mm.h       |    1 +
>  arch/m68k/include/asm/cacheflush_no.h       |    1 +
>  arch/microblaze/include/asm/cacheflush.h    |    1 +
>  arch/mips/include/asm/cacheflush.h          |    1 +
>  arch/mn10300/include/asm/cacheflush.h       |    1 +
>  arch/parisc/include/asm/cacheflush.h        |    1 +
>  arch/powerpc/include/asm/cacheflush.h       |    1 +
>  arch/s390/include/asm/cacheflush.h          |    1 +
>  arch/sh/include/asm/cacheflush.h            |    1 +
>  arch/sh/include/cpu-common/cpu/cacheflush.h |    1 +
>  arch/sh/include/cpu-sh2a/cpu/cacheflush.h   |    1 +
>  arch/sh/include/cpu-sh3/cpu/cacheflush.h    |    1 +
>  arch/sh/include/cpu-sh4/cpu/cacheflush.h    |    1 +
>  arch/sh/include/cpu-sh5/cpu/cacheflush.h    |    1 +
>  arch/sparc/include/asm/cacheflush_32.h      |    1 +
>  arch/sparc/include/asm/cacheflush_64.h      |    1 +
>  arch/x86/include/asm/cacheflush.h           |    1 +
>  arch/xtensa/include/asm/cacheflush.h        |    2 ++
>  drivers/mtd/mtd_blkdevs.c                   |    2 ++
>  include/linux/bio.h                         |   19 +++++++++++++++++++
>  include/linux/blkdev.h                      |   18 ++++++++++++++++++
>  30 files changed, 70 insertions(+)

patch looks mangled in the middle:

> --- a/arch/x86/include/asm/cacheflush.h
> +++ b/arch/x86/include/asm/cacheflush.h
> @@ -12,6 +12,7 @@ static inline void flush_cache_range(struct
> vm_area_struct *vma, unsigned long start, unsigned long end) { }
>  static inline void flush_cache_page(struct vm_area_struct *vma,
>  				    unsigned long vmaddr, unsigned
> long pfn) { } +#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
>  static inline void flush_dcache_page(struct page *page) { }
>  static inline void flush_dcache_mmap_lock(struct address_space
> *mapping) { } static inline void flush_dcache_mmap_unlock(struct
> address_space *mapping) { } diff --git

	Ingo

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] mtd: fix mtd_blkdevs problem with caches on some architectures (2.6.31)
  2009-11-22 13:29             ` Ingo Molnar
@ 2009-11-22 13:55               ` Ilya Loginov
  2009-11-22 18:48                 ` Andrew Morton
  0 siblings, 1 reply; 18+ messages in thread
From: Ilya Loginov @ 2009-11-22 13:55 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Andrew Morton, David Woodhouse, linux-kernel, Peter Horton,
	Ed L. Cashin, Jens Axboe

> patch looks mangled in the middle:

Oh, yeah. Thank you! I've changed my e-mail client preferences yesturday.
This was bad idea...

This is right version.

Signed-off-by: Ilya Loginov <isloginov@gmail.com>
---
 arch/alpha/include/asm/cacheflush.h         |    1 +
 arch/arm/include/asm/cacheflush.h           |    1 +
 arch/avr32/include/asm/cacheflush.h         |    1 +
 arch/blackfin/include/asm/cacheflush.h      |    2 ++
 arch/cris/include/asm/cacheflush.h          |    1 +
 arch/frv/include/asm/cacheflush.h           |    1 +
 arch/h8300/include/asm/cacheflush.h         |    1 +
 arch/ia64/include/asm/cacheflush.h          |    1 +
 arch/m32r/include/asm/cacheflush.h          |    3 +++
 arch/m68k/include/asm/cacheflush_mm.h       |    1 +
 arch/m68k/include/asm/cacheflush_no.h       |    1 +
 arch/microblaze/include/asm/cacheflush.h    |    1 +
 arch/mips/include/asm/cacheflush.h          |    1 +
 arch/mn10300/include/asm/cacheflush.h       |    1 +
 arch/parisc/include/asm/cacheflush.h        |    1 +
 arch/powerpc/include/asm/cacheflush.h       |    1 +
 arch/s390/include/asm/cacheflush.h          |    1 +
 arch/sh/include/asm/cacheflush.h            |    1 +
 arch/sh/include/cpu-common/cpu/cacheflush.h |    1 +
 arch/sh/include/cpu-sh2a/cpu/cacheflush.h   |    1 +
 arch/sh/include/cpu-sh3/cpu/cacheflush.h    |    1 +
 arch/sh/include/cpu-sh4/cpu/cacheflush.h    |    1 +
 arch/sh/include/cpu-sh5/cpu/cacheflush.h    |    1 +
 arch/sparc/include/asm/cacheflush_32.h      |    1 +
 arch/sparc/include/asm/cacheflush_64.h      |    1 +
 arch/x86/include/asm/cacheflush.h           |    1 +
 arch/xtensa/include/asm/cacheflush.h        |    2 ++
 drivers/mtd/mtd_blkdevs.c                   |    2 ++
 include/linux/bio.h                         |   19 +++++++++++++++++++
 include/linux/blkdev.h                      |   18 ++++++++++++++++++
 30 files changed, 70 insertions(+)

diff --git a/arch/alpha/include/asm/cacheflush.h b/arch/alpha/include/asm/cacheflush.h
index b686cc7..01d71e1 100644
--- a/arch/alpha/include/asm/cacheflush.h
+++ b/arch/alpha/include/asm/cacheflush.h
@@ -9,6 +9,7 @@
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index 1a711ea..2420f91 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -408,6 +408,7 @@ extern void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
  * about to change to user space.  This is the same method as used on SPARC64.
  * See update_mmu_cache for the user space part.
  */
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *);
 
 extern void __flush_dcache_page(struct address_space *mapping, struct page *page);
diff --git a/arch/avr32/include/asm/cacheflush.h b/arch/avr32/include/asm/cacheflush.h
index 6706747..96e5382 100644
--- a/arch/avr32/include/asm/cacheflush.h
+++ b/arch/avr32/include/asm/cacheflush.h
@@ -107,6 +107,7 @@ extern void flush_icache_page(struct vm_area_struct *vma, struct page *page);
  * do something here, but only for certain configurations.  No such
  * configurations exist at this time.
  */
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(page)		do { } while (0)
 #define flush_dcache_mmap_unlock(page)		do { } while (0)
diff --git a/arch/blackfin/include/asm/cacheflush.h b/arch/blackfin/include/asm/cacheflush.h
index 7e55549..0a7d14b 100644
--- a/arch/blackfin/include/asm/cacheflush.h
+++ b/arch/blackfin/include/asm/cacheflush.h
@@ -89,9 +89,11 @@ do { memcpy(dst, src, len);						\
 #endif
 #if defined(CONFIG_BFIN_EXTMEM_WRITEBACK) || defined(CONFIG_BFIN_L2_WRITEBACK)
 # define flush_dcache_range(start,end)		blackfin_dcache_flush_range((start), (end))
+# define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 # define flush_dcache_page(page)		blackfin_dflush_page(page_address(page))
 #else
 # define flush_dcache_range(start,end)		do { } while (0)
+# define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 # define flush_dcache_page(page)		do { } while (0)
 #endif
 
diff --git a/arch/cris/include/asm/cacheflush.h b/arch/cris/include/asm/cacheflush.h
index cf60e3f..36795bc 100644
--- a/arch/cris/include/asm/cacheflush.h
+++ b/arch/cris/include/asm/cacheflush.h
@@ -12,6 +12,7 @@
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/frv/include/asm/cacheflush.h b/arch/frv/include/asm/cacheflush.h
index 432a69e..edbac54 100644
--- a/arch/frv/include/asm/cacheflush.h
+++ b/arch/frv/include/asm/cacheflush.h
@@ -47,6 +47,7 @@ static inline void __flush_cache_all(void)
 }
 
 /* dcache/icache coherency... */
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 #ifdef CONFIG_MMU
 extern void flush_dcache_page(struct page *page);
 #else
diff --git a/arch/h8300/include/asm/cacheflush.h b/arch/h8300/include/asm/cacheflush.h
index 5ffdca2..4cf2df2 100644
--- a/arch/h8300/include/asm/cacheflush.h
+++ b/arch/h8300/include/asm/cacheflush.h
@@ -15,6 +15,7 @@
 #define	flush_cache_dup_mm(mm)		do { } while (0)
 #define	flush_cache_range(vma,a,b)
 #define	flush_cache_page(vma,p,pfn)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define	flush_dcache_page(page)
 #define	flush_dcache_mmap_lock(mapping)
 #define	flush_dcache_mmap_unlock(mapping)
diff --git a/arch/ia64/include/asm/cacheflush.h b/arch/ia64/include/asm/cacheflush.h
index c8ce271..429eefc 100644
--- a/arch/ia64/include/asm/cacheflush.h
+++ b/arch/ia64/include/asm/cacheflush.h
@@ -25,6 +25,7 @@
 #define flush_cache_vmap(start, end)		do { } while (0)
 #define flush_cache_vunmap(start, end)		do { } while (0)
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 #define flush_dcache_page(page)			\
 do {						\
 	clear_bit(PG_arch_1, &(page)->flags);	\
diff --git a/arch/m32r/include/asm/cacheflush.h b/arch/m32r/include/asm/cacheflush.h
index 78587c9..8e8e045 100644
--- a/arch/m32r/include/asm/cacheflush.h
+++ b/arch/m32r/include/asm/cacheflush.h
@@ -12,6 +12,7 @@ extern void _flush_cache_copyback_all(void);
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
@@ -33,6 +34,7 @@ extern void smp_flush_cache_all(void);
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
@@ -46,6 +48,7 @@ extern void smp_flush_cache_all(void);
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/m68k/include/asm/cacheflush_mm.h b/arch/m68k/include/asm/cacheflush_mm.h
index 16bf375..73de7c8 100644
--- a/arch/m68k/include/asm/cacheflush_mm.h
+++ b/arch/m68k/include/asm/cacheflush_mm.h
@@ -128,6 +128,7 @@ static inline void __flush_page_to_ram(void *vaddr)
 	}
 }
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 #define flush_dcache_page(page)		__flush_page_to_ram(page_address(page))
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/m68k/include/asm/cacheflush_no.h b/arch/m68k/include/asm/cacheflush_no.h
index c65f00a..89f1956 100644
--- a/arch/m68k/include/asm/cacheflush_no.h
+++ b/arch/m68k/include/asm/cacheflush_no.h
@@ -12,6 +12,7 @@
 #define flush_cache_range(vma, start, end)	__flush_cache_all()
 #define flush_cache_page(vma, vmaddr)		do { } while (0)
 #define flush_dcache_range(start,len)		__flush_cache_all()
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/microblaze/include/asm/cacheflush.h b/arch/microblaze/include/asm/cacheflush.h
index f989d6a..088076e 100644
--- a/arch/microblaze/include/asm/cacheflush.h
+++ b/arch/microblaze/include/asm/cacheflush.h
@@ -37,6 +37,7 @@
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
 
 #define flush_dcache_range(start, end)	__invalidate_dcache_range(start, end)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/mips/include/asm/cacheflush.h b/arch/mips/include/asm/cacheflush.h
index 03b1d69..40bb9fd 100644
--- a/arch/mips/include/asm/cacheflush.h
+++ b/arch/mips/include/asm/cacheflush.h
@@ -38,6 +38,7 @@ extern void (*flush_cache_range)(struct vm_area_struct *vma,
 extern void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page, unsigned long pfn);
 extern void __flush_dcache_page(struct page *page);
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 static inline void flush_dcache_page(struct page *page)
 {
 	if (cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc)
diff --git a/arch/mn10300/include/asm/cacheflush.h b/arch/mn10300/include/asm/cacheflush.h
index 2db746a..4a15067 100644
--- a/arch/mn10300/include/asm/cacheflush.h
+++ b/arch/mn10300/include/asm/cacheflush.h
@@ -26,6 +26,7 @@
 #define flush_cache_page(vma, vmaddr, pfn)	do {} while (0)
 #define flush_cache_vmap(start, end)		do {} while (0)
 #define flush_cache_vunmap(start, end)		do {} while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do {} while (0)
 #define flush_dcache_mmap_lock(mapping)		do {} while (0)
 #define flush_dcache_mmap_unlock(mapping)	do {} while (0)
diff --git a/arch/parisc/include/asm/cacheflush.h b/arch/parisc/include/asm/cacheflush.h
index 7243951..7a73b61 100644
--- a/arch/parisc/include/asm/cacheflush.h
+++ b/arch/parisc/include/asm/cacheflush.h
@@ -42,6 +42,7 @@ void flush_cache_mm(struct mm_struct *mm);
 #define flush_cache_vmap(start, end)		flush_cache_all()
 #define flush_cache_vunmap(start, end)		flush_cache_all()
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *page);
 
 #define flush_dcache_mmap_lock(mapping) \
diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h
index ba667a3..ab9e402 100644
--- a/arch/powerpc/include/asm/cacheflush.h
+++ b/arch/powerpc/include/asm/cacheflush.h
@@ -25,6 +25,7 @@
 #define flush_cache_vmap(start, end)		do { } while (0)
 #define flush_cache_vunmap(start, end)		do { } while (0)
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *page);
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/s390/include/asm/cacheflush.h b/arch/s390/include/asm/cacheflush.h
index 49d5af9..405cc97 100644
--- a/arch/s390/include/asm/cacheflush.h
+++ b/arch/s390/include/asm/cacheflush.h
@@ -10,6 +10,7 @@
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/sh/include/asm/cacheflush.h b/arch/sh/include/asm/cacheflush.h
index 4c5462d..46ba64c 100644
--- a/arch/sh/include/asm/cacheflush.h
+++ b/arch/sh/include/asm/cacheflush.h
@@ -16,6 +16,7 @@
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_icache_range(start, end)		do { } while (0)
 #define flush_icache_page(vma,pg)		do { } while (0)
diff --git a/arch/sh/include/cpu-common/cpu/cacheflush.h b/arch/sh/include/cpu-common/cpu/cacheflush.h
index c3db00b..bd508bd 100644
--- a/arch/sh/include/cpu-common/cpu/cacheflush.h
+++ b/arch/sh/include/cpu-common/cpu/cacheflush.h
@@ -31,6 +31,7 @@
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/sh/include/cpu-sh2a/cpu/cacheflush.h b/arch/sh/include/cpu-sh2a/cpu/cacheflush.h
index 3d3b920..56c8c88 100644
--- a/arch/sh/include/cpu-sh2a/cpu/cacheflush.h
+++ b/arch/sh/include/cpu-sh2a/cpu/cacheflush.h
@@ -22,6 +22,7 @@
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/sh/include/cpu-sh3/cpu/cacheflush.h b/arch/sh/include/cpu-sh3/cpu/cacheflush.h
index 1ac27aa..e03e964 100644
--- a/arch/sh/include/cpu-sh3/cpu/cacheflush.h
+++ b/arch/sh/include/cpu-sh3/cpu/cacheflush.h
@@ -26,6 +26,7 @@ void flush_cache_mm(struct mm_struct *mm);
 void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
                               unsigned long end);
 void flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn);
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 void flush_dcache_page(struct page *pg);
 void flush_icache_range(unsigned long start, unsigned long end);
 void flush_icache_page(struct vm_area_struct *vma, struct page *page);
diff --git a/arch/sh/include/cpu-sh4/cpu/cacheflush.h b/arch/sh/include/cpu-sh4/cpu/cacheflush.h
index 065306d..1789e3e 100644
--- a/arch/sh/include/cpu-sh4/cpu/cacheflush.h
+++ b/arch/sh/include/cpu-sh4/cpu/cacheflush.h
@@ -24,6 +24,7 @@ void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
 		       unsigned long end);
 void flush_cache_page(struct vm_area_struct *vma, unsigned long addr,
 		      unsigned long pfn);
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 void flush_dcache_page(struct page *pg);
 
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
diff --git a/arch/sh/include/cpu-sh5/cpu/cacheflush.h b/arch/sh/include/cpu-sh5/cpu/cacheflush.h
index 5a11f0b..cd098a3 100644
--- a/arch/sh/include/cpu-sh5/cpu/cacheflush.h
+++ b/arch/sh/include/cpu-sh5/cpu/cacheflush.h
@@ -13,6 +13,7 @@ extern void flush_cache_sigtramp(unsigned long vaddr);
 extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
 			      unsigned long end);
 extern void flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn);
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *pg);
 extern void flush_icache_range(unsigned long start, unsigned long end);
 extern void flush_icache_user_range(struct vm_area_struct *vma,
diff --git a/arch/sparc/include/asm/cacheflush_32.h b/arch/sparc/include/asm/cacheflush_32.h
index 68ac109..2e46877 100644
--- a/arch/sparc/include/asm/cacheflush_32.h
+++ b/arch/sparc/include/asm/cacheflush_32.h
@@ -75,6 +75,7 @@ BTFIXUPDEF_CALL(void, flush_sig_insns, struct mm_struct *, unsigned long)
 
 extern void sparc_flush_page_to_ram(struct page *page);
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 #define flush_dcache_page(page)			sparc_flush_page_to_ram(page)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/sparc/include/asm/cacheflush_64.h b/arch/sparc/include/asm/cacheflush_64.h
index c433217..b953840 100644
--- a/arch/sparc/include/asm/cacheflush_64.h
+++ b/arch/sparc/include/asm/cacheflush_64.h
@@ -37,6 +37,7 @@ extern void flush_dcache_page_all(struct mm_struct *mm, struct page *page);
 #endif
 
 extern void __flush_dcache_range(unsigned long start, unsigned long end);
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *page);
 
 #define flush_icache_page(vma, pg)	do { } while(0)
diff --git a/arch/x86/include/asm/cacheflush.h b/arch/x86/include/asm/cacheflush.h
index e55dfc1..7631500 100644
--- a/arch/x86/include/asm/cacheflush.h
+++ b/arch/x86/include/asm/cacheflush.h
@@ -12,6 +12,7 @@ static inline void flush_cache_range(struct vm_area_struct *vma,
 				     unsigned long start, unsigned long end) { }
 static inline void flush_cache_page(struct vm_area_struct *vma,
 				    unsigned long vmaddr, unsigned long pfn) { }
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 static inline void flush_dcache_page(struct page *page) { }
 static inline void flush_dcache_mmap_lock(struct address_space *mapping) { }
 static inline void flush_dcache_mmap_unlock(struct address_space *mapping) { }
diff --git a/arch/xtensa/include/asm/cacheflush.h b/arch/xtensa/include/asm/cacheflush.h
index b7b8fbe..376cd9d 100644
--- a/arch/xtensa/include/asm/cacheflush.h
+++ b/arch/xtensa/include/asm/cacheflush.h
@@ -101,6 +101,7 @@ static inline void __invalidate_icache_page_alias(unsigned long virt,
 #define flush_cache_vmap(start,end)	flush_cache_all()
 #define flush_cache_vunmap(start,end)	flush_cache_all()
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page*);
 extern void flush_cache_range(struct vm_area_struct*, ulong, ulong);
 extern void flush_cache_page(struct vm_area_struct*, unsigned long, unsigned long);
@@ -114,6 +115,7 @@ extern void flush_cache_page(struct vm_area_struct*, unsigned long, unsigned lon
 #define flush_cache_vmap(start,end)			do { } while (0)
 #define flush_cache_vunmap(start,end)			do { } while (0)
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)				do { } while (0)
 
 #define flush_cache_page(vma,addr,pfn)			do { } while (0)
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
index 7baba40..abddc60 100644
--- a/drivers/mtd/mtd_blkdevs.c
+++ b/drivers/mtd/mtd_blkdevs.c
@@ -68,12 +68,14 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
 		for (; nsect > 0; nsect--, block++, buf += tr->blksize)
 			if (tr->readsect(dev, block, buf))
 				return -EIO;
+		rq_flush_dcache_pages(req);
 		return 0;
 
 	case WRITE:
 		if (!tr->writesect)
 			return -EIO;
 
+		rq_flush_dcache_pages(req);
 		for (; nsect > 0; nsect--, block++, buf += tr->blksize)
 			if (tr->writesect(dev, block, buf))
 				return -EIO;
diff --git a/include/linux/bio.h b/include/linux/bio.h
index 2892b71..ecafedc 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -396,6 +396,25 @@ extern struct bio *bio_copy_kern(struct request_queue *, void *, unsigned int,
 				 gfp_t, int);
 extern void bio_set_pages_dirty(struct bio *bio);
 extern void bio_check_pages_dirty(struct bio *bio);
+
+#ifndef ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
+# error	"You should to define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE for your platform."
+#endif
+#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
+static inline void bio_flush_dcache_pages(struct bio *bi)
+{
+	int i;
+	struct bio_vec* bvec;
+
+	bio_for_each_segment(bvec, bi, i)
+		flush_dcache_page(bvec->bv_page);
+}
+#else
+static inline void bio_flush_dcache_pages(struct bio *bi)
+{
+}
+#endif
+
 extern struct bio *bio_copy_user(struct request_queue *, struct rq_map_data *,
 				 unsigned long, unsigned int, int, gfp_t);
 extern struct bio *bio_copy_user_iov(struct request_queue *,
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 69103e0..9b5214c 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -740,6 +740,24 @@ struct req_iterator {
 #define rq_iter_last(rq, _iter)					\
 		(_iter.bio->bi_next == NULL && _iter.i == _iter.bio->bi_vcnt-1)
 
+#ifndef ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
+# error	"You should to define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE for your platform."
+#endif
+#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
+static inline void rq_flush_dcache_pages(struct request *rq)
+{
+	struct req_iterator iter;
+	struct bio_vec* bvec;
+
+	rq_for_each_segment(bvec, rq, iter)
+		flush_dcache_page(bvec->bv_page);
+}
+#else
+static inline void rq_flush_dcache_pages(struct request *rq)
+{
+}
+#endif
+
 extern int blk_register_queue(struct gendisk *disk);
 extern void blk_unregister_queue(struct gendisk *disk);
 extern void register_disk(struct gendisk *dev);


-- 
Ilya Loginov <isloginov@gmail.com>

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH] mtd: fix mtd_blkdevs problem with caches on some architectures (2.6.31)
  2009-11-22 13:55               ` Ilya Loginov
@ 2009-11-22 18:48                 ` Andrew Morton
  2009-11-22 19:18                   ` Ilya Loginov
  0 siblings, 1 reply; 18+ messages in thread
From: Andrew Morton @ 2009-11-22 18:48 UTC (permalink / raw)
  To: Ilya Loginov
  Cc: Ingo Molnar, David Woodhouse, linux-kernel, Peter Horton,
	Ed L. Cashin, Jens Axboe

On Sun, 22 Nov 2009 16:55:21 +0300 Ilya Loginov <isloginov@gmail.com> wrote:

> +#ifndef ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
> +# error	"You should to define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE for your platform."
> +#endif
> +#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
> +static inline void bio_flush_dcache_pages(struct bio *bi)
> +{
> +	int i;
> +	struct bio_vec* bvec;
> +
> +	bio_for_each_segment(bvec, bi, i)
> +		flush_dcache_page(bvec->bv_page);
> +}
> +#else
> +static inline void bio_flush_dcache_pages(struct bio *bi)
> +{
> +}
> +#endif
> +
>  extern struct bio *bio_copy_user(struct request_queue *, struct rq_map_data *,
>  				 unsigned long, unsigned int, int, gfp_t);
>  extern struct bio *bio_copy_user_iov(struct request_queue *,
> diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
> index 69103e0..9b5214c 100644
> --- a/include/linux/blkdev.h
> +++ b/include/linux/blkdev.h
> @@ -740,6 +740,24 @@ struct req_iterator {
>  #define rq_iter_last(rq, _iter)					\
>  		(_iter.bio->bi_next == NULL && _iter.i == _iter.bio->bi_vcnt-1)
>  
> +#ifndef ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
> +# error	"You should to define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE for your platform."
> +#endif
> +#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
> +static inline void rq_flush_dcache_pages(struct request *rq)
> +{
> +	struct req_iterator iter;
> +	struct bio_vec* bvec;
> +
> +	rq_for_each_segment(bvec, rq, iter)
> +		flush_dcache_page(bvec->bv_page);
> +}
> +#else
> +static inline void rq_flush_dcache_pages(struct request *rq)
> +{
> +}
> +#endif

I don't think the non-stub versions of these should be inlined.  They
will generate quite a lot of code and they're pretty heavyweight. 
Better to implement them in block/ somewhere, and EXPORT_SYMBOL().


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] mtd: fix mtd_blkdevs problem with caches on some architectures (2.6.31)
  2009-11-22  9:53             ` David Woodhouse
@ 2009-11-22 18:49               ` Ilya Loginov
  0 siblings, 0 replies; 18+ messages in thread
From: Ilya Loginov @ 2009-11-22 18:49 UTC (permalink / raw)
  To: David Woodhouse
  Cc: Andrew Morton, linux-kernel, Peter Horton, Ed L. Cashin, Jens Axboe

On Sun, 22 Nov 2009 09:53:50 +0000
David Woodhouse <dwmw2@infradead.org> wrote:

> The thing is, having a function called flush_dcache_page() which doesn't
> actually flush a page of the dcache is just blatantly stupid.

Unfortunately, it's well-established that all architectures have these 
functions. Many kernel systems, for example file systems drivers (ext2,
ext3, ntfs), use them.

In letter to Andrew Morton I wrote that among 20 architectures this call
is not empty only for 8 of them. And it is the problem.

But some architectures really need this call. And kernel has to work
reasonably with them too. Therefore it is required often to call for
empty functions.
 
> It's misnamed -- it should probably be called something like
> 'flush_valiased_dcache_page()' or 'unalias_dcache_page()' instead, since
> I believe it's only supposed to cope with aliasing issues with virtually
> indexed caches.

I don't think so. For example I had this bug on the processor, which 
icache don't finds for data in dcache. There was no dcache aliases.
 
> If you're talking about _extending_ the existing silly name to a new
> ARCH_IMPLEMENTS_FOO macro or Kconfig option, perhaps this would be a
> good time to fix the nomenclature, rather than propagating the error?

Andrew has showed me in his first letter another topic in this mailing.
It is said there that there is no reasonable infrastructure in kernel to
correct such things. The first patch can fix bug in the mtd but the 
problem of useless cycle on many architectures is arising. 

It is because there is nothing associated with the flush_dcache_page()
function. 

This way enable us to solve and this problem too. But I agree that it
is not elegant. Have you any idea how to make it better?

Thanks!

-- 
Ilya Loginov <isloginov@gmail.com>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] mtd: fix mtd_blkdevs problem with caches on some architectures (2.6.31)
  2009-11-22 18:48                 ` Andrew Morton
@ 2009-11-22 19:18                   ` Ilya Loginov
  2009-11-22 19:51                     ` Andrew Morton
  0 siblings, 1 reply; 18+ messages in thread
From: Ilya Loginov @ 2009-11-22 19:18 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Ingo Molnar, David Woodhouse, linux-kernel, Peter Horton,
	Ed L. Cashin, Jens Axboe

On Sun, 22 Nov 2009 10:48:16 -0800
Andrew Morton <akpm@linux-foundation.org> wrote:

> I don't think the non-stub versions of these should be inlined.  They
> will generate quite a lot of code and they're pretty heavyweight.
> Better to implement them in block/ somewhere, and EXPORT_SYMBOL().

I tried this way from the beginning, and to avoid redefinitions I enclose
everything in #if #endif in *.c files. I think it is not very good.
So there are two possibilities.

1. To keep it like it is now and in this way there will be quite a lot of code.
But in previous letters I gave statistics on the flush_dcache_page call in a
kernel. And our case is particular. There will not be generated a lot of code.
Or just take away inline.

2. Or it is better to carry over normal realization to *.c file and enclose
everything by one more #if #endif.

What do you consier to be better?

-- 
Ilya Loginov <isloginov@gmail.com>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] mtd: fix mtd_blkdevs problem with caches on some architectures (2.6.31)
  2009-11-22 19:18                   ` Ilya Loginov
@ 2009-11-22 19:51                     ` Andrew Morton
  2009-11-22 20:55                       ` Ilya Loginov
  0 siblings, 1 reply; 18+ messages in thread
From: Andrew Morton @ 2009-11-22 19:51 UTC (permalink / raw)
  To: Ilya Loginov
  Cc: Ingo Molnar, David Woodhouse, linux-kernel, Peter Horton,
	Ed L. Cashin, Jens Axboe

On Sun, 22 Nov 2009 22:18:36 +0300 Ilya Loginov <isloginov@gmail.com> wrote:

> On Sun, 22 Nov 2009 10:48:16 -0800
> Andrew Morton <akpm@linux-foundation.org> wrote:
> 
> > I don't think the non-stub versions of these should be inlined.  They
> > will generate quite a lot of code and they're pretty heavyweight.
> > Better to implement them in block/ somewhere, and EXPORT_SYMBOL().
> 
> I tried this way from the beginning, and to avoid redefinitions I enclose
> everything in #if #endif in *.c files. I think it is not very good.
> So there are two possibilities.
> 
> 1. To keep it like it is now and in this way there will be quite a lot of code.
> But in previous letters I gave statistics on the flush_dcache_page call in a
> kernel. And our case is particular. There will not be generated a lot of code.
> Or just take away inline.
> 
> 2. Or it is better to carry over normal realization to *.c file and enclose
> everything by one more #if #endif.
> 
> What do you consier to be better?

3. :)

In .h:

#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
extern void rq_flush_dcache_pages(struct request *rq);
#else
static inline void bio_flush_dcache_pages(struct bio *bi)
{
}
#endif

In .c:
	
#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
void rq_flush_dcache_pages(struct request *rq)
{
	struct req_iterator iter;
	struct bio_vec* bvec;

	rq_for_each_segment(bvec, rq, iter)
		flush_dcache_page(bvec->bv_page);
}
EXPORT_SYMBOL(rq_flush_dcache_pages);
#endif

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] mtd: fix mtd_blkdevs problem with caches on some architectures (2.6.31)
  2009-11-22 19:51                     ` Andrew Morton
@ 2009-11-22 20:55                       ` Ilya Loginov
  2009-11-24 20:48                         ` Andrew Morton
  0 siblings, 1 reply; 18+ messages in thread
From: Ilya Loginov @ 2009-11-22 20:55 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Ingo Molnar, David Woodhouse, linux-kernel, Peter Horton,
	Ed L. Cashin, Jens Axboe

> > I tried this way from the beginning, and to avoid redefinitions I enclose
> > everything in #if #endif in *.c files. I think it is not very good.
> > So there are two possibilities.
> > 

Ah. I think the first choice is always the best choise. =)

> In .h:
> 
> #if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
> extern void rq_flush_dcache_pages(struct request *rq);
> #else
> static inline void bio_flush_dcache_pages(struct bio *bi)
> {
> }
> #endif
> 
> In .c:
> 	
> #if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
> void rq_flush_dcache_pages(struct request *rq)
> {
> 	struct req_iterator iter;
> 	struct bio_vec* bvec;
> 
> 	rq_for_each_segment(bvec, rq, iter)
> 		flush_dcache_page(bvec->bv_page);
> }
> EXPORT_SYMBOL(rq_flush_dcache_pages);
> #endif

This is 2) =)

Thanks a lot for your help and comments!

Signed-off-by: Ilya Loginov <isloginov@gmail.com>
---
 arch/alpha/include/asm/cacheflush.h         |    1 +
 arch/arm/include/asm/cacheflush.h           |    1 +
 arch/avr32/include/asm/cacheflush.h         |    1 +
 arch/blackfin/include/asm/cacheflush.h      |    2 ++
 arch/cris/include/asm/cacheflush.h          |    1 +
 arch/frv/include/asm/cacheflush.h           |    1 +
 arch/h8300/include/asm/cacheflush.h         |    1 +
 arch/ia64/include/asm/cacheflush.h          |    1 +
 arch/m32r/include/asm/cacheflush.h          |    3 +++
 arch/m68k/include/asm/cacheflush_mm.h       |    1 +
 arch/m68k/include/asm/cacheflush_no.h       |    1 +
 arch/microblaze/include/asm/cacheflush.h    |    1 +
 arch/mips/include/asm/cacheflush.h          |    1 +
 arch/mn10300/include/asm/cacheflush.h       |    1 +
 arch/parisc/include/asm/cacheflush.h        |    1 +
 arch/powerpc/include/asm/cacheflush.h       |    1 +
 arch/s390/include/asm/cacheflush.h          |    1 +
 arch/sh/include/asm/cacheflush.h            |    1 +
 arch/sh/include/cpu-common/cpu/cacheflush.h |    1 +
 arch/sh/include/cpu-sh2a/cpu/cacheflush.h   |    1 +
 arch/sh/include/cpu-sh3/cpu/cacheflush.h    |    1 +
 arch/sh/include/cpu-sh4/cpu/cacheflush.h    |    1 +
 arch/sh/include/cpu-sh5/cpu/cacheflush.h    |    1 +
 arch/sparc/include/asm/cacheflush_32.h      |    1 +
 arch/sparc/include/asm/cacheflush_64.h      |    1 +
 arch/x86/include/asm/cacheflush.h           |    1 +
 arch/xtensa/include/asm/cacheflush.h        |    2 ++
 block/blk-core.c                            |   19 +++++++++++++++++++
 drivers/mtd/mtd_blkdevs.c                   |    2 ++
 fs/bio.c                                    |   12 ++++++++++++
 include/linux/bio.h                         |   12 ++++++++++++
 include/linux/blkdev.h                      |   11 +++++++++++
 32 files changed, 87 insertions(+)

diff --git a/arch/alpha/include/asm/cacheflush.h b/arch/alpha/include/asm/cacheflush.h
index b686cc7..01d71e1 100644
--- a/arch/alpha/include/asm/cacheflush.h
+++ b/arch/alpha/include/asm/cacheflush.h
@@ -9,6 +9,7 @@
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index 1a711ea..2420f91 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -408,6 +408,7 @@ extern void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
  * about to change to user space.  This is the same method as used on SPARC64.
  * See update_mmu_cache for the user space part.
  */
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *);
 
 extern void __flush_dcache_page(struct address_space *mapping, struct page *page);
diff --git a/arch/avr32/include/asm/cacheflush.h b/arch/avr32/include/asm/cacheflush.h
index 6706747..96e5382 100644
--- a/arch/avr32/include/asm/cacheflush.h
+++ b/arch/avr32/include/asm/cacheflush.h
@@ -107,6 +107,7 @@ extern void flush_icache_page(struct vm_area_struct *vma, struct page *page);
  * do something here, but only for certain configurations.  No such
  * configurations exist at this time.
  */
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(page)		do { } while (0)
 #define flush_dcache_mmap_unlock(page)		do { } while (0)
diff --git a/arch/blackfin/include/asm/cacheflush.h b/arch/blackfin/include/asm/cacheflush.h
index 7e55549..0a7d14b 100644
--- a/arch/blackfin/include/asm/cacheflush.h
+++ b/arch/blackfin/include/asm/cacheflush.h
@@ -89,9 +89,11 @@ do { memcpy(dst, src, len);						\
 #endif
 #if defined(CONFIG_BFIN_EXTMEM_WRITEBACK) || defined(CONFIG_BFIN_L2_WRITEBACK)
 # define flush_dcache_range(start,end)		blackfin_dcache_flush_range((start), (end))
+# define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 # define flush_dcache_page(page)		blackfin_dflush_page(page_address(page))
 #else
 # define flush_dcache_range(start,end)		do { } while (0)
+# define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 # define flush_dcache_page(page)		do { } while (0)
 #endif
 
diff --git a/arch/cris/include/asm/cacheflush.h b/arch/cris/include/asm/cacheflush.h
index cf60e3f..36795bc 100644
--- a/arch/cris/include/asm/cacheflush.h
+++ b/arch/cris/include/asm/cacheflush.h
@@ -12,6 +12,7 @@
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/frv/include/asm/cacheflush.h b/arch/frv/include/asm/cacheflush.h
index 432a69e..edbac54 100644
--- a/arch/frv/include/asm/cacheflush.h
+++ b/arch/frv/include/asm/cacheflush.h
@@ -47,6 +47,7 @@ static inline void __flush_cache_all(void)
 }
 
 /* dcache/icache coherency... */
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 #ifdef CONFIG_MMU
 extern void flush_dcache_page(struct page *page);
 #else
diff --git a/arch/h8300/include/asm/cacheflush.h b/arch/h8300/include/asm/cacheflush.h
index 5ffdca2..4cf2df2 100644
--- a/arch/h8300/include/asm/cacheflush.h
+++ b/arch/h8300/include/asm/cacheflush.h
@@ -15,6 +15,7 @@
 #define	flush_cache_dup_mm(mm)		do { } while (0)
 #define	flush_cache_range(vma,a,b)
 #define	flush_cache_page(vma,p,pfn)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define	flush_dcache_page(page)
 #define	flush_dcache_mmap_lock(mapping)
 #define	flush_dcache_mmap_unlock(mapping)
diff --git a/arch/ia64/include/asm/cacheflush.h b/arch/ia64/include/asm/cacheflush.h
index c8ce271..429eefc 100644
--- a/arch/ia64/include/asm/cacheflush.h
+++ b/arch/ia64/include/asm/cacheflush.h
@@ -25,6 +25,7 @@
 #define flush_cache_vmap(start, end)		do { } while (0)
 #define flush_cache_vunmap(start, end)		do { } while (0)
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 #define flush_dcache_page(page)			\
 do {						\
 	clear_bit(PG_arch_1, &(page)->flags);	\
diff --git a/arch/m32r/include/asm/cacheflush.h b/arch/m32r/include/asm/cacheflush.h
index 78587c9..8e8e045 100644
--- a/arch/m32r/include/asm/cacheflush.h
+++ b/arch/m32r/include/asm/cacheflush.h
@@ -12,6 +12,7 @@ extern void _flush_cache_copyback_all(void);
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
@@ -33,6 +34,7 @@ extern void smp_flush_cache_all(void);
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
@@ -46,6 +48,7 @@ extern void smp_flush_cache_all(void);
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/m68k/include/asm/cacheflush_mm.h b/arch/m68k/include/asm/cacheflush_mm.h
index 16bf375..73de7c8 100644
--- a/arch/m68k/include/asm/cacheflush_mm.h
+++ b/arch/m68k/include/asm/cacheflush_mm.h
@@ -128,6 +128,7 @@ static inline void __flush_page_to_ram(void *vaddr)
 	}
 }
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 #define flush_dcache_page(page)		__flush_page_to_ram(page_address(page))
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/m68k/include/asm/cacheflush_no.h b/arch/m68k/include/asm/cacheflush_no.h
index c65f00a..89f1956 100644
--- a/arch/m68k/include/asm/cacheflush_no.h
+++ b/arch/m68k/include/asm/cacheflush_no.h
@@ -12,6 +12,7 @@
 #define flush_cache_range(vma, start, end)	__flush_cache_all()
 #define flush_cache_page(vma, vmaddr)		do { } while (0)
 #define flush_dcache_range(start,len)		__flush_cache_all()
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/microblaze/include/asm/cacheflush.h b/arch/microblaze/include/asm/cacheflush.h
index f989d6a..088076e 100644
--- a/arch/microblaze/include/asm/cacheflush.h
+++ b/arch/microblaze/include/asm/cacheflush.h
@@ -37,6 +37,7 @@
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
 
 #define flush_dcache_range(start, end)	__invalidate_dcache_range(start, end)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/mips/include/asm/cacheflush.h b/arch/mips/include/asm/cacheflush.h
index 03b1d69..40bb9fd 100644
--- a/arch/mips/include/asm/cacheflush.h
+++ b/arch/mips/include/asm/cacheflush.h
@@ -38,6 +38,7 @@ extern void (*flush_cache_range)(struct vm_area_struct *vma,
 extern void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page, unsigned long pfn);
 extern void __flush_dcache_page(struct page *page);
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 static inline void flush_dcache_page(struct page *page)
 {
 	if (cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc)
diff --git a/arch/mn10300/include/asm/cacheflush.h b/arch/mn10300/include/asm/cacheflush.h
index 2db746a..4a15067 100644
--- a/arch/mn10300/include/asm/cacheflush.h
+++ b/arch/mn10300/include/asm/cacheflush.h
@@ -26,6 +26,7 @@
 #define flush_cache_page(vma, vmaddr, pfn)	do {} while (0)
 #define flush_cache_vmap(start, end)		do {} while (0)
 #define flush_cache_vunmap(start, end)		do {} while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do {} while (0)
 #define flush_dcache_mmap_lock(mapping)		do {} while (0)
 #define flush_dcache_mmap_unlock(mapping)	do {} while (0)
diff --git a/arch/parisc/include/asm/cacheflush.h b/arch/parisc/include/asm/cacheflush.h
index 7243951..7a73b61 100644
--- a/arch/parisc/include/asm/cacheflush.h
+++ b/arch/parisc/include/asm/cacheflush.h
@@ -42,6 +42,7 @@ void flush_cache_mm(struct mm_struct *mm);
 #define flush_cache_vmap(start, end)		flush_cache_all()
 #define flush_cache_vunmap(start, end)		flush_cache_all()
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *page);
 
 #define flush_dcache_mmap_lock(mapping) \
diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h
index ba667a3..ab9e402 100644
--- a/arch/powerpc/include/asm/cacheflush.h
+++ b/arch/powerpc/include/asm/cacheflush.h
@@ -25,6 +25,7 @@
 #define flush_cache_vmap(start, end)		do { } while (0)
 #define flush_cache_vunmap(start, end)		do { } while (0)
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *page);
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/s390/include/asm/cacheflush.h b/arch/s390/include/asm/cacheflush.h
index 49d5af9..405cc97 100644
--- a/arch/s390/include/asm/cacheflush.h
+++ b/arch/s390/include/asm/cacheflush.h
@@ -10,6 +10,7 @@
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/sh/include/asm/cacheflush.h b/arch/sh/include/asm/cacheflush.h
index 4c5462d..46ba64c 100644
--- a/arch/sh/include/asm/cacheflush.h
+++ b/arch/sh/include/asm/cacheflush.h
@@ -16,6 +16,7 @@
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_icache_range(start, end)		do { } while (0)
 #define flush_icache_page(vma,pg)		do { } while (0)
diff --git a/arch/sh/include/cpu-common/cpu/cacheflush.h b/arch/sh/include/cpu-common/cpu/cacheflush.h
index c3db00b..bd508bd 100644
--- a/arch/sh/include/cpu-common/cpu/cacheflush.h
+++ b/arch/sh/include/cpu-common/cpu/cacheflush.h
@@ -31,6 +31,7 @@
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/sh/include/cpu-sh2a/cpu/cacheflush.h b/arch/sh/include/cpu-sh2a/cpu/cacheflush.h
index 3d3b920..56c8c88 100644
--- a/arch/sh/include/cpu-sh2a/cpu/cacheflush.h
+++ b/arch/sh/include/cpu-sh2a/cpu/cacheflush.h
@@ -22,6 +22,7 @@
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/sh/include/cpu-sh3/cpu/cacheflush.h b/arch/sh/include/cpu-sh3/cpu/cacheflush.h
index 1ac27aa..e03e964 100644
--- a/arch/sh/include/cpu-sh3/cpu/cacheflush.h
+++ b/arch/sh/include/cpu-sh3/cpu/cacheflush.h
@@ -26,6 +26,7 @@ void flush_cache_mm(struct mm_struct *mm);
 void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
                               unsigned long end);
 void flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn);
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 void flush_dcache_page(struct page *pg);
 void flush_icache_range(unsigned long start, unsigned long end);
 void flush_icache_page(struct vm_area_struct *vma, struct page *page);
diff --git a/arch/sh/include/cpu-sh4/cpu/cacheflush.h b/arch/sh/include/cpu-sh4/cpu/cacheflush.h
index 065306d..1789e3e 100644
--- a/arch/sh/include/cpu-sh4/cpu/cacheflush.h
+++ b/arch/sh/include/cpu-sh4/cpu/cacheflush.h
@@ -24,6 +24,7 @@ void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
 		       unsigned long end);
 void flush_cache_page(struct vm_area_struct *vma, unsigned long addr,
 		      unsigned long pfn);
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 void flush_dcache_page(struct page *pg);
 
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
diff --git a/arch/sh/include/cpu-sh5/cpu/cacheflush.h b/arch/sh/include/cpu-sh5/cpu/cacheflush.h
index 5a11f0b..cd098a3 100644
--- a/arch/sh/include/cpu-sh5/cpu/cacheflush.h
+++ b/arch/sh/include/cpu-sh5/cpu/cacheflush.h
@@ -13,6 +13,7 @@ extern void flush_cache_sigtramp(unsigned long vaddr);
 extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
 			      unsigned long end);
 extern void flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn);
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *pg);
 extern void flush_icache_range(unsigned long start, unsigned long end);
 extern void flush_icache_user_range(struct vm_area_struct *vma,
diff --git a/arch/sparc/include/asm/cacheflush_32.h b/arch/sparc/include/asm/cacheflush_32.h
index 68ac109..2e46877 100644
--- a/arch/sparc/include/asm/cacheflush_32.h
+++ b/arch/sparc/include/asm/cacheflush_32.h
@@ -75,6 +75,7 @@ BTFIXUPDEF_CALL(void, flush_sig_insns, struct mm_struct *, unsigned long)
 
 extern void sparc_flush_page_to_ram(struct page *page);
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 #define flush_dcache_page(page)			sparc_flush_page_to_ram(page)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/sparc/include/asm/cacheflush_64.h b/arch/sparc/include/asm/cacheflush_64.h
index c433217..b953840 100644
--- a/arch/sparc/include/asm/cacheflush_64.h
+++ b/arch/sparc/include/asm/cacheflush_64.h
@@ -37,6 +37,7 @@ extern void flush_dcache_page_all(struct mm_struct *mm, struct page *page);
 #endif
 
 extern void __flush_dcache_range(unsigned long start, unsigned long end);
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *page);
 
 #define flush_icache_page(vma, pg)	do { } while(0)
diff --git a/arch/x86/include/asm/cacheflush.h b/arch/x86/include/asm/cacheflush.h
index e55dfc1..7631500 100644
--- a/arch/x86/include/asm/cacheflush.h
+++ b/arch/x86/include/asm/cacheflush.h
@@ -12,6 +12,7 @@ static inline void flush_cache_range(struct vm_area_struct *vma,
 				     unsigned long start, unsigned long end) { }
 static inline void flush_cache_page(struct vm_area_struct *vma,
 				    unsigned long vmaddr, unsigned long pfn) { }
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 static inline void flush_dcache_page(struct page *page) { }
 static inline void flush_dcache_mmap_lock(struct address_space *mapping) { }
 static inline void flush_dcache_mmap_unlock(struct address_space *mapping) { }
diff --git a/arch/xtensa/include/asm/cacheflush.h b/arch/xtensa/include/asm/cacheflush.h
index b7b8fbe..376cd9d 100644
--- a/arch/xtensa/include/asm/cacheflush.h
+++ b/arch/xtensa/include/asm/cacheflush.h
@@ -101,6 +101,7 @@ static inline void __invalidate_icache_page_alias(unsigned long virt,
 #define flush_cache_vmap(start,end)	flush_cache_all()
 #define flush_cache_vunmap(start,end)	flush_cache_all()
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page*);
 extern void flush_cache_range(struct vm_area_struct*, ulong, ulong);
 extern void flush_cache_page(struct vm_area_struct*, unsigned long, unsigned long);
@@ -114,6 +115,7 @@ extern void flush_cache_page(struct vm_area_struct*, unsigned long, unsigned lon
 #define flush_cache_vmap(start,end)			do { } while (0)
 #define flush_cache_vunmap(start,end)			do { } while (0)
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)				do { } while (0)
 
 #define flush_cache_page(vma,addr,pfn)			do { } while (0)
diff --git a/block/blk-core.c b/block/blk-core.c
index e3299a7..824f822 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -2254,6 +2254,25 @@ void blk_rq_bio_prep(struct request_queue *q, struct request *rq,
 		rq->rq_disk = bio->bi_bdev->bd_disk;
 }
 
+#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
+/**
+ * rq_flush_dcache_pages - Helper function to flush all pages in a request
+ * @rq: the request to be flushed
+ *
+ * Description:
+ *     Flush all pages in @rq.
+ */
+void rq_flush_dcache_pages(struct request *rq)
+{
+	struct req_iterator iter;
+	struct bio_vec* bvec;
+
+	rq_for_each_segment(bvec, rq, iter)
+		flush_dcache_page(bvec->bv_page);
+}
+EXPORT_SYMBOL_GPL(rq_flush_dcache_pages);
+#endif
+
 /**
  * blk_lld_busy - Check if underlying low-level drivers of a device are busy
  * @q : the queue of the device being checked
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
index 7baba40..abddc60 100644
--- a/drivers/mtd/mtd_blkdevs.c
+++ b/drivers/mtd/mtd_blkdevs.c
@@ -68,12 +68,14 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
 		for (; nsect > 0; nsect--, block++, buf += tr->blksize)
 			if (tr->readsect(dev, block, buf))
 				return -EIO;
+		rq_flush_dcache_pages(req);
 		return 0;
 
 	case WRITE:
 		if (!tr->writesect)
 			return -EIO;
 
+		rq_flush_dcache_pages(req);
 		for (; nsect > 0; nsect--, block++, buf += tr->blksize)
 			if (tr->writesect(dev, block, buf))
 				return -EIO;
diff --git a/fs/bio.c b/fs/bio.c
index 7673800..25f79d3 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -1376,6 +1376,18 @@ void bio_check_pages_dirty(struct bio *bio)
 	}
 }
 
+#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
+void bio_flush_dcache_pages(struct bio *bi)
+{
+	int i;
+	struct bio_vec* bvec;
+
+	bio_for_each_segment(bvec, bi, i)
+		flush_dcache_page(bvec->bv_page);
+}
+EXPORT_SYMBOL(bio_flush_dcache_pages);
+#endif
+
 /**
  * bio_endio - end I/O on a bio
  * @bio:	bio
diff --git a/include/linux/bio.h b/include/linux/bio.h
index 2892b71..3bd12dd 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -396,6 +396,18 @@ extern struct bio *bio_copy_kern(struct request_queue *, void *, unsigned int,
 				 gfp_t, int);
 extern void bio_set_pages_dirty(struct bio *bio);
 extern void bio_check_pages_dirty(struct bio *bio);
+
+#ifndef ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
+# error	"You should to define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE for your platform."
+#endif
+#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
+extern void bio_flush_dcache_pages(struct bio *bi);
+#else
+static inline void bio_flush_dcache_pages(struct bio *bi)
+{
+}
+#endif
+
 extern struct bio *bio_copy_user(struct request_queue *, struct rq_map_data *,
 				 unsigned long, unsigned int, int, gfp_t);
 extern struct bio *bio_copy_user_iov(struct request_queue *,
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 69103e0..ce57692 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -740,6 +740,17 @@ struct req_iterator {
 #define rq_iter_last(rq, _iter)					\
 		(_iter.bio->bi_next == NULL && _iter.i == _iter.bio->bi_vcnt-1)
 
+#ifndef ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
+# error	"You should to define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE for your platform."
+#endif
+#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
+extern void rq_flush_dcache_pages(struct request *rq);
+#else
+static inline void rq_flush_dcache_pages(struct request *rq)
+{
+}
+#endif
+
 extern int blk_register_queue(struct gendisk *disk);
 extern void blk_unregister_queue(struct gendisk *disk);
 extern void register_disk(struct gendisk *dev);

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH] mtd: fix mtd_blkdevs problem with caches on some architectures (2.6.31)
  2009-11-22 20:55                       ` Ilya Loginov
@ 2009-11-24 20:48                         ` Andrew Morton
  2009-11-25  1:01                           ` Ilya Loginov
  0 siblings, 1 reply; 18+ messages in thread
From: Andrew Morton @ 2009-11-24 20:48 UTC (permalink / raw)
  To: Ilya Loginov
  Cc: Ingo Molnar, David Woodhouse, linux-kernel, Peter Horton,
	Ed L. Cashin, Jens Axboe

On Sun, 22 Nov 2009 23:55:39 +0300
Ilya Loginov <isloginov@gmail.com> wrote:

> > > I tried this way from the beginning, and to avoid redefinitions I enclose
> > > everything in #if #endif in *.c files. I think it is not very good.
> > > So there are two possibilities.
> > > 
> 
> Ah. I think the first choice is always the best choise. =)
> 
> > In .h:
> > 
> > #if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
> > extern void rq_flush_dcache_pages(struct request *rq);
> > #else
> > static inline void bio_flush_dcache_pages(struct bio *bi)
> > {
> > }
> > #endif
> > 
> > In .c:
> > 	
> > #if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
> > void rq_flush_dcache_pages(struct request *rq)
> > {
> > 	struct req_iterator iter;
> > 	struct bio_vec* bvec;
> > 
> > 	rq_for_each_segment(bvec, rq, iter)
> > 		flush_dcache_page(bvec->bv_page);
> > }
> > EXPORT_SYMBOL(rq_flush_dcache_pages);
> > #endif
> 
> This is 2) =)
> 
> Thanks a lot for your help and comments!
> 
> Signed-off-by: Ilya Loginov <isloginov@gmail.com>

Looks good to me, but...

Patch doesn't vaguely apply to linux-next because of arch/sh changes. 
I was going to fix that but afaict your assertion that sh doesn't
implement flush_dcache_page() appears to be untrue in linux-next and a
bit of thought is needed there.

Also, please provide a nice chagnelog whcih describes the change, and
our reasons for making it.


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] mtd: fix mtd_blkdevs problem with caches on some architectures (2.6.31)
  2009-11-24 20:48                         ` Andrew Morton
@ 2009-11-25  1:01                           ` Ilya Loginov
  0 siblings, 0 replies; 18+ messages in thread
From: Ilya Loginov @ 2009-11-25  1:01 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Ingo Molnar, David Woodhouse, linux-kernel, Peter Horton,
	Ed L. Cashin, Jens Axboe

> Patch doesn't vaguely apply to linux-next because of arch/sh changes. 
> I was going to fix that but afaict your assertion that sh doesn't
> implement flush_dcache_page() appears to be untrue in linux-next and a
> bit of thought is needed there.

	You right. The sh architecture changed in linux-next and scope 
arch was added. I created new patch and tested it on linux-next.
 
> Also, please provide a nice chagnelog whcih describes the change, and
> our reasons for making it.

Mtdblock driver doesn't call flush_dcache_page for pages in request. So,
this cause problem on architectures where icache doesn't fill from dcache
or with dcache aliases. Patch fix this. The ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
symbol was introduced to avoid pointless empty cache-thrashing loops on 
architectures for which flush_dcache_page() is a no-op. Every architecture was
provided with this #define. New functions bio_flush_dcache_pages and
rq_flush_dcache_pages flush pages on architectires where
ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE is equal 1 or do nothing otherwise.

See "fix mtd_blkdevs problem with caches on some architectures" discussion
on LKML for more information.

Signed-off-by: Ilya Loginov <isloginov@gmail.com>
---
 arch/alpha/include/asm/cacheflush.h      |    1 +
 arch/arm/include/asm/cacheflush.h        |    1 +
 arch/avr32/include/asm/cacheflush.h      |    1 +
 arch/blackfin/include/asm/cacheflush.h   |    2 ++
 arch/cris/include/asm/cacheflush.h       |    1 +
 arch/frv/include/asm/cacheflush.h        |    1 +
 arch/h8300/include/asm/cacheflush.h      |    1 +
 arch/ia64/include/asm/cacheflush.h       |    1 +
 arch/m32r/include/asm/cacheflush.h       |    3 +++
 arch/m68k/include/asm/cacheflush_mm.h    |    1 +
 arch/m68k/include/asm/cacheflush_no.h    |    1 +
 arch/microblaze/include/asm/cacheflush.h |    1 +
 arch/mips/include/asm/cacheflush.h       |    1 +
 arch/mn10300/include/asm/cacheflush.h    |    1 +
 arch/parisc/include/asm/cacheflush.h     |    1 +
 arch/powerpc/include/asm/cacheflush.h    |    1 +
 arch/s390/include/asm/cacheflush.h       |    1 +
 arch/score/include/asm/cacheflush.h      |    1 +
 arch/sh/include/asm/cacheflush.h         |    1 +
 arch/sparc/include/asm/cacheflush_32.h   |    1 +
 arch/sparc/include/asm/cacheflush_64.h   |    1 +
 arch/x86/include/asm/cacheflush.h        |    1 +
 arch/xtensa/include/asm/cacheflush.h     |    1 +
 block/blk-core.c                         |   19 +++++++++++++++++++
 drivers/mtd/mtd_blkdevs.c                |    2 ++
 fs/bio.c                                 |   12 ++++++++++++
 include/asm-generic/cacheflush.h         |    1 +
 include/linux/bio.h                      |   12 ++++++++++++
 include/linux/blkdev.h                   |   11 +++++++++++
 29 files changed, 83 insertions(+)

diff --git a/arch/alpha/include/asm/cacheflush.h b/arch/alpha/include/asm/cacheflush.h
index b686cc7..01d71e1 100644
--- a/arch/alpha/include/asm/cacheflush.h
+++ b/arch/alpha/include/asm/cacheflush.h
@@ -9,6 +9,7 @@
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index 9fd6d3a..73eceb8 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -418,6 +418,7 @@ extern void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
  * about to change to user space.  This is the same method as used on SPARC64.
  * See update_mmu_cache for the user space part.
  */
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *);
 
 static inline void __flush_icache_all(void)
diff --git a/arch/avr32/include/asm/cacheflush.h b/arch/avr32/include/asm/cacheflush.h
index 6706747..96e5382 100644
--- a/arch/avr32/include/asm/cacheflush.h
+++ b/arch/avr32/include/asm/cacheflush.h
@@ -107,6 +107,7 @@ extern void flush_icache_page(struct vm_area_struct *vma, struct page *page);
  * do something here, but only for certain configurations.  No such
  * configurations exist at this time.
  */
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(page)		do { } while (0)
 #define flush_dcache_mmap_unlock(page)		do { } while (0)
diff --git a/arch/blackfin/include/asm/cacheflush.h b/arch/blackfin/include/asm/cacheflush.h
index af03a36..417eaac 100644
--- a/arch/blackfin/include/asm/cacheflush.h
+++ b/arch/blackfin/include/asm/cacheflush.h
@@ -68,9 +68,11 @@ do { memcpy(dst, src, len);						\
 #endif
 #if defined(CONFIG_BFIN_EXTMEM_WRITEBACK) || defined(CONFIG_BFIN_L2_WRITEBACK)
 # define flush_dcache_range(start,end)		blackfin_dcache_flush_range((start), (end))
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 # define flush_dcache_page(page)		blackfin_dflush_page(page_address(page))
 #else
 # define flush_dcache_range(start,end)		do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 # define flush_dcache_page(page)		do { } while (0)
 #endif
 
diff --git a/arch/cris/include/asm/cacheflush.h b/arch/cris/include/asm/cacheflush.h
index cf60e3f..36795bc 100644
--- a/arch/cris/include/asm/cacheflush.h
+++ b/arch/cris/include/asm/cacheflush.h
@@ -12,6 +12,7 @@
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/frv/include/asm/cacheflush.h b/arch/frv/include/asm/cacheflush.h
index 432a69e..edbac54 100644
--- a/arch/frv/include/asm/cacheflush.h
+++ b/arch/frv/include/asm/cacheflush.h
@@ -47,6 +47,7 @@ static inline void __flush_cache_all(void)
 }
 
 /* dcache/icache coherency... */
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 #ifdef CONFIG_MMU
 extern void flush_dcache_page(struct page *page);
 #else
diff --git a/arch/h8300/include/asm/cacheflush.h b/arch/h8300/include/asm/cacheflush.h
index 5ffdca2..4cf2df2 100644
--- a/arch/h8300/include/asm/cacheflush.h
+++ b/arch/h8300/include/asm/cacheflush.h
@@ -15,6 +15,7 @@
 #define	flush_cache_dup_mm(mm)		do { } while (0)
 #define	flush_cache_range(vma,a,b)
 #define	flush_cache_page(vma,p,pfn)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define	flush_dcache_page(page)
 #define	flush_dcache_mmap_lock(mapping)
 #define	flush_dcache_mmap_unlock(mapping)
diff --git a/arch/ia64/include/asm/cacheflush.h b/arch/ia64/include/asm/cacheflush.h
index c8ce271..429eefc 100644
--- a/arch/ia64/include/asm/cacheflush.h
+++ b/arch/ia64/include/asm/cacheflush.h
@@ -25,6 +25,7 @@
 #define flush_cache_vmap(start, end)		do { } while (0)
 #define flush_cache_vunmap(start, end)		do { } while (0)
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 #define flush_dcache_page(page)			\
 do {						\
 	clear_bit(PG_arch_1, &(page)->flags);	\
diff --git a/arch/m32r/include/asm/cacheflush.h b/arch/m32r/include/asm/cacheflush.h
index 78587c9..8e8e045 100644
--- a/arch/m32r/include/asm/cacheflush.h
+++ b/arch/m32r/include/asm/cacheflush.h
@@ -12,6 +12,7 @@ extern void _flush_cache_copyback_all(void);
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
@@ -33,6 +34,7 @@ extern void smp_flush_cache_all(void);
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
@@ -46,6 +48,7 @@ extern void smp_flush_cache_all(void);
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/m68k/include/asm/cacheflush_mm.h b/arch/m68k/include/asm/cacheflush_mm.h
index 16bf375..73de7c8 100644
--- a/arch/m68k/include/asm/cacheflush_mm.h
+++ b/arch/m68k/include/asm/cacheflush_mm.h
@@ -128,6 +128,7 @@ static inline void __flush_page_to_ram(void *vaddr)
 	}
 }
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 #define flush_dcache_page(page)		__flush_page_to_ram(page_address(page))
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/m68k/include/asm/cacheflush_no.h b/arch/m68k/include/asm/cacheflush_no.h
index c65f00a..89f1956 100644
--- a/arch/m68k/include/asm/cacheflush_no.h
+++ b/arch/m68k/include/asm/cacheflush_no.h
@@ -12,6 +12,7 @@
 #define flush_cache_range(vma, start, end)	__flush_cache_all()
 #define flush_cache_page(vma, vmaddr)		do { } while (0)
 #define flush_dcache_range(start,len)		__flush_cache_all()
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/microblaze/include/asm/cacheflush.h b/arch/microblaze/include/asm/cacheflush.h
index d3f3f75..1f04b91 100644
--- a/arch/microblaze/include/asm/cacheflush.h
+++ b/arch/microblaze/include/asm/cacheflush.h
@@ -37,6 +37,7 @@
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
 
 #define flush_dcache_range(start, end)	__invalidate_dcache_range(start, end)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/mips/include/asm/cacheflush.h b/arch/mips/include/asm/cacheflush.h
index 03b1d69..40bb9fd 100644
--- a/arch/mips/include/asm/cacheflush.h
+++ b/arch/mips/include/asm/cacheflush.h
@@ -38,6 +38,7 @@ extern void (*flush_cache_range)(struct vm_area_struct *vma,
 extern void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page, unsigned long pfn);
 extern void __flush_dcache_page(struct page *page);
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 static inline void flush_dcache_page(struct page *page)
 {
 	if (cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc)
diff --git a/arch/mn10300/include/asm/cacheflush.h b/arch/mn10300/include/asm/cacheflush.h
index 1a55d61..29e692f 100644
--- a/arch/mn10300/include/asm/cacheflush.h
+++ b/arch/mn10300/include/asm/cacheflush.h
@@ -26,6 +26,7 @@
 #define flush_cache_page(vma, vmaddr, pfn)	do {} while (0)
 #define flush_cache_vmap(start, end)		do {} while (0)
 #define flush_cache_vunmap(start, end)		do {} while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do {} while (0)
 #define flush_dcache_mmap_lock(mapping)		do {} while (0)
 #define flush_dcache_mmap_unlock(mapping)	do {} while (0)
diff --git a/arch/parisc/include/asm/cacheflush.h b/arch/parisc/include/asm/cacheflush.h
index 7243951..7a73b61 100644
--- a/arch/parisc/include/asm/cacheflush.h
+++ b/arch/parisc/include/asm/cacheflush.h
@@ -42,6 +42,7 @@ void flush_cache_mm(struct mm_struct *mm);
 #define flush_cache_vmap(start, end)		flush_cache_all()
 #define flush_cache_vunmap(start, end)		flush_cache_all()
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *page);
 
 #define flush_dcache_mmap_lock(mapping) \
diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h
index ba667a3..ab9e402 100644
--- a/arch/powerpc/include/asm/cacheflush.h
+++ b/arch/powerpc/include/asm/cacheflush.h
@@ -25,6 +25,7 @@
 #define flush_cache_vmap(start, end)		do { } while (0)
 #define flush_cache_vunmap(start, end)		do { } while (0)
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *page);
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/s390/include/asm/cacheflush.h b/arch/s390/include/asm/cacheflush.h
index 49d5af9..405cc97 100644
--- a/arch/s390/include/asm/cacheflush.h
+++ b/arch/s390/include/asm/cacheflush.h
@@ -10,6 +10,7 @@
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/score/include/asm/cacheflush.h b/arch/score/include/asm/cacheflush.h
index 07cc8fc..caaba24 100644
--- a/arch/score/include/asm/cacheflush.h
+++ b/arch/score/include/asm/cacheflush.h
@@ -16,6 +16,7 @@ extern void flush_icache_range(unsigned long start, unsigned long end);
 extern void flush_dcache_range(unsigned long start, unsigned long end);
 
 #define flush_cache_dup_mm(mm)			do {} while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do {} while (0)
 #define flush_dcache_mmap_lock(mapping)		do {} while (0)
 #define flush_dcache_mmap_unlock(mapping)	do {} while (0)
diff --git a/arch/sh/include/asm/cacheflush.h b/arch/sh/include/asm/cacheflush.h
index c29918f..dda96eb 100644
--- a/arch/sh/include/asm/cacheflush.h
+++ b/arch/sh/include/asm/cacheflush.h
@@ -42,6 +42,7 @@ extern void flush_cache_page(struct vm_area_struct *vma,
 				unsigned long addr, unsigned long pfn);
 extern void flush_cache_range(struct vm_area_struct *vma,
 				 unsigned long start, unsigned long end);
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *page);
 extern void flush_icache_range(unsigned long start, unsigned long end);
 extern void flush_icache_page(struct vm_area_struct *vma,
diff --git a/arch/sparc/include/asm/cacheflush_32.h b/arch/sparc/include/asm/cacheflush_32.h
index 68ac109..2e46877 100644
--- a/arch/sparc/include/asm/cacheflush_32.h
+++ b/arch/sparc/include/asm/cacheflush_32.h
@@ -75,6 +75,7 @@ BTFIXUPDEF_CALL(void, flush_sig_insns, struct mm_struct *, unsigned long)
 
 extern void sparc_flush_page_to_ram(struct page *page);
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 #define flush_dcache_page(page)			sparc_flush_page_to_ram(page)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/arch/sparc/include/asm/cacheflush_64.h b/arch/sparc/include/asm/cacheflush_64.h
index c433217..b953840 100644
--- a/arch/sparc/include/asm/cacheflush_64.h
+++ b/arch/sparc/include/asm/cacheflush_64.h
@@ -37,6 +37,7 @@ extern void flush_dcache_page_all(struct mm_struct *mm, struct page *page);
 #endif
 
 extern void __flush_dcache_range(unsigned long start, unsigned long end);
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *page);
 
 #define flush_icache_page(vma, pg)	do { } while(0)
diff --git a/arch/x86/include/asm/cacheflush.h b/arch/x86/include/asm/cacheflush.h
index eebb2cd..634c40a 100644
--- a/arch/x86/include/asm/cacheflush.h
+++ b/arch/x86/include/asm/cacheflush.h
@@ -12,6 +12,7 @@ static inline void flush_cache_range(struct vm_area_struct *vma,
 				     unsigned long start, unsigned long end) { }
 static inline void flush_cache_page(struct vm_area_struct *vma,
 				    unsigned long vmaddr, unsigned long pfn) { }
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 static inline void flush_dcache_page(struct page *page) { }
 static inline void flush_dcache_mmap_lock(struct address_space *mapping) { }
 static inline void flush_dcache_mmap_unlock(struct address_space *mapping) { }
diff --git a/arch/xtensa/include/asm/cacheflush.h b/arch/xtensa/include/asm/cacheflush.h
index b7b8fbe..a508f2f 100644
--- a/arch/xtensa/include/asm/cacheflush.h
+++ b/arch/xtensa/include/asm/cacheflush.h
@@ -101,6 +101,7 @@ static inline void __invalidate_icache_page_alias(unsigned long virt,
 #define flush_cache_vmap(start,end)	flush_cache_all()
 #define flush_cache_vunmap(start,end)	flush_cache_all()
 
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page*);
 extern void flush_cache_range(struct vm_area_struct*, ulong, ulong);
 extern void flush_cache_page(struct vm_area_struct*, unsigned long, unsigned long);
diff --git a/block/blk-core.c b/block/blk-core.c
index 71da511..ae5de91 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -2358,6 +2358,25 @@ void blk_rq_bio_prep(struct request_queue *q, struct request *rq,
 		rq->rq_disk = bio->bi_bdev->bd_disk;
 }
 
+#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
+/**
+ * rq_flush_dcache_pages - Helper function to flush all pages in a request
+ * @rq: the request to be flushed
+ *
+ * Description:
+ *     Flush all pages in @rq.
+ */
+void rq_flush_dcache_pages(struct request *rq)
+{
+	struct req_iterator iter;
+	struct bio_vec* bvec;
+
+	rq_for_each_segment(bvec, rq, iter)
+		flush_dcache_page(bvec->bv_page);
+}
+EXPORT_SYMBOL_GPL(rq_flush_dcache_pages);
+#endif
+
 /**
  * blk_lld_busy - Check if underlying low-level drivers of a device are busy
  * @q : the queue of the device being checked
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
index b76d6e5..1ab47d5 100644
--- a/drivers/mtd/mtd_blkdevs.c
+++ b/drivers/mtd/mtd_blkdevs.c
@@ -59,12 +59,14 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
 		for (; nsect > 0; nsect--, block++, buf += tr->blksize)
 			if (tr->readsect(dev, block, buf))
 				return -EIO;
+		rq_flush_dcache_pages(req);
 		return 0;
 
 	case WRITE:
 		if (!tr->writesect)
 			return -EIO;
 
+		rq_flush_dcache_pages(req);
 		for (; nsect > 0; nsect--, block++, buf += tr->blksize)
 			if (tr->writesect(dev, block, buf))
 				return -EIO;
diff --git a/fs/bio.c b/fs/bio.c
index 2bd671a..ca1245c 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -1393,6 +1393,18 @@ void bio_check_pages_dirty(struct bio *bio)
 	}
 }
 
+#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
+void bio_flush_dcache_pages(struct bio *bi)
+{
+	int i;
+	struct bio_vec* bvec;
+
+	bio_for_each_segment(bvec, bi, i)
+		flush_dcache_page(bvec->bv_page);
+}
+EXPORT_SYMBOL(bio_flush_dcache_pages);
+#endif
+
 /**
  * bio_endio - end I/O on a bio
  * @bio:	bio
diff --git a/include/asm-generic/cacheflush.h b/include/asm-generic/cacheflush.h
index ba4ec39..57b5c3c 100644
--- a/include/asm-generic/cacheflush.h
+++ b/include/asm-generic/cacheflush.h
@@ -13,6 +13,7 @@
 #define flush_cache_dup_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
diff --git a/include/linux/bio.h b/include/linux/bio.h
index 474792b..5a81c8e 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -391,6 +391,18 @@ extern struct bio *bio_copy_kern(struct request_queue *, void *, unsigned int,
 				 gfp_t, int);
 extern void bio_set_pages_dirty(struct bio *bio);
 extern void bio_check_pages_dirty(struct bio *bio);
+
+#ifndef ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
+# error	"You should to define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE for your platform."
+#endif
+#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
+extern void bio_flush_dcache_pages(struct bio *bi);
+#else
+static inline void bio_flush_dcache_pages(struct bio *bi)
+{
+}
+#endif
+
 extern struct bio *bio_copy_user(struct request_queue *, struct rq_map_data *,
 				 unsigned long, unsigned int, int, gfp_t);
 extern struct bio *bio_copy_user_iov(struct request_queue *,
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 1cc0297..099a2db 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -752,6 +752,17 @@ struct req_iterator {
 #define rq_iter_last(rq, _iter)					\
 		(_iter.bio->bi_next == NULL && _iter.i == _iter.bio->bi_vcnt-1)
 
+#ifndef ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
+# error	"You should to define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE for your platform."
+#endif
+#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
+extern void rq_flush_dcache_pages(struct request *rq);
+#else
+static inline void rq_flush_dcache_pages(struct request *rq)
+{
+}
+#endif
+
 extern int blk_register_queue(struct gendisk *disk);
 extern void blk_unregister_queue(struct gendisk *disk);
 extern void register_disk(struct gendisk *dev);

^ permalink raw reply related	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2009-11-25  1:01 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-11-18 14:08 [PATCH] mtd: fix mtd_blkdevs problem with caches on some architectures (2.6.31) Ilya Loginov
2009-11-21  0:37 ` Andrew Morton
2009-11-21 14:04   ` Ilya Loginov
2009-11-21 17:54     ` Andrew Morton
2009-11-21 23:11       ` Ilya Loginov
2009-11-21 23:26         ` Andrew Morton
2009-11-21 23:36           ` Ilya Loginov
2009-11-22  9:46           ` Ilya Loginov
2009-11-22  9:53             ` David Woodhouse
2009-11-22 18:49               ` Ilya Loginov
2009-11-22 13:29             ` Ingo Molnar
2009-11-22 13:55               ` Ilya Loginov
2009-11-22 18:48                 ` Andrew Morton
2009-11-22 19:18                   ` Ilya Loginov
2009-11-22 19:51                     ` Andrew Morton
2009-11-22 20:55                       ` Ilya Loginov
2009-11-24 20:48                         ` Andrew Morton
2009-11-25  1:01                           ` Ilya Loginov

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.