From: Huan Nguyen <nhuhuan@google.com>
To: tglx@kernel.org, mingo@redhat.com, bp@alien8.de,
dave.hansen@linux.intel.com, x86@kernel.org, hpa@zytor.com,
akpm@linux-foundation.org, david@kernel.org, ljs@kernel.org,
Liam.Howlett@oracle.com, vbabka@kernel.org, rppt@kernel.org,
surenb@google.com, mhocko@suse.com, trondmy@kernel.org,
anna@kernel.org, ziy@nvidia.com, matthew.brost@intel.com,
joshua.hahnjy@gmail.com, rakie.kim@sk.com, byungchul@sk.com,
gourry@gourry.net, ying.huang@linux.alibaba.com,
apopple@nvidia.com, rostedt@goodmis.org, mhiramat@kernel.org,
mathieu.desnoyers@efficios.com, jackmanb@google.com,
hannes@cmpxchg.org, shivankg@amd.com
Cc: rientjes@google.com, dave@stgolabs.net, nifan.cxl@gmail.com,
fvdl@google.com, jic23@kernel.org, rkodsara@amd.com,
bharata@amd.com, sj@kernel.org, weixugc@google.com,
xuezhengchu@huawei.com, yiannis@zptcorp.com,
yiannis.nikolakop@gmail.com, dimitrios.palyvos@zptcorp.com,
alirad.malek@zptcorp.com, ryan.roberts@arm.com,
nhuhuan@google.com, linux-kernel@vger.kernel.org,
linux-mm@kvack.org, linux-nfs@vger.kernel.org,
linux-trace-kernel@vger.kernel.org
Subject: [RFC PATCH v3 1/3] mm, x86: support copying a folio using non-temporal stores
Date: Tue, 3 Nov 2026 14:30:23 -0800 [thread overview]
Message-ID: <20261103223025.2482227-2-nhuhuan@google.com> (raw)
In-Reply-To: <20261103223025.2482227-1-nhuhuan@google.com>
On x86_64 architecture, copying cold memory folios using standard store
instructions pollutes CPU caches with cold data, increasing memory
latency and bandwidth overhead.
Support machine-check safe non-temporal copying of folios:
- Add copy_mc_page_nt() to copy a 4KiB page using non-temporal stores,
prefetching, and MCE exception handling.
- Add copy_mc_highpage_nt() to map and copy a 4KiB page.
- Add folio_mc_copy_nt() to copy a folio using copy_mc_highpage_nt().
Because non-temporal stores are weakly ordered, a wmb() is issued at the
end of folio_mc_copy_nt() before page tables are updated to ensure the
new folio contents are globally visible. In the event of task preemption
and CPU migration mid-folio, the scheduler's locked instructions on the
departing CPU serialize and drain earlier stores, while the final wmb()
covers the remainder on the new CPU.
Suggested-by: Alirad Malek <alirad.malek@zptcorp.com>
Suggested-by: Dimitrios Palyvos-Giannas <dimitrios.palyvos@zptcorp.com>
Signed-off-by: Huan Nguyen <nhuhuan@google.com>
---
arch/x86/include/asm/page_64.h | 2 ++
arch/x86/lib/copy_page_64.S | 65 ++++++++++++++++++++++++++++++++++
include/linux/highmem.h | 21 +++++++++++
include/linux/mm.h | 1 +
mm/util.c | 29 +++++++++++++++
5 files changed, 118 insertions(+)
diff --git a/arch/x86/include/asm/page_64.h b/arch/x86/include/asm/page_64.h
index 1895c207f629..f37126b56239 100644
--- a/arch/x86/include/asm/page_64.h
+++ b/arch/x86/include/asm/page_64.h
@@ -114,7 +114,9 @@ static inline void clear_page(void *addr)
clear_pages(addr, 1);
}
+#define __HAVE_ARCH_COPY_PAGE_NT 1
void copy_page(void *to, void *from);
+unsigned long copy_mc_page_nt(void *to, const void *from);
KCFI_REFERENCE(copy_page);
/*
diff --git a/arch/x86/lib/copy_page_64.S b/arch/x86/lib/copy_page_64.S
index d8e87fedc20d..185fa3bc34c0 100644
--- a/arch/x86/lib/copy_page_64.S
+++ b/arch/x86/lib/copy_page_64.S
@@ -6,6 +6,7 @@
#include <linux/cfi_types.h>
#include <asm/cpufeatures.h>
#include <asm/alternative.h>
+#include <asm/asm.h>
/*
* Some CPUs run faster using the string copy instructions (sane microcode).
@@ -88,3 +89,67 @@ SYM_FUNC_START_LOCAL(copy_page_regs)
addq $2*8, %rsp
RET
SYM_FUNC_END(copy_page_regs)
+
+/*
+ * Copy an entire 4KB page using non-temporal stores (movnti).
+ * Returns 0 on success, or number of bytes not copied on error.
+ */
+SYM_TYPED_FUNC_START(copy_mc_page_nt)
+ subq $2*8, %rsp
+ movq %rbx, (%rsp)
+ movq %r12, 1*8(%rsp)
+
+ xorl %eax, %eax
+ .p2align 4,,10
+ .p2align 3
+
+.L_nt0: movq 0x8*0(%rsi,%rax), %rdx
+.L_nt1: movq 0x8*1(%rsi,%rax), %rcx
+.L_nt2: movq 0x8*2(%rsi,%rax), %rbx
+.L_nt3: movq 0x8*3(%rsi,%rax), %r8
+.L_nt4: movq 0x8*4(%rsi,%rax), %r9
+.L_nt5: movq 0x8*5(%rsi,%rax), %r10
+.L_nt6: movq 0x8*6(%rsi,%rax), %r11
+.L_nt7: movq 0x8*7(%rsi,%rax), %r12
+
+ prefetchnta 5*64(%rsi,%rax)
+
+ movnti %rdx, 0x8*0(%rdi,%rax)
+ movnti %rcx, 0x8*1(%rdi,%rax)
+ movnti %rbx, 0x8*2(%rdi,%rax)
+ movnti %r8, 0x8*3(%rdi,%rax)
+ movnti %r9, 0x8*4(%rdi,%rax)
+ movnti %r10, 0x8*5(%rdi,%rax)
+ movnti %r11, 0x8*6(%rdi,%rax)
+ movnti %r12, 0x8*7(%rdi,%rax)
+
+ addq $64, %rax
+ cmpq $4096, %rax
+ jne .L_nt0
+
+ movq (%rsp), %rbx
+ movq 1*8(%rsp), %r12
+ addq $2*8, %rsp
+ xorl %eax, %eax
+ RET
+
+.E_nt:
+ negl %eax
+ addl $4096, %eax
+ sfence
+ movq (%rsp), %rbx
+ movq 1*8(%rsp), %r12
+ addq $2*8, %rsp
+ RET
+
+ _ASM_EXTABLE_TYPE(.L_nt0, .E_nt, EX_TYPE_DEFAULT_MCE_SAFE)
+ _ASM_EXTABLE_TYPE(.L_nt1, .E_nt, EX_TYPE_DEFAULT_MCE_SAFE)
+ _ASM_EXTABLE_TYPE(.L_nt2, .E_nt, EX_TYPE_DEFAULT_MCE_SAFE)
+ _ASM_EXTABLE_TYPE(.L_nt3, .E_nt, EX_TYPE_DEFAULT_MCE_SAFE)
+ _ASM_EXTABLE_TYPE(.L_nt4, .E_nt, EX_TYPE_DEFAULT_MCE_SAFE)
+ _ASM_EXTABLE_TYPE(.L_nt5, .E_nt, EX_TYPE_DEFAULT_MCE_SAFE)
+ _ASM_EXTABLE_TYPE(.L_nt6, .E_nt, EX_TYPE_DEFAULT_MCE_SAFE)
+ _ASM_EXTABLE_TYPE(.L_nt7, .E_nt, EX_TYPE_DEFAULT_MCE_SAFE)
+
+SYM_FUNC_END(copy_mc_page_nt)
+EXPORT_SYMBOL_GPL(copy_mc_page_nt)
diff --git a/include/linux/highmem.h b/include/linux/highmem.h
index d7aac9de1c8a..264b3f109151 100644
--- a/include/linux/highmem.h
+++ b/include/linux/highmem.h
@@ -484,6 +484,27 @@ static inline int copy_mc_highpage(struct page *to, struct page *from)
}
#endif
+#ifdef __HAVE_ARCH_COPY_PAGE_NT
+static inline int copy_mc_highpage_nt(struct page *to, struct page *from)
+{
+ unsigned long ret;
+ char *vfrom, *vto;
+
+ vfrom = kmap_local_page(from);
+ vto = kmap_local_page(to);
+ ret = copy_mc_page_nt(vto, vfrom);
+ if (!ret)
+ kmsan_copy_page_meta(to, from);
+ kunmap_local(vto);
+ kunmap_local(vfrom);
+
+ if (ret)
+ memory_failure_queue(page_to_pfn(from), 0);
+
+ return ret;
+}
+#endif
+
static inline void memcpy_page(struct page *dst_page, size_t dst_off,
struct page *src_page, size_t src_off,
size_t len)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 9f167950926a..549bb21027e4 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2127,6 +2127,7 @@ void __folio_put(struct folio *folio);
void split_page(struct page *page, unsigned int order);
void folio_copy(struct folio *dst, struct folio *src);
int folio_mc_copy(struct folio *dst, struct folio *src);
+int folio_mc_copy_nt(struct folio *dst, struct folio *src);
unsigned long nr_free_buffer_pages(void);
diff --git a/mm/util.c b/mm/util.c
index 8acfe2148ba5..0418529264fd 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -778,6 +778,35 @@ int folio_mc_copy(struct folio *dst, struct folio *src)
}
EXPORT_SYMBOL(folio_mc_copy);
+int folio_mc_copy_nt(struct folio *dst, struct folio *src)
+{
+ long nr = folio_nr_pages(src);
+ long i = 0;
+
+ for (;;) {
+#ifdef __HAVE_ARCH_COPY_PAGE_NT
+ if (copy_mc_highpage_nt(folio_page(dst, i), folio_page(src, i)))
+ return -EHWPOISON;
+#else
+ if (copy_mc_highpage(folio_page(dst, i), folio_page(src, i)))
+ return -EHWPOISON;
+#endif
+ if (++i == nr)
+ break;
+ cond_resched();
+ }
+
+#ifdef __HAVE_ARCH_COPY_PAGE_NT
+ /*
+ * Drain weakly ordered non-temporal stores before the folio
+ * is published.
+ */
+ wmb();
+#endif
+ return 0;
+}
+EXPORT_SYMBOL(folio_mc_copy_nt);
+
int sysctl_overcommit_memory __read_mostly = OVERCOMMIT_GUESS;
static int sysctl_overcommit_ratio __read_mostly = 50;
static unsigned long sysctl_overcommit_kbytes __read_mostly;
--
2.56.0.398.g882cbad275-goog
next prev parent reply other threads:[~2026-11-03 22:31 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-30 15:02 [PATCH RFC v2 0/3] Demote to lower tier " Yiannis Nikolakopoulos
2026-07-30 15:02 ` [PATCH RFC v2 1/3] mm, x86: support copying a folio " Yiannis Nikolakopoulos
2026-07-31 21:53 ` Huan Nguyen
2026-08-17 16:34 ` Garg, Shivank
2026-07-30 15:02 ` [PATCH RFC v2 2/3] mm: new migrate_mode flag for async " Yiannis Nikolakopoulos
2026-08-05 14:14 ` Huang, Ying
2026-07-30 15:02 ` [PATCH RFC v2 3/3] mm: use non-temporal stores for demotion Yiannis Nikolakopoulos
2026-07-30 17:30 ` [PATCH RFC v2 0/3] Demote to lower tier using non-temporal stores Gregory Price
2026-07-30 17:40 ` Frank van der Linden
2026-07-30 18:08 ` Johannes Weiner
2026-07-30 20:49 ` Gregory Price
2026-11-03 22:30 ` [RFC PATCH v3 0/3] mm: use non-temporal stores for demotion Huan Nguyen
2026-11-03 22:30 ` Huan Nguyen [this message]
2026-11-03 22:30 ` [RFC PATCH v3 2/3] mm/migrate: introduce async non-temporal migration mode Huan Nguyen
2026-11-03 22:30 ` [RFC PATCH v3 3/3] mm/vmscan: demote folios using non-temporal stores Huan Nguyen
2026-11-04 0:09 ` [RFC PATCH v3 0/3] mm: use non-temporal stores for demotion Zi Yan
2026-11-04 9:07 ` Lorenzo Stoakes (ARM)
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=20261103223025.2482227-2-nhuhuan@google.com \
--to=nhuhuan@google.com \
--cc=Liam.Howlett@oracle.com \
--cc=akpm@linux-foundation.org \
--cc=alirad.malek@zptcorp.com \
--cc=anna@kernel.org \
--cc=apopple@nvidia.com \
--cc=bharata@amd.com \
--cc=bp@alien8.de \
--cc=byungchul@sk.com \
--cc=dave.hansen@linux.intel.com \
--cc=dave@stgolabs.net \
--cc=david@kernel.org \
--cc=dimitrios.palyvos@zptcorp.com \
--cc=fvdl@google.com \
--cc=gourry@gourry.net \
--cc=hannes@cmpxchg.org \
--cc=hpa@zytor.com \
--cc=jackmanb@google.com \
--cc=jic23@kernel.org \
--cc=joshua.hahnjy@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=linux-nfs@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=ljs@kernel.org \
--cc=mathieu.desnoyers@efficios.com \
--cc=matthew.brost@intel.com \
--cc=mhiramat@kernel.org \
--cc=mhocko@suse.com \
--cc=mingo@redhat.com \
--cc=nifan.cxl@gmail.com \
--cc=rakie.kim@sk.com \
--cc=rientjes@google.com \
--cc=rkodsara@amd.com \
--cc=rostedt@goodmis.org \
--cc=rppt@kernel.org \
--cc=ryan.roberts@arm.com \
--cc=shivankg@amd.com \
--cc=sj@kernel.org \
--cc=surenb@google.com \
--cc=tglx@kernel.org \
--cc=trondmy@kernel.org \
--cc=vbabka@kernel.org \
--cc=weixugc@google.com \
--cc=x86@kernel.org \
--cc=xuezhengchu@huawei.com \
--cc=yiannis.nikolakop@gmail.com \
--cc=yiannis@zptcorp.com \
--cc=ying.huang@linux.alibaba.com \
--cc=ziy@nvidia.com \
/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®