| From d2b2c6dd227ba5b8a802858748ec9a780cb75b47 Mon Sep 17 00:00:00 2001 |
| From: Lars Persson <lars.persson@axis.com> |
| Date: Thu, 28 Mar 2019 20:44:28 -0700 |
| Subject: mm/migrate.c: add missing flush_dcache_page for non-mapped page migrate |
| |
| From: Lars Persson <lars.persson@axis.com> |
| |
| commit d2b2c6dd227ba5b8a802858748ec9a780cb75b47 upstream. |
| |
| 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 c01778001a4f |
| ("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: 97ee0524614 ("flush cache before installing new page at migraton") |
| Signed-off-by: Lars Persson <larper@axis.com> |
| Reviewed-by: Paul Burton <paul.burton@mips.com> |
| Acked-by: Mel Gorman <mgorman@techsingularity.net> |
| Cc: Ralf Baechle <ralf@linux-mips.org> |
| Cc: <stable@vger.kernel.org> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| mm/migrate.c | 11 ++++++++--- |
| 1 file changed, 8 insertions(+), 3 deletions(-) |
| |
| --- a/mm/migrate.c |
| +++ b/mm/migrate.c |
| @@ -247,10 +247,8 @@ static bool remove_migration_pte(struct |
| pte = swp_entry_to_pte(entry); |
| } else if (is_device_public_page(new)) { |
| pte = pte_mkdevmap(pte); |
| - flush_dcache_page(new); |
| } |
| - } else |
| - flush_dcache_page(new); |
| + } |
| |
| #ifdef CONFIG_HUGETLB_PAGE |
| if (PageHuge(new)) { |
| @@ -971,6 +969,13 @@ static int move_to_new_page(struct page |
| */ |
| if (!PageMappingFlags(page)) |
| 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: |
| return rc; |