@@ -126,8 +126,10 @@ void __update_cache(struct vm_area_struct *vma,
{
struct page *page;
unsigned long pfn = pte_pfn(pte);
+ /* flush any dirty data page before using it as a code page */
+ int exec = (vma != NULL) ? (vma->vm_flags & VM_EXEC) : 1;
- if (!boot_cpu_data.dcache.n_aliases)
+ if (!boot_cpu_data.dcache.n_aliases && !exec)
return;
page = pfn_to_page(pfn);
@@ -136,7 +138,7 @@ void __update_cache(struct vm_area_struct *vma,
if (dirty) {
unsigned long addr = (unsigned long)page_address(page);
- if (pages_do_alias(addr, address & PAGE_MASK))
+ if (exec || pages_do_alias(addr, address & PAGE_MASK))
__flush_purge_region((void *)addr, PAGE_SIZE);
}
}
Best regards,
Markus Pietrek
-----Ursprüngliche Nachricht-----
Von: Matt Fleming [mailto:matt@console-pimps.org]
Gesendet: Dienstag, 22. Dezember 2009 17:52
An: Pietrek, Markus
Cc: linux-sh@vger.kernel.org
Betreff: Re: Probably cache synchronization issue on SH7723
On Tue, Dec 22, 2009 at 05:18:16PM +0100, Pietrek, Markus wrote:
> Hi,
>
> Lacking some understanding of the caching system I'm not sure why in
> update_cache() some dirty pages are skipped. The following patch fixes
> my problem, but I'm not sure about any negative side effects.
Interesting! Good investigative work.
It's an optimisation so that we don't flush the dcache more than we need
to. There shouldn't be any negative side effects of your patch, it's
just a bit inefficient.
Having looked at the MIPS __update_cache() function I'm wondering if the
bug is that we should be flushing the cache if the page is executable.
Could you try this patch?
@@ -126,8 +126,9 @@ void __update_cache(struct vm_area_struct *vma,
{
struct page *page;
unsigned long pfn = pte_pfn(pte);
+ int exec = (vma->vm_flags & VM_EXEC);
- if (!boot_cpu_data.dcache.n_aliases)
+ if (!boot_cpu_data.dcache.n_aliases && !exec)
return;
page = pfn_to_page(pfn);
@@ -136,7 +137,7 @@ void __update_cache(struct vm_area_struct *vma,
if (dirty) {
unsigned long addr = (unsigned long)page_address(page);
- if (pages_do_alias(addr, address & PAGE_MASK))
+ if (exec || pages_do_alias(addr, address & PAGE_MASK))
__flush_purge_region((void *)addr, PAGE_SIZE);
}
}