diff mbox

[V3,2/2] ARM: Handle user space mapped pages in flush_kernel_dcache_page

Message ID CACVXFVPOuabwAa1VDmSnfDG=M-1Df02_kpbm0UVAVctCAB-U4Q@mail.gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Ming Lei May 4, 2013, 8:21 a.m. UTC
On Fri, May 3, 2013 at 6:02 PM, Catalin Marinas <catalin.marinas@arm.com> wrote:
>>
>> I assume that you inhibited the call to flush_dcache_page() in
>> __get_user_pages() for anon pages.  Otherwise, you will be flooded
>> with warnings.
>
> I haven't done any stress testing so I don't think I hit this code path,
> so no warning. But yes, it should have triggered. Anyway, in this case
> flush_dcache_page() should have just ignored (clearing PG_arch_1 is
> harmless anyway if we also ignore this bit in __sync_icache_dcache for
> non-aliasing caches).

Yes, maybe we can do a little optimization for O_DIRECT since no
dcache alias and I/D coherency problem in this case on ARMv7, how
about below change?


Thanks,

Comments

Catalin Marinas May 8, 2013, 3:08 p.m. UTC | #1
On Sat, May 04, 2013 at 09:21:27AM +0100, Ming Lei wrote:
> On Fri, May 3, 2013 at 6:02 PM, Catalin Marinas <catalin.marinas@arm.com> wrote:
> >>
> >> I assume that you inhibited the call to flush_dcache_page() in
> >> __get_user_pages() for anon pages.  Otherwise, you will be flooded
> >> with warnings.
> >
> > I haven't done any stress testing so I don't think I hit this code path,
> > so no warning. But yes, it should have triggered. Anyway, in this case
> > flush_dcache_page() should have just ignored (clearing PG_arch_1 is
> > harmless anyway if we also ignore this bit in __sync_icache_dcache for
> > non-aliasing caches).
> 
> Yes, maybe we can do a little optimization for O_DIRECT since no
> dcache alias and I/D coherency problem in this case on ARMv7, how
> about below change?
> 
> diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
> index 1c8f7f5..962a657 100644
> --- a/arch/arm/mm/flush.c
> +++ b/arch/arm/mm/flush.c
> @@ -287,6 +287,8 @@ void flush_dcache_page(struct page *page)
>  	    mapping && !mapping_mapped(mapping))
>  		clear_bit(PG_dcache_clean, &page->flags);
>  	else {
> +		if (!mapping && cache_is_vipt_nonaliasing())
> +			return;
>  		__flush_dcache_page(mapping, page);
>  		if (mapping && cache_is_vivt())
>  			__flush_dcache_aliases(mapping, page);

I wonder whether we could move the:

	if (!mapping)
		return

at the top of this function, IOW don't touch any anonymous pages. Would
anything be broken (apart from wrong API use)?
Russell King - ARM Linux May 8, 2013, 6:43 p.m. UTC | #2
On Wed, May 08, 2013 at 04:08:00PM +0100, Catalin Marinas wrote:
> On Sat, May 04, 2013 at 09:21:27AM +0100, Ming Lei wrote:
> > On Fri, May 3, 2013 at 6:02 PM, Catalin Marinas <catalin.marinas@arm.com> wrote:
> > >>
> > >> I assume that you inhibited the call to flush_dcache_page() in
> > >> __get_user_pages() for anon pages.  Otherwise, you will be flooded
> > >> with warnings.
> > >
> > > I haven't done any stress testing so I don't think I hit this code path,
> > > so no warning. But yes, it should have triggered. Anyway, in this case
> > > flush_dcache_page() should have just ignored (clearing PG_arch_1 is
> > > harmless anyway if we also ignore this bit in __sync_icache_dcache for
> > > non-aliasing caches).
> > 
> > Yes, maybe we can do a little optimization for O_DIRECT since no
> > dcache alias and I/D coherency problem in this case on ARMv7, how
> > about below change?
> > 
> > diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
> > index 1c8f7f5..962a657 100644
> > --- a/arch/arm/mm/flush.c
> > +++ b/arch/arm/mm/flush.c
> > @@ -287,6 +287,8 @@ void flush_dcache_page(struct page *page)
> >  	    mapping && !mapping_mapped(mapping))
> >  		clear_bit(PG_dcache_clean, &page->flags);
> >  	else {
> > +		if (!mapping && cache_is_vipt_nonaliasing())
> > +			return;
> >  		__flush_dcache_page(mapping, page);
> >  		if (mapping && cache_is_vivt())
> >  			__flush_dcache_aliases(mapping, page);
> 
> I wonder whether we could move the:
> 
> 	if (!mapping)
> 		return
> 
> at the top of this function, IOW don't touch any anonymous pages. Would
> anything be broken (apart from wrong API use)?

I suspect you may be missing something - and I suggest reading the Sparc
version, which is where this PG_arch_1 stuff was first dreamed up (by
DaveM).

Are you positive that this path can be eliminated?  Totally sure?  Have
you checked the arg/env pages that fs/exec.c and the binfmt's insert into
the new process?

The comments against the Sparc version suggest that the "else" clause
is necessary ensure that case is adequately covered.
Simon Baatz May 8, 2013, 7:31 p.m. UTC | #3
Hi Russel,

On Wed, May 08, 2013 at 07:43:54PM +0100, Russell King - ARM Linux wrote:
> On Wed, May 08, 2013 at 04:08:00PM +0100, Catalin Marinas wrote:
> > On Sat, May 04, 2013 at 09:21:27AM +0100, Ming Lei wrote:
> > > On Fri, May 3, 2013 at 6:02 PM, Catalin Marinas <catalin.marinas@arm.com> wrote:
> > > >>
> > > >> I assume that you inhibited the call to flush_dcache_page() in
> > > >> __get_user_pages() for anon pages.  Otherwise, you will be flooded
> > > >> with warnings.
> > > >
> > > > I haven't done any stress testing so I don't think I hit this code path,
> > > > so no warning. But yes, it should have triggered. Anyway, in this case
> > > > flush_dcache_page() should have just ignored (clearing PG_arch_1 is
> > > > harmless anyway if we also ignore this bit in __sync_icache_dcache for
> > > > non-aliasing caches).
> > > 
> > > Yes, maybe we can do a little optimization for O_DIRECT since no
> > > dcache alias and I/D coherency problem in this case on ARMv7, how
> > > about below change?
> > > 
> > > diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
> > > index 1c8f7f5..962a657 100644
> > > --- a/arch/arm/mm/flush.c
> > > +++ b/arch/arm/mm/flush.c
> > > @@ -287,6 +287,8 @@ void flush_dcache_page(struct page *page)
> > >  	    mapping && !mapping_mapped(mapping))
> > >  		clear_bit(PG_dcache_clean, &page->flags);
> > >  	else {
> > > +		if (!mapping && cache_is_vipt_nonaliasing())
> > > +			return;
> > >  		__flush_dcache_page(mapping, page);
> > >  		if (mapping && cache_is_vivt())
> > >  			__flush_dcache_aliases(mapping, page);
> > 
> > I wonder whether we could move the:
> > 
> > 	if (!mapping)
> > 		return
> > 
> > at the top of this function, IOW don't touch any anonymous pages. Would
> > anything be broken (apart from wrong API use)?
> 
> I suspect you may be missing something - and I suggest reading the Sparc
> version, which is where this PG_arch_1 stuff was first dreamed up (by
> DaveM).
> 
> Are you positive that this path can be eliminated?  Totally sure?  Have
> you checked the arg/env pages that fs/exec.c and the binfmt's insert into
> the new process?
> 
> The comments against the Sparc version suggest that the "else" clause
> is necessary ensure that case is adequately covered.

At least the fs/exec.c and the binfmt stuff use
flush_kernel_dcache_page() for 5 years or so now (see commit b6a2fe). 
Which makes sense, since flush_dcache_page() is not supposed to
handle anon pages anyway.

The problem are the tons of flush_dcache_page() uses that wrongly
assume that no anon pages need to be handled (e.g. 
drivers/block/loop.c and crypto/scatterwalk.c just to name two).

- Simon
Catalin Marinas May 8, 2013, 9:13 p.m. UTC | #4
On Wed, May 08, 2013 at 08:31:30PM +0100, Simon Baatz wrote:
> On Wed, May 08, 2013 at 07:43:54PM +0100, Russell King - ARM Linux wrote:
> > On Wed, May 08, 2013 at 04:08:00PM +0100, Catalin Marinas wrote:
> > > On Sat, May 04, 2013 at 09:21:27AM +0100, Ming Lei wrote:
> > > > On Fri, May 3, 2013 at 6:02 PM, Catalin Marinas <catalin.marinas@arm.com> wrote:
> > > > >>
> > > > >> I assume that you inhibited the call to flush_dcache_page() in
> > > > >> __get_user_pages() for anon pages.  Otherwise, you will be flooded
> > > > >> with warnings.
> > > > >
> > > > > I haven't done any stress testing so I don't think I hit this code path,
> > > > > so no warning. But yes, it should have triggered. Anyway, in this case
> > > > > flush_dcache_page() should have just ignored (clearing PG_arch_1 is
> > > > > harmless anyway if we also ignore this bit in __sync_icache_dcache for
> > > > > non-aliasing caches).
> > > > 
> > > > Yes, maybe we can do a little optimization for O_DIRECT since no
> > > > dcache alias and I/D coherency problem in this case on ARMv7, how
> > > > about below change?
> > > > 
> > > > diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
> > > > index 1c8f7f5..962a657 100644
> > > > --- a/arch/arm/mm/flush.c
> > > > +++ b/arch/arm/mm/flush.c
> > > > @@ -287,6 +287,8 @@ void flush_dcache_page(struct page *page)
> > > >  	    mapping && !mapping_mapped(mapping))
> > > >  		clear_bit(PG_dcache_clean, &page->flags);
> > > >  	else {
> > > > +		if (!mapping && cache_is_vipt_nonaliasing())
> > > > +			return;
> > > >  		__flush_dcache_page(mapping, page);
> > > >  		if (mapping && cache_is_vivt())
> > > >  			__flush_dcache_aliases(mapping, page);
> > > 
> > > I wonder whether we could move the:
> > > 
> > > 	if (!mapping)
> > > 		return
> > > 
> > > at the top of this function, IOW don't touch any anonymous pages. Would
> > > anything be broken (apart from wrong API use)?
> > 
> > I suspect you may be missing something - and I suggest reading the Sparc
> > version, which is where this PG_arch_1 stuff was first dreamed up (by
> > DaveM).
> > 
> > Are you positive that this path can be eliminated?  Totally sure?  Have
> > you checked the arg/env pages that fs/exec.c and the binfmt's insert into
> > the new process?
> > 
> > The comments against the Sparc version suggest that the "else" clause
> > is necessary ensure that case is adequately covered.
> 
> At least the fs/exec.c and the binfmt stuff use
> flush_kernel_dcache_page() for 5 years or so now (see commit b6a2fe). 
> Which makes sense, since flush_dcache_page() is not supposed to
> handle anon pages anyway.

Indeed, the sparc comment on arg pages no longer applies. It was also
more of an optimisation which I'm not convinced it would have saved
anything on ARM.
Ming Lei May 9, 2013, 1:52 a.m. UTC | #5
On Wed, May 8, 2013 at 11:08 PM, Catalin Marinas
<catalin.marinas@arm.com> wrote:
> On Sat, May 04, 2013 at 09:21:27AM +0100, Ming Lei wrote:
>> On Fri, May 3, 2013 at 6:02 PM, Catalin Marinas <catalin.marinas@arm.com> wrote:
>> >>
>> >> I assume that you inhibited the call to flush_dcache_page() in
>> >> __get_user_pages() for anon pages.  Otherwise, you will be flooded
>> >> with warnings.
>> >
>> > I haven't done any stress testing so I don't think I hit this code path,
>> > so no warning. But yes, it should have triggered. Anyway, in this case
>> > flush_dcache_page() should have just ignored (clearing PG_arch_1 is
>> > harmless anyway if we also ignore this bit in __sync_icache_dcache for
>> > non-aliasing caches).
>>
>> Yes, maybe we can do a little optimization for O_DIRECT since no
>> dcache alias and I/D coherency problem in this case on ARMv7, how
>> about below change?
>>
>> diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
>> index 1c8f7f5..962a657 100644
>> --- a/arch/arm/mm/flush.c
>> +++ b/arch/arm/mm/flush.c
>> @@ -287,6 +287,8 @@ void flush_dcache_page(struct page *page)
>>           mapping && !mapping_mapped(mapping))
>>               clear_bit(PG_dcache_clean, &page->flags);
>>       else {
>> +             if (!mapping && cache_is_vipt_nonaliasing())
>> +                     return;
>>               __flush_dcache_page(mapping, page);
>>               if (mapping && cache_is_vivt())
>>                       __flush_dcache_aliases(mapping, page);
>
> I wonder whether we could move the:
>
>         if (!mapping)
>                 return
>
> at the top of this function, IOW don't touch any anonymous pages. Would
> anything be broken (apart from wrong API use)?

In case of O_DIRECT, the anonymous page may be shared, so looks it
should be flushed for vipt_aliasing cache.

Catalin, btw, would you mind give comments on the patch below(it might
be a 'fix' on one commit you submitted)?

      http://marc.info/?l=linux-arm-kernel&m=136757247311694&w=2

Thanks
Simon Baatz May 11, 2013, 6:27 a.m. UTC | #6
On Sat, May 04, 2013 at 04:21:27PM +0800, Ming Lei wrote:
> On Fri, May 3, 2013 at 6:02 PM, Catalin Marinas <catalin.marinas@arm.com> wrote:
> >>
> >> I assume that you inhibited the call to flush_dcache_page() in
> >> __get_user_pages() for anon pages.  Otherwise, you will be flooded
> >> with warnings.
> >
> > I haven't done any stress testing so I don't think I hit this code path,
> > so no warning. But yes, it should have triggered. Anyway, in this case
> > flush_dcache_page() should have just ignored (clearing PG_arch_1 is
> > harmless anyway if we also ignore this bit in __sync_icache_dcache for
> > non-aliasing caches).
> 
> Yes, maybe we can do a little optimization for O_DIRECT since no
> dcache alias and I/D coherency problem in this case on ARMv7, how
> about below change?
> 
> diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
> index 1c8f7f5..962a657 100644
> --- a/arch/arm/mm/flush.c
> +++ b/arch/arm/mm/flush.c
> @@ -287,6 +287,8 @@ void flush_dcache_page(struct page *page)
>  	    mapping && !mapping_mapped(mapping))
>  		clear_bit(PG_dcache_clean, &page->flags);
>  	else {
> +		if (!mapping && cache_is_vipt_nonaliasing())
> +			return;
>  		__flush_dcache_page(mapping, page);
>  		if (mapping && cache_is_vivt())
>  			__flush_dcache_aliases(mapping, page);
> 

Yes, this should not be needed. However, I seem to get funny pixel
errors on an Exynos 5 based Chromebook when not flushing in this
case.  Strange.  This is not on a mainline kernel, I will need to
have a look what happens here.


- Simon
Ming Lei May 13, 2013, 3:12 a.m. UTC | #7
On Sat, May 11, 2013 at 2:27 PM, Simon Baatz <gmbnomis@gmail.com> wrote:
> On Sat, May 04, 2013 at 04:21:27PM +0800, Ming Lei wrote:
>> On Fri, May 3, 2013 at 6:02 PM, Catalin Marinas <catalin.marinas@arm.com> wrote:
>> >>
>> >> I assume that you inhibited the call to flush_dcache_page() in
>> >> __get_user_pages() for anon pages.  Otherwise, you will be flooded
>> >> with warnings.
>> >
>> > I haven't done any stress testing so I don't think I hit this code path,
>> > so no warning. But yes, it should have triggered. Anyway, in this case
>> > flush_dcache_page() should have just ignored (clearing PG_arch_1 is
>> > harmless anyway if we also ignore this bit in __sync_icache_dcache for
>> > non-aliasing caches).
>>
>> Yes, maybe we can do a little optimization for O_DIRECT since no
>> dcache alias and I/D coherency problem in this case on ARMv7, how
>> about below change?
>>
>> diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
>> index 1c8f7f5..962a657 100644
>> --- a/arch/arm/mm/flush.c
>> +++ b/arch/arm/mm/flush.c
>> @@ -287,6 +287,8 @@ void flush_dcache_page(struct page *page)
>>           mapping && !mapping_mapped(mapping))
>>               clear_bit(PG_dcache_clean, &page->flags);
>>       else {
>> +             if (!mapping && cache_is_vipt_nonaliasing())
>> +                     return;
>>               __flush_dcache_page(mapping, page);
>>               if (mapping && cache_is_vivt())
>>                       __flush_dcache_aliases(mapping, page);
>>
>
> Yes, this should not be needed. However, I seem to get funny pixel
> errors on an Exynos 5 based Chromebook when not flushing in this
> case.  Strange.  This is not on a mainline kernel, I will need to
> have a look what happens here.

Yes, it is a bit strange, not sure how flush_dcache_page() is used
in memory mapped by mmap.(suppose the display buffer is mmaped)

I test O_DIRECT writing to USB mass storage with the patch, looks
the data written is correct.

[tom]$dd if=/mnt/nfs/test/usb/qieteing-512M.rmvb
of=/mnt/usb/tests/qieteing-512M.rmvb oflag=direct,sync bs=512M count=1
1+0 records in
1+0 records out
536870912 bytes (537 MB) copied, 111.631 s, 4.8 MB/s

#echo 3 > /proc/sys/vm/drop_caches

[tom]$cd /mnt/usb/tests/
[tom]$md5sum -c /mnt/nfs/test/usb/qieteing-512M.rmvb.md5
qieteing-512M.rmvb: OK


Thanks,
diff mbox

Patch

diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
index 1c8f7f5..962a657 100644
--- a/arch/arm/mm/flush.c
+++ b/arch/arm/mm/flush.c
@@ -287,6 +287,8 @@  void flush_dcache_page(struct page *page)
 	    mapping && !mapping_mapped(mapping))
 		clear_bit(PG_dcache_clean, &page->flags);
 	else {
+		if (!mapping && cache_is_vipt_nonaliasing())
+			return;
 		__flush_dcache_page(mapping, page);
 		if (mapping && cache_is_vivt())
 			__flush_dcache_aliases(mapping, page);