Skip to content

Commit d2b2c6d

Browse files
larperaxistorvalds
authored andcommitted
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 c017780 ("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/[email protected] Fixes: 97ee052 ("flush cache before installing new page at migraton") Signed-off-by: Lars Persson <[email protected]> Reviewed-by: Paul Burton <[email protected]> Acked-by: Mel Gorman <[email protected]> Cc: Ralf Baechle <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 0bc9f5d commit d2b2c6d

File tree

1 file changed

+8
-3
lines changed

1 file changed

+8
-3
lines changed

mm/migrate.c

+8-3
Original file line numberDiff line numberDiff line change
@@ -248,10 +248,8 @@ static bool remove_migration_pte(struct page *page, struct vm_area_struct *vma,
248248
pte = swp_entry_to_pte(entry);
249249
} else if (is_device_public_page(new)) {
250250
pte = pte_mkdevmap(pte);
251-
flush_dcache_page(new);
252251
}
253-
} else
254-
flush_dcache_page(new);
252+
}
255253

256254
#ifdef CONFIG_HUGETLB_PAGE
257255
if (PageHuge(new)) {
@@ -995,6 +993,13 @@ static int move_to_new_page(struct page *newpage, struct page *page,
995993
*/
996994
if (!PageMappingFlags(page))
997995
page->mapping = NULL;
996+
997+
if (unlikely(is_zone_device_page(newpage))) {
998+
if (is_device_public_page(newpage))
999+
flush_dcache_page(newpage);
1000+
} else
1001+
flush_dcache_page(newpage);
1002+
9981003
}
9991004
out:
10001005
return rc;

0 commit comments

Comments
 (0)