From: "Mike Rapoport (Microsoft)" <rppt@kernel.org>
To: linux-mm@kvack.org
Cc: Albert Ou <aou@eecs.berkeley.edu>,
Andrew Morton <akpm@linux-foundation.org>,
Andy Lutomirski <luto@kernel.org>,
Borislav Petkov <bp@alien8.de>,
Brendan Jackman <jackmanb@google.com>,
Catalin Marinas <catalin.marinas@arm.com>,
Dave Hansen <dave.hansen@linux.intel.com>,
David Hildenbrand <david@kernel.org>,
Huacai Chen <chenhuacai@kernel.org>,
Ingo Molnar <mingo@kernel.org>, Ingo Molnar <mingo@redhat.com>,
Kevin Brodsky <kevin.brodsky@arm.com>,
"Liam R. Howlett" <liam@infradead.org>,
Lorenzo Stoakes <ljs@kernel.org>, Michal Hocko <mhocko@suse.com>,
Mike Rapoport <rppt@kernel.org>,
Palmer Dabbelt <palmer@dabbelt.com>,
Paul Walmsley <pjw@kernel.org>,
Peter Zijlstra <peterz@infradead.org>,
"H. Peter Anvin" <hpa@zytor.com>,
Suren Baghdasaryan <surenb@google.com>,
Thomas Gleixner <tglx@kernel.org>,
Vlastimil Babka <vbabka@kernel.org>,
Will Deacon <will@kernel.org>,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, linux-riscv@lists.infradead.org,
loongarch@lists.linux.dev, x86@kernel.org
Subject: [PATCH RFC 14/18] x86/mm/pat, mm: move cpa-test to mm
Date: Tue, 21 Jul 2026 19:23:37 +0300 [thread overview]
Message-ID: <20260721-generic-set-memory-v0-1-v1-14-2c1fc62306b3@kernel.org> (raw)
In-Reply-To: <20260721-generic-set-memory-v0-1-v1-0-2c1fc62306b3@kernel.org>
x86 has a nice test suite for set_memory APIs and CPA machinery.
Now that core CPA machinery is a part of the generic code let's make the
test also available as the part of the common code:
* move arch/x86/mm/pat/cpa-test.c to mm/
* keep it included in set_memory.c rather than a separate compilation unit.
* adjust the code to use pXd accessors instead of hardcoded x86 specific
bits
* replace max_pfn_mapped used as an upper bound with test local
max_test_pfn derived from high_memory.
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
---
arch/x86/Kconfig.debug | 6 ----
arch/x86/mm/pat/set_memory.c | 8 -----
mm/Kconfig.debug | 7 ++++
{arch/x86/mm/pat => mm}/cpa-test.c | 66 +++++++++++++++++++-------------------
mm/set_memory.c | 8 +++++
5 files changed, 48 insertions(+), 47 deletions(-)
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index c95c3aaadf97..314b72aad6ff 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -157,12 +157,6 @@ config DEBUG_BOOT_PARAMS
help
This option will cause struct boot_params to be exported via debugfs.
-config CPA_DEBUG
- bool "CPA self-test code"
- depends on DEBUG_KERNEL
- help
- Do change_page_attr() self-tests every 30 seconds.
-
config DEBUG_ENTRY
bool "Debug low-level entry code"
depends on DEBUG_KERNEL
diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c
index 5109139a2d31..c460121c96b9 100644
--- a/arch/x86/mm/pat/set_memory.c
+++ b/arch/x86/mm/pat/set_memory.c
@@ -2324,11 +2324,3 @@ int __init kernel_unmap_pages_in_pgd(pgd_t *pgd, unsigned long address,
return retval;
}
-
-/*
- * The testcases use internal knowledge of the implementation that shouldn't
- * be exposed to the rest of the kernel. Include these directly here.
- */
-#ifdef CONFIG_CPA_DEBUG
-#include "cpa-test.c"
-#endif
diff --git a/mm/Kconfig.debug b/mm/Kconfig.debug
index 91b3e027b753..83cfef6b2d8c 100644
--- a/mm/Kconfig.debug
+++ b/mm/Kconfig.debug
@@ -320,3 +320,10 @@ config PER_VMA_LOCK_STATS
overhead in the page fault path.
If in doubt, say N.
+
+config CPA_DEBUG
+ bool "CPA self-test code"
+ depends on GENERIC_SET_MEMORY
+ depends on DEBUG_KERNEL
+ help
+ Do change_page_attr() self-tests every 30 seconds.
diff --git a/arch/x86/mm/pat/cpa-test.c b/mm/cpa-test.c
similarity index 80%
rename from arch/x86/mm/pat/cpa-test.c
rename to mm/cpa-test.c
index ad3c1feec990..63c3463a5a7d 100644
--- a/arch/x86/mm/pat/cpa-test.c
+++ b/mm/cpa-test.c
@@ -13,32 +13,24 @@
#include <linux/mm.h>
#include <linux/vmalloc.h>
-#include <asm/cacheflush.h>
-#include <asm/kdebug.h>
-
/*
* Only print the results of the first pass:
*/
static __read_mostly int print = 1;
+static unsigned long max_test_pfn;
enum {
NTEST = 3 * 100,
NPAGES = 100,
-#ifdef CONFIG_X86_64
- LPS = (1 << PMD_SHIFT),
-#elif defined(CONFIG_X86_PAE)
- LPS = (1 << PMD_SHIFT),
-#else
- LPS = (1 << 22),
-#endif
- GPS = (1<<30)
+ LPS = PMD_SIZE,
+ GPS = PUD_SIZE
};
-#define PAGE_CPA_TEST __pgprot(_PAGE_CPA_TEST)
+#define PAGE_CPA_TEST __pgprot(_PAGE_SPECIAL)
static int pte_testbit(pte_t pte)
{
- return pte_flags(pte) & _PAGE_SOFTW1;
+ return pte_special(pte);
}
struct split_state {
@@ -54,10 +46,10 @@ static int print_split(struct split_state *s)
s->lpg = s->gpg = s->spg = s->exec = 0;
s->min_exec = ~0UL;
s->max_exec = 0;
- for (i = 0; i < max_pfn_mapped; ) {
+ for (i = 0; i < max_test_pfn; ) {
unsigned long addr = (unsigned long)__va(i << PAGE_SHIFT);
unsigned int level;
- pte_t *pte;
+ pte_t *pte, pteval;
pte = lookup_address(addr, &level);
if (!pte) {
@@ -65,15 +57,16 @@ static int print_split(struct split_state *s)
i++;
continue;
}
+ pteval = ptep_get(pte);
- if (level == PG_LEVEL_1G && sizeof(long) == 8) {
+ if (level == PGTABLE_LEVEL_PUD && sizeof(long) == 8) {
s->gpg++;
i += GPS/PAGE_SIZE;
- } else if (level == PG_LEVEL_2M) {
- if ((pte_val(*pte) & _PAGE_PRESENT) && !(pte_val(*pte) & _PAGE_PSE)) {
+ } else if (level == PGTABLE_LEVEL_PMD) {
+ if (pte_present(pteval) && !pte_huge(pteval)) {
printk(KERN_ERR
- "%lx level %d but not PSE %Lx\n",
- addr, level, (u64)pte_val(*pte));
+ "%lx level %d but not leaf %Lx\n",
+ addr, level, (u64)pte_val(pteval));
err = 1;
}
s->lpg++;
@@ -82,7 +75,7 @@ static int print_split(struct split_state *s)
s->spg++;
i++;
}
- if (!(pte_val(*pte) & _PAGE_NX)) {
+ if (pte_exec(pteval)) {
s->exec++;
if (addr < s->min_exec)
s->min_exec = addr;
@@ -100,8 +93,8 @@ static int print_split(struct split_state *s)
expected = (s->gpg*GPS + s->lpg*LPS)/PAGE_SIZE + s->spg + missed;
if (expected != i) {
- printk(KERN_ERR "CPA max_pfn_mapped %lu but expected %lu\n",
- max_pfn_mapped, expected);
+ printk(KERN_ERR "CPA max_test_pfn %lu but expected %lu\n",
+ max_test_pfn, expected);
return 1;
}
return err;
@@ -118,7 +111,7 @@ static int pageattr_test(void)
{
struct split_state sa, sb, sc;
unsigned long *bm;
- pte_t *pte, pte0;
+ pte_t *pte, pte0, pte_val;
int failed = 0;
unsigned int level;
int i, k;
@@ -127,7 +120,7 @@ static int pageattr_test(void)
if (print)
printk(KERN_INFO "CPA self-test:\n");
- bm = vzalloc((max_pfn_mapped + 7) / 8);
+ bm = vzalloc((max_test_pfn + 7) / 8);
if (!bm) {
printk(KERN_ERR "CPA Cannot vmalloc bitmap\n");
return -ENOMEM;
@@ -136,11 +129,11 @@ static int pageattr_test(void)
failed += print_split(&sa);
for (i = 0; i < NTEST; i++) {
- unsigned long pfn = get_random_u32_below(max_pfn_mapped);
+ unsigned long pfn = get_random_u32_below(max_test_pfn);
addr[i] = (unsigned long)__va(pfn << PAGE_SHIFT);
len[i] = get_random_u32_below(NPAGES);
- len[i] = min_t(unsigned long, len[i], max_pfn_mapped - pfn - 1);
+ len[i] = min_t(unsigned long, len[i], max_test_pfn - pfn - 1);
if (len[i] == 0)
len[i] = 1;
@@ -150,15 +143,20 @@ static int pageattr_test(void)
for (k = 0; k < len[i]; k++) {
pte = lookup_address(addr[i] + k*PAGE_SIZE, &level);
- if (!pte || pgprot_val(pte_pgprot(*pte)) == 0 ||
- !(pte_val(*pte) & _PAGE_PRESENT)) {
+ if (!pte) {
+ addr[i] = 0;
+ break;
+ }
+ pte_val = ptep_get(pte);
+ if (pgprot_val(pte_pgprot(pte_val)) == 0 ||
+ !pte_present(pte_val)) {
addr[i] = 0;
break;
}
if (k == 0) {
- pte0 = *pte;
+ pte0 = pte_val;
} else {
- if (pgprot_val(pte_pgprot(*pte)) !=
+ if (pgprot_val(pte_pgprot(pte_val)) !=
pgprot_val(pte_pgprot(pte0))) {
len[i] = k;
break;
@@ -198,12 +196,12 @@ static int pageattr_test(void)
}
pte = lookup_address(addr[i], &level);
- if (!pte || !pte_testbit(*pte) || pte_huge(*pte)) {
+ if (!pte || !pte_testbit(*pte) || level != PGTABLE_LEVEL_PTE) {
printk(KERN_ERR "CPA %lx: bad pte %Lx\n", addr[i],
pte ? (u64)pte_val(*pte) : 0ULL);
failed++;
}
- if (level != PG_LEVEL_4K) {
+ if (level != PGTABLE_LEVEL_PTE) {
printk(KERN_ERR "CPA %lx: unexpected level %d\n",
addr[i], level);
failed++;
@@ -266,6 +264,8 @@ static int start_pageattr_test(void)
{
struct task_struct *p;
+ max_test_pfn = PFN_DOWN(__pa(high_memory - 1));
+
p = kthread_create(do_pageattr_test, NULL, "pageattr-test");
if (!IS_ERR(p))
wake_up_process(p);
diff --git a/mm/set_memory.c b/mm/set_memory.c
index 1a7e63512981..744405efcc34 100644
--- a/mm/set_memory.c
+++ b/mm/set_memory.c
@@ -386,3 +386,11 @@ int change_page_attr_set_clr(unsigned long *addr, int numpages,
out:
return err;
}
+
+/*
+ * The testcases use internal knowledge of the implementation that shouldn't
+ * be exposed to the rest of the kernel. Include these directly here.
+ */
+#ifdef CONFIG_CPA_DEBUG
+#include "cpa-test.c"
+#endif
--
2.53.0
next prev parent reply other threads:[~2026-07-21 16:25 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-21 16:23 [PATCH RFC 00/18] arch, mm: create a generic set_memory/change_page_attr core Mike Rapoport (Microsoft)
2026-07-21 16:23 ` [PATCH RFC 01/18] x86/mm/pat: Don't gate cpa_lock on debug_pagealloc_enabled() Mike Rapoport (Microsoft)
2026-07-21 17:16 ` Lorenzo Stoakes (ARM)
2026-07-21 18:30 ` Mike Rapoport
2026-07-22 8:55 ` Lorenzo Stoakes (ARM)
2026-07-21 16:23 ` [PATCH RFC 02/18] x86/mm/pat: fix effective RW computation in lookup_address_in_pgd_attr() Mike Rapoport (Microsoft)
2026-07-21 16:23 ` [PATCH RFC 03/18] x86/mm/pat: replace x86-speficic pg_level with generic pgtable_level Mike Rapoport (Microsoft)
2026-07-21 16:23 ` [PATCH RFC 04/18] x86/mm/pat: use page table accessors for effective RW/NX bits Mike Rapoport (Microsoft)
2026-07-21 16:23 ` [PATCH RFC 05/18] x86/mm/pat: use a generic helper for the large page size Mike Rapoport (Microsoft)
2026-07-21 16:23 ` [PATCH RFC 06/18] x86/mm/pat: introduce an inline helper to check if alias needs update Mike Rapoport (Microsoft)
2026-07-21 16:23 ` [PATCH RFC 07/18] x86/mm/pat: introduce cpa_handle_large_page() Mike Rapoport (Microsoft)
2026-07-21 16:23 ` [PATCH RFC 08/18] x86/mm/pat: use cpa_split_data structure to pass split parameters Mike Rapoport (Microsoft)
2026-07-21 16:23 ` [PATCH RFC 09/18] x86/mm/pat: use a single locked lookup for PTE verification Mike Rapoport (Microsoft)
2026-07-21 16:23 ` [PATCH RFC 10/18] x86/mm/pat: move the large page size calculation to should_split_large_page Mike Rapoport (Microsoft)
2026-07-21 16:23 ` [PATCH RFC 11/18] x86/mm/pat, mm: set_memory: pull change_page_attr() core to mm/ Mike Rapoport (Microsoft)
2026-07-21 16:23 ` [PATCH RFC 12/18] x86/pat/mm, mm/set_memory: abstract the CPA page table lock Mike Rapoport (Microsoft)
2026-07-21 16:23 ` [PATCH RFC 13/18] mm/set_memory: read page table entries with pXdp_get() Mike Rapoport (Microsoft)
2026-07-21 16:23 ` Mike Rapoport (Microsoft) [this message]
2026-07-21 16:23 ` [PATCH RFC 15/18] riscv: convert set_memory to the generic CPA implementation Mike Rapoport (Microsoft)
2026-07-21 16:23 ` [PATCH RFC 16/18] riscv: make set_direct_map_*_noflush actually noflush Mike Rapoport (Microsoft)
2026-07-21 16:23 ` [PATCH RFC 17/18] loongarch: convert set_memory to the generic CPA implementation Mike Rapoport (Microsoft)
2026-07-21 16:23 ` [PATCH RFC 18/18] loongarch: make set_direct_map_*_noflush actually noflush Mike Rapoport (Microsoft)
2026-07-21 17:19 ` [PATCH RFC 00/18] arch, mm: create a generic set_memory/change_page_attr core Borislav Petkov
2026-07-21 18:28 ` Mike Rapoport
2026-07-21 19:54 ` Borislav Petkov
2026-07-22 6:50 ` Mike Rapoport
2026-07-22 17:03 ` Dave Hansen
2026-07-27 10:22 ` Mike Rapoport
2026-07-22 13:20 ` [syzbot ci] " syzbot ci
2026-07-22 15:17 ` [PATCH RFC 00/18] " Adrian Barnaś
2026-07-27 10:16 ` Mike Rapoport
2026-11-01 22:16 ` patchwork-bot+linux-riscv
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=20260721-generic-set-memory-v0-1-v1-14-2c1fc62306b3@kernel.org \
--to=rppt@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=aou@eecs.berkeley.edu \
--cc=bp@alien8.de \
--cc=catalin.marinas@arm.com \
--cc=chenhuacai@kernel.org \
--cc=dave.hansen@linux.intel.com \
--cc=david@kernel.org \
--cc=hpa@zytor.com \
--cc=jackmanb@google.com \
--cc=kevin.brodsky@arm.com \
--cc=liam@infradead.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=linux-riscv@lists.infradead.org \
--cc=ljs@kernel.org \
--cc=loongarch@lists.linux.dev \
--cc=luto@kernel.org \
--cc=mhocko@suse.com \
--cc=mingo@kernel.org \
--cc=mingo@redhat.com \
--cc=palmer@dabbelt.com \
--cc=peterz@infradead.org \
--cc=pjw@kernel.org \
--cc=surenb@google.com \
--cc=tglx@kernel.org \
--cc=vbabka@kernel.org \
--cc=will@kernel.org \
--cc=x86@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®