mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Magnus Lindholm <linmag7@gmail.com>
To: davem@davemloft.net, andreas@gaisler.com
Cc: sparclinux@vger.kernel.org, linux-kernel@vger.kernel.org,
	linmag7@gmail.com, stable@vger.kernel.org
Subject: [PATCH 2/9] sparc32: flush the source user alias in copy_user_highpage()
Date: Sun,  8 Nov 2026 23:34:12 +0100	[thread overview]
Message-ID: <20261108223516.1125534-3-linmag7@gmail.com> (raw)
In-Reply-To: <20261108223516.1125534-1-linmag7@gmail.com>

copy_user_highpage() also handles lowmem pages. A source user alias can be
dirtied after the fork cache flush but before write protection and its TLB
shootdown complete on another CPU. This explains why flushing at fork
alone is insufficient; the historical tests below did not isolate that
particular interleaving.

The hyperSPARC external cache is virtually indexed, so index bits lie
above the page offset and one physical page can occupy 64, 128 or 256
distinct cache locations depending on cache size. Two mappings of a page
do not see each other's dirty lines.

copy_user_highpage() reads the source through a kmap_local alias, so lines
dirtied through the user mapping sit in a different set and the copy reads
stale memory. copy_user_page() then flushes page_address(page), NULL for a
highmem page, with no NULL check.

Flush the source page's user alias with flush_cache_page() before reading
it, and flush the destination through the address actually written.

Only observable on HyperSPARC: SuperSPARC's caches are physically indexed
and MBus snooped, so viking_flush_cache_all() is a window flush and a
return.

Fork/COW torture on a two-cpu SPARCstation 20: 7 of 20 runs lost writes
before, 0 of 20 after.

The source-alias omission predates Git history; the later folio conversion
also removed sparc_flush_page_to_ram()'s NULL guard. This change uses the
mapped destination address and covers both cases.

Cc: stable@vger.kernel.org
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
 arch/sparc/include/asm/page_32.h |  6 ++++++
 arch/sparc/mm/init_32.c          | 23 +++++++++++++++++++++++
 2 files changed, 29 insertions(+)

diff --git a/arch/sparc/include/asm/page_32.h b/arch/sparc/include/asm/page_32.h
index 7429291fb118..c968ec33ee98 100644
--- a/arch/sparc/include/asm/page_32.h
+++ b/arch/sparc/include/asm/page_32.h
@@ -28,6 +28,12 @@
 		(void)(vaddr);			\
 	} while (0)
 
+#define __HAVE_ARCH_COPY_USER_HIGHPAGE
+struct page;
+struct vm_area_struct;
+void copy_user_highpage(struct page *to, struct page *from,
+			unsigned long vaddr, struct vm_area_struct *vma);
+
 /* passing structs on the Sparc slow us down tremendously... */
 
 /* #define STRICT_MM_TYPECHECKS */
diff --git a/arch/sparc/mm/init_32.c b/arch/sparc/mm/init_32.c
index 2f693b70dbd8..7b53ee9f061f 100644
--- a/arch/sparc/mm/init_32.c
+++ b/arch/sparc/mm/init_32.c
@@ -103,6 +103,29 @@ void sparc_flush_page_to_ram(struct page *page)
 }
 EXPORT_SYMBOL(sparc_flush_page_to_ram);
 
+/*
+ * The kernel reads the source page through a kmap alias, which on a
+ * virtually indexed cache lands in a different set than the user mapping
+ * userspace has been dirtying.  Flush that alias first, and flush the
+ * destination through the address actually written rather than
+ * page_address(), which is NULL for a highmem page.
+ */
+void copy_user_highpage(struct page *to, struct page *from,
+			unsigned long vaddr, struct vm_area_struct *vma)
+{
+	char *vfrom, *vto;
+
+	if (vma)
+		flush_cache_page(vma, vaddr, page_to_pfn(from));
+
+	vfrom = kmap_local_page(from);
+	vto = kmap_local_page(to);
+	copy_page(vto, vfrom);
+	__flush_page_to_ram((unsigned long)vto);
+	kunmap_local(vto);
+	kunmap_local(vfrom);
+}
+
 void sparc_flush_folio_to_ram(struct folio *folio)
 {
 	unsigned long vaddr = (unsigned long)folio_address(folio);
-- 
2.43.0


  parent reply	other threads:[~2026-11-08 22:36 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-08 22:34 [PATCH 0/9] sparc32: repair cache hooks, mappings and TLB tracking Magnus Lindholm
2026-11-08 22:34 ` [PATCH 1/9] sparc32: inspect every PROM CPU cache geometry Magnus Lindholm
2026-11-08 22:34 ` Magnus Lindholm [this message]
2026-11-08 22:34 ` [PATCH 3/9] sparc32: do not flush a NULL address in flush_dcache_folio Magnus Lindholm
2026-11-08 22:34 ` [PATCH 4/9] sparc32: flush the cache when a kmap_local mapping is installed Magnus Lindholm
2026-11-08 22:34 ` [PATCH 5/9] sparc32: preset modified and referenced bits in kmap PTEs Magnus Lindholm
2026-11-08 22:34 ` [PATCH 6/9] sparc32: colour-align private file mappings Magnus Lindholm
2026-11-08 22:34 ` [PATCH 7/9] sparc32: implement flush_anon_page Magnus Lindholm
2026-11-08 22:34 ` [PATCH 8/9] sparc32: retain mm_cpumask across TLB shootdowns Magnus Lindholm
2026-11-08 22:34 ` [PATCH 9/9] sparc32: enroll and order CPUs before switching address spaces Magnus Lindholm

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261108223516.1125534-3-linmag7@gmail.com \
    --to=linmag7@gmail.com \
    --cc=andreas@gaisler.com \
    --cc=davem@davemloft.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=sparclinux@vger.kernel.org \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®