Commit d2b2c6dd authored by Lars Persson's avatar Lars Persson Committed by Linus Torvalds

mm/migrate.c: add missing flush_dcache_page for non-mapped page migrate

Our MIPS 1004Kc SoCs were seeing random userspace crashes with SIGILL
and SIGSEGV that could not be traced back to a userspace code bug.  They
had all the magic signs of an I/D cache coherency issue.

Now recently we noticed that the /proc/sys/vm/compact_memory interface
was quite efficient at provoking this class of userspace crashes.

Studying the code in mm/migrate.c there is a distinction made between
migrating a page that is mapped at the instant of migration and one that
is not mapped.  Our problem turned out to be the non-mapped pages.

For the non-mapped page the code performs a copy of the page content and
all relevant meta-data of the page without doing the required D-cache
maintenance.  This leaves dirty data in the D-cache of the CPU and on
the 1004K cores this data is not visible to the I-cache.  A subsequent
page-fault that triggers a mapping of the page will happily serve the
process with potentially stale code.

What about ARM then, this bug should have seen greater exposure? Well
ARM became immune to this flaw back in 2010, see commit c0177800
("ARM: 6379/1: Assume new page cache pages have dirty D-cache").

My proposed fix moves the D-cache maintenance inside move_to_new_page to
make it common for both cases.

Link: http://lkml.kernel.org/r/20190315083502.11849-1-larper@axis.com
Fixes: 97ee0524 ("flush cache before installing new page at migraton")
Signed-off-by: default avatarLars Persson <larper@axis.com>
Reviewed-by: default avatarPaul Burton <paul.burton@mips.com>
Acked-by: default avatarMel Gorman <mgorman@techsingularity.net>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 0bc9f5d1
...@@ -248,10 +248,8 @@ static bool remove_migration_pte(struct page *page, struct vm_area_struct *vma, ...@@ -248,10 +248,8 @@ static bool remove_migration_pte(struct page *page, struct vm_area_struct *vma,
pte = swp_entry_to_pte(entry); pte = swp_entry_to_pte(entry);
} else if (is_device_public_page(new)) { } else if (is_device_public_page(new)) {
pte = pte_mkdevmap(pte); pte = pte_mkdevmap(pte);
flush_dcache_page(new);
} }
} else }
flush_dcache_page(new);
#ifdef CONFIG_HUGETLB_PAGE #ifdef CONFIG_HUGETLB_PAGE
if (PageHuge(new)) { if (PageHuge(new)) {
...@@ -995,6 +993,13 @@ static int move_to_new_page(struct page *newpage, struct page *page, ...@@ -995,6 +993,13 @@ static int move_to_new_page(struct page *newpage, struct page *page,
*/ */
if (!PageMappingFlags(page)) if (!PageMappingFlags(page))
page->mapping = NULL; page->mapping = NULL;
if (unlikely(is_zone_device_page(newpage))) {
if (is_device_public_page(newpage))
flush_dcache_page(newpage);
} else
flush_dcache_page(newpage);
} }
out: out:
return rc; return rc;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment