Linux-mm Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [RFC V2 0/3] lib/vsprintf: Add support for pgtable entries
@ 2026-06-10  4:35 Anshuman Khandual
  2026-06-10  4:35 ` [RFC V2 1/3] " Anshuman Khandual
                   ` (3 more replies)
  0 siblings, 4 replies; 15+ messages in thread
From: Anshuman Khandual @ 2026-06-10  4:35 UTC (permalink / raw)
  To: linux-mm
  Cc: Anshuman Khandual, Andy Shevchenko, Rasmus Villemoes,
	Sergey Senozhatsky, Petr Mladek, Steven Rostedt, Jonathan Corbet,
	Andrew Morton, David Hildenbrand, linux-kernel, linux-doc

Printing page table entries has been a common requirement both in generic
and platform memory management for various purposes. Hence let's create a
dedicated printk format for such entries which will also help standardize
pgtable printing across different platforms.

Also add a test for this new print format in lib/tests/printf_kunit.c via
existing CONFIG_PRINTF_KUNIT_TEST.

This series applies on v7.1-rc7

This series has been tested on arm64 but built tested on several others
including x86, powerpc, s390, riscv, and mips etc. Although it does not
build on arm32 platform due to existing pgdp_get() concerns.

Changes in V2:

Accommodated most suggestions from Petr Mladek and others

- Moved __print_bad_page_map_pgtable() changes into a separate patch
- Added helper pxd_pointer() for pgtable print format
- Added buffer check via check_pointer()
- Added special_hex_number() for base case printing
- Added static_assert() to ensure acceptable pxd_t size
- Avoided direct dereferences and used pxdp_get() helpers instead
- Improved printf KUNIT tests for all level page table entries

Changes in V1:

https://lore.kernel.org/all/20250618041235.1716143-1-anshuman.khandual@arm.com/

Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Cc: Sergey Senozhatsky <senozhatsky@chromium.org>
Cc: Petr Mladek <pmladek@suse.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: David Hildenbrand <david@redhat.com>
Cc: linux-kernel@vger.kernel.org
Cc: linux-doc@vger.kernel.org
Cc: linux-mm@kvack.org

Anshuman Khandual (3):
  lib/vsprintf: Add support for pgtable entries
  kunit: printf: Add test for pgtable entries
  mm: Replace pgtable entry prints with new format

 Documentation/core-api/printk-formats.rst | 19 ++++++++
 lib/tests/printf_kunit.c                  | 57 ++++++++++++++++++++++
 lib/vsprintf.c                            | 58 +++++++++++++++++++++++
 mm/memory.c                               | 15 ++----
 scripts/checkpatch.pl                     |  2 +-
 5 files changed, 140 insertions(+), 11 deletions(-)

-- 
2.30.2



^ permalink raw reply	[flat|nested] 15+ messages in thread

* [RFC V2 1/3] lib/vsprintf: Add support for pgtable entries
  2026-06-10  4:35 [RFC V2 0/3] lib/vsprintf: Add support for pgtable entries Anshuman Khandual
@ 2026-06-10  4:35 ` Anshuman Khandual
  2026-06-10 11:13   ` Usama Arif
  2026-06-10  4:35 ` [RFC V2 2/3] kunit: printf: Add test " Anshuman Khandual
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 15+ messages in thread
From: Anshuman Khandual @ 2026-06-10  4:35 UTC (permalink / raw)
  To: linux-mm
  Cc: Anshuman Khandual, Andy Shevchenko, Rasmus Villemoes,
	Sergey Senozhatsky, Petr Mladek, Steven Rostedt, Jonathan Corbet,
	Andrew Morton, David Hildenbrand, linux-kernel, linux-doc,
	David Hildenbrand, Lorenzo Stoakes, Andy Whitcroft

Add some print formats for pgtable entries at any pgtable level. These new
formats are %pp[g|4|u|m|t][d|e] i.e %ppgd, %pp4d, %ppud, %ppmd, and %ppte.
These currently support both 32 bit and 64 bit pgtable entries that can be
extended up to 128 bit when required.

Signed-off-by: Anshuman Khandual <anshuman.khandual@arm.com>
---
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: David Hildenbrand <david@kernel.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>
Cc: Petr Mladek <pmladek@suse.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Andy Whitcroft <apw@canonical.com>
Cc: linux-mm@kvack.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-doc@vger.kernel.org

 Documentation/core-api/printk-formats.rst | 19 ++++++++
 lib/vsprintf.c                            | 58 +++++++++++++++++++++++
 scripts/checkpatch.pl                     |  2 +-
 3 files changed, 78 insertions(+), 1 deletion(-)

diff --git a/Documentation/core-api/printk-formats.rst b/Documentation/core-api/printk-formats.rst
index c0b1b6089307..e69f91a9dd9d 100644
--- a/Documentation/core-api/printk-formats.rst
+++ b/Documentation/core-api/printk-formats.rst
@@ -696,6 +696,25 @@ Rust
 Only intended to be used from Rust code to format ``core::fmt::Arguments``.
 Do *not* use it from C.
 
+Page Table Entry
+----------------
+
+::
+
+        %p[pgd|p4dp|pud|pmd|pte]
+
+Print page table entry at any level.
+
+Passed by reference.
+
+Examples for a 64 bit page table entry, given &(u64)0xc0ffee::
+
+        %ppte   0x0000000000c0ffee
+        %ppmd   0x0000000000c0ffee
+        %ppud   0x0000000000c0ffee
+        %pp4d   0x0000000000c0ffee
+        %ppgd   0x0000000000c0ffee
+
 Thanks
 ======
 
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 9f359b31c8d1..d4ad3048a4db 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -856,6 +856,59 @@ static char *default_pointer(char *buf, char *end, const void *ptr,
 	return ptr_to_id(buf, end, ptr, spec);
 }
 
+static char *pxd_pointer(char *buf, char *end, const void *ptr,
+			 struct printf_spec spec, const char *fmt)
+{
+	if (check_pointer(&buf, end, ptr, spec))
+		return buf;
+
+	if (fmt[1] == 't' && fmt[2] == 'e') {
+		pte_t *pte = (pte_t *)ptr;
+
+		static_assert(sizeof(pte_t) == 4 ||
+			      sizeof(pte_t) == 8,
+			      "pte_t size must be 4 or 8 bytes");
+		return special_hex_number(buf, end, pte_val(ptep_get(pte)), sizeof(pte_t));
+	}
+
+	if (fmt[1] == 'm' && fmt[2] == 'd') {
+		pmd_t *pmd = (pmd_t *)ptr;
+
+		static_assert(sizeof(pmd_t) == 4 ||
+			      sizeof(pmd_t) == 8,
+			      "pmd_t size must be 4 or 8 bytes");
+		return special_hex_number(buf, end, pmd_val(pmdp_get(pmd)), sizeof(pmd_t));
+	}
+
+	if (fmt[1] == 'u' && fmt[2] == 'd') {
+		pud_t *pud = (pud_t *)ptr;
+
+		static_assert(sizeof(pud_t) == 4 ||
+			      sizeof(pud_t) == 8,
+			      "pud_t size must be 4 or 8 bytes");
+		return special_hex_number(buf, end, pud_val(pudp_get(pud)), sizeof(pud_t));
+	}
+
+	if (fmt[1] == '4' && fmt[2] == 'd') {
+		p4d_t *p4d = (p4d_t *)ptr;
+
+		static_assert(sizeof(p4d_t) == 4 ||
+			      sizeof(p4d_t) == 8,
+			      "p4d_t size must be 4 or 8 bytes");
+		return special_hex_number(buf, end, p4d_val(p4dp_get(p4d)), sizeof(p4d_t));
+	}
+
+	if (fmt[1] == 'g' && fmt[2] == 'd') {
+		pgd_t *pgd = (pgd_t *)ptr;
+
+		static_assert(sizeof(pgd_t) == 4 ||
+			      sizeof(pgd_t) == 8,
+			      "pgd_t size must be 4 or 8 bytes");
+		return special_hex_number(buf, end, pgd_val(pgdp_get(pgd)), sizeof(pgd_t));
+	}
+	return default_pointer(buf, end, ptr, spec);
+}
+
 int kptr_restrict __read_mostly;
 
 static noinline_for_stack
@@ -2506,6 +2559,9 @@ early_param("no_hash_pointers", no_hash_pointers_enable);
  *		Without an option prints the full name of the node
  *		f full name
  *		P node name, including a possible unit address
+ * - 'p[g|4|u|m|t|][d|e]' For a page table entry, this prints its
+ *			  contents in a hexadecimal format
+ *
  * - 'x' For printing the address unmodified. Equivalent to "%lx".
  *       Please read the documentation (path below) before using!
  * - '[ku]s' For a BPF/tracing related format specifier, e.g. used out of
@@ -2615,6 +2671,8 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
 		default:
 			return error_string(buf, end, "(einval)", spec);
 		}
+	case 'p':
+		return pxd_pointer(buf, end, ptr, spec, fmt);
 	default:
 		return default_pointer(buf, end, ptr, spec);
 	}
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 0492d6afc9a1..f68955858e29 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -6975,7 +6975,7 @@ sub process {
 				my $fmt = get_quoted_string($lines[$count - 1], raw_line($count, 0));
 				$fmt =~ s/%%//g;
 
-				while ($fmt =~ /(\%[\*\d\.]*p(\w)(\w*))/g) {
+				while ($fmt =~ /(\%[\*\d\.]*p(\w)(\w*)(pte|pmd|pud|p4d|pgd))/g) {
 					$specifier = $1;
 					$extension = $2;
 					$qualifier = $3;
-- 
2.30.2



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC V2 2/3] kunit: printf: Add test for pgtable entries
  2026-06-10  4:35 [RFC V2 0/3] lib/vsprintf: Add support for pgtable entries Anshuman Khandual
  2026-06-10  4:35 ` [RFC V2 1/3] " Anshuman Khandual
@ 2026-06-10  4:35 ` Anshuman Khandual
  2026-06-10  4:35 ` [RFC V2 3/3] mm: Replace pgtable entry prints with new format Anshuman Khandual
  2026-06-11 19:15 ` [RFC V2 0/3] lib/vsprintf: Add support for pgtable entries Matthew Wilcox
  3 siblings, 0 replies; 15+ messages in thread
From: Anshuman Khandual @ 2026-06-10  4:35 UTC (permalink / raw)
  To: linux-mm
  Cc: Anshuman Khandual, Andy Shevchenko, Rasmus Villemoes,
	Sergey Senozhatsky, Petr Mladek, Steven Rostedt, Jonathan Corbet,
	Andrew Morton, David Hildenbrand, linux-kernel, linux-doc

Add test for new pgtable entry print formats with entry size being 64 bits.

Signed-off-by: Anshuman Khandual <anshuman.khandual@arm.com>
---
Cc: Petr Mladek <pmladek@suse.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Cc: Sergey Senozhatsky <senozhatsky@chromium.org>
Cc: linux-kernel@vger.kernel.org

 lib/tests/printf_kunit.c | 57 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)

diff --git a/lib/tests/printf_kunit.c b/lib/tests/printf_kunit.c
index bb70b9cddadd..850bfc0e3409 100644
--- a/lib/tests/printf_kunit.c
+++ b/lib/tests/printf_kunit.c
@@ -791,6 +791,62 @@ errptr(struct kunit *kunittest)
 #endif
 }
 
+struct pgtable_test {
+	u64 val;
+	const char *name;
+};
+
+static struct pgtable_test pgtable_test_cases[] = {
+	{ .val = 0xc0ffee,		.name = "0x0000000000c0ffee"},
+	{ .val = 0xdeadbeef,		.name = "0x00000000deadbeef"},
+	{ .val = 0xaabbcc,		.name = "0x0000000000aabbcc"},
+	{ .val = 0xcc,			.name = "0x00000000000000cc"},
+	{ .val = 0x1,			.name = "0x0000000000000001"},
+	{ .val = 0x11,			.name = "0x0000000000000011"},
+	{ .val = 0x111,			.name = "0x0000000000000111"},
+	{ .val = 0x10000010001,		.name = "0x0000010000010001"},
+	{ .val = 0xc0ffeec0ffee,	.name = "0x0000c0ffeec0ffee"},
+	{ .val = 0x10000000000,		.name = "0x0000010000000000"},
+	{ .val = 0x11000000000,		.name = "0x0000011000000000"},
+	{ .val = 0x1000000000000001,	.name = "0x1000000000000001"},
+	{ .val = 0x1100000000000010,	.name = "0x1100000000000010"},
+	{ .val = 0x1110000000000100,	.name = "0x1110000000000100"},
+	{ .val = 0xfff000000000ff00,	.name = "0xfff000000000ff00"},
+};
+
+static void
+pgtable_ptr(struct kunit *kunittest)
+{
+	char buf[64];
+	int i;
+
+	if (sizeof(pte_t) != 8)
+		kunit_skip(kunittest, "pte_t size is not 64 bits");
+
+	for (i = 0; i < ARRAY_SIZE(pgtable_test_cases); i++) {
+		pte_t pte = __pte(pgtable_test_cases[i].val);
+		pmd_t pmd = __pmd(pgtable_test_cases[i].val);
+		pud_t pud = __pud(pgtable_test_cases[i].val);
+		p4d_t p4d = __p4d(pgtable_test_cases[i].val);
+		pgd_t pgd = __pgd(pgtable_test_cases[i].val);
+
+		snprintf(buf, sizeof(buf), "%ppte", &pte);
+		KUNIT_EXPECT_STREQ(kunittest, buf, pgtable_test_cases[i].name);
+
+		snprintf(buf, sizeof(buf), "%ppmd", &pmd);
+		KUNIT_EXPECT_STREQ(kunittest, buf, pgtable_test_cases[i].name);
+
+		snprintf(buf, sizeof(buf), "%ppud", &pud);
+		KUNIT_EXPECT_STREQ(kunittest, buf, pgtable_test_cases[i].name);
+
+		snprintf(buf, sizeof(buf), "%pp4d", &p4d);
+		KUNIT_EXPECT_STREQ(kunittest, buf, pgtable_test_cases[i].name);
+
+		snprintf(buf, sizeof(buf), "%ppgd", &pgd);
+		KUNIT_EXPECT_STREQ(kunittest, buf, pgtable_test_cases[i].name);
+	}
+}
+
 static int printf_suite_init(struct kunit_suite *suite)
 {
 	total_tests = 0;
@@ -839,6 +895,7 @@ static struct kunit_case printf_test_cases[] = {
 	KUNIT_CASE(errptr),
 	KUNIT_CASE(fwnode_pointer),
 	KUNIT_CASE(fourcc_pointer),
+	KUNIT_CASE(pgtable_ptr),
 	{}
 };
 
-- 
2.30.2



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC V2 3/3] mm: Replace pgtable entry prints with new format
  2026-06-10  4:35 [RFC V2 0/3] lib/vsprintf: Add support for pgtable entries Anshuman Khandual
  2026-06-10  4:35 ` [RFC V2 1/3] " Anshuman Khandual
  2026-06-10  4:35 ` [RFC V2 2/3] kunit: printf: Add test " Anshuman Khandual
@ 2026-06-10  4:35 ` Anshuman Khandual
  2026-06-11 11:32   ` David Hildenbrand (Arm)
  2026-06-12 11:08   ` David Hildenbrand (Arm)
  2026-06-11 19:15 ` [RFC V2 0/3] lib/vsprintf: Add support for pgtable entries Matthew Wilcox
  3 siblings, 2 replies; 15+ messages in thread
From: Anshuman Khandual @ 2026-06-10  4:35 UTC (permalink / raw)
  To: linux-mm
  Cc: Anshuman Khandual, Andy Shevchenko, Rasmus Villemoes,
	Sergey Senozhatsky, Petr Mladek, Steven Rostedt, Jonathan Corbet,
	Andrew Morton, David Hildenbrand, linux-kernel, linux-doc,
	David Hildenbrand, Lorenzo Stoakes

Replace all existing pgtable entry prints with recently added new format in
__print_bad_page_map_pgtable().

Signed-off-by: Anshuman Khandual <anshuman.khandual@arm.com>
---
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: David Hildenbrand <david@kernel.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>
Cc: linux-mm@kvack.org
Cc: linux-kernel@vger.kernel.org

 mm/memory.c | 15 +++++----------
 1 file changed, 5 insertions(+), 10 deletions(-)

diff --git a/mm/memory.c b/mm/memory.c
index 86a973119bd4..8a25790f7c24 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -521,7 +521,6 @@ static bool is_bad_page_map_ratelimited(void)
 
 static void __print_bad_page_map_pgtable(struct mm_struct *mm, unsigned long addr)
 {
-	unsigned long long pgdv, p4dv, pudv, pmdv;
 	p4d_t p4d, *p4dp;
 	pud_t pud, *pudp;
 	pmd_t pmd, *pmdp;
@@ -532,34 +531,30 @@ static void __print_bad_page_map_pgtable(struct mm_struct *mm, unsigned long add
 	 * see locking requirements for print_bad_page_map().
 	 */
 	pgdp = pgd_offset(mm, addr);
-	pgdv = pgd_val(*pgdp);
 
 	if (!pgd_present(*pgdp) || pgd_leaf(*pgdp)) {
-		pr_alert("pgd:%08llx\n", pgdv);
+		pr_alert("pgd:%ppgd\n", pgdp);
 		return;
 	}
 
 	p4dp = p4d_offset(pgdp, addr);
 	p4d = p4dp_get(p4dp);
-	p4dv = p4d_val(p4d);
 
 	if (!p4d_present(p4d) || p4d_leaf(p4d)) {
-		pr_alert("pgd:%08llx p4d:%08llx\n", pgdv, p4dv);
+		pr_alert("pgd:%ppgd p4d:%pp4d\n", pgdp, p4dp);
 		return;
 	}
 
 	pudp = pud_offset(p4dp, addr);
 	pud = pudp_get(pudp);
-	pudv = pud_val(pud);
 
 	if (!pud_present(pud) || pud_leaf(pud)) {
-		pr_alert("pgd:%08llx p4d:%08llx pud:%08llx\n", pgdv, p4dv, pudv);
+		pr_alert("pgd:%ppgd p4d:%pp4d pud:%ppud\n", pgdp, p4dp, pudp);
 		return;
 	}
 
 	pmdp = pmd_offset(pudp, addr);
 	pmd = pmdp_get(pmdp);
-	pmdv = pmd_val(pmd);
 
 	/*
 	 * Dumping the PTE would be nice, but it's tricky with CONFIG_HIGHPTE,
@@ -567,8 +562,8 @@ static void __print_bad_page_map_pgtable(struct mm_struct *mm, unsigned long add
 	 * doing another map would be bad. print_bad_page_map() should
 	 * already take care of printing the PTE.
 	 */
-	pr_alert("pgd:%08llx p4d:%08llx pud:%08llx pmd:%08llx\n", pgdv,
-		 p4dv, pudv, pmdv);
+	pr_alert("pgd:%ppgd p4d:%pp4d pud:%ppud pmd:%ppmd\n", pgdp,
+		 p4dp, pudp, pmdp);
 }
 
 /*
-- 
2.30.2



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [RFC V2 1/3] lib/vsprintf: Add support for pgtable entries
  2026-06-10  4:35 ` [RFC V2 1/3] " Anshuman Khandual
@ 2026-06-10 11:13   ` Usama Arif
  2026-06-11  5:15     ` Anshuman Khandual
  0 siblings, 1 reply; 15+ messages in thread
From: Usama Arif @ 2026-06-10 11:13 UTC (permalink / raw)
  To: Anshuman Khandual
  Cc: Usama Arif, linux-mm, Andy Shevchenko, Rasmus Villemoes,
	Sergey Senozhatsky, Petr Mladek, Steven Rostedt, Jonathan Corbet,
	Andrew Morton, David Hildenbrand, linux-kernel, linux-doc,
	David Hildenbrand, Lorenzo Stoakes, Andy Whitcroft

On Wed, 10 Jun 2026 05:35:43 +0100 Anshuman Khandual <anshuman.khandual@arm.com> wrote:

> Add some print formats for pgtable entries at any pgtable level. These new
> formats are %pp[g|4|u|m|t][d|e] i.e %ppgd, %pp4d, %ppud, %ppmd, and %ppte.
> These currently support both 32 bit and 64 bit pgtable entries that can be
> extended up to 128 bit when required.
> 
> Signed-off-by: Anshuman Khandual <anshuman.khandual@arm.com>
> ---
> Cc: Andrew Morton <akpm@linux-foundation.org>
> Cc: David Hildenbrand <david@kernel.org>
> Cc: Lorenzo Stoakes <ljs@kernel.org>
> Cc: Petr Mladek <pmladek@suse.com>
> Cc: Steven Rostedt <rostedt@goodmis.org>
> Cc: Jonathan Corbet <corbet@lwn.net>
> Cc: Andy Whitcroft <apw@canonical.com>
> Cc: linux-mm@kvack.org
> Cc: linux-kernel@vger.kernel.org
> Cc: linux-doc@vger.kernel.org
> 
>  Documentation/core-api/printk-formats.rst | 19 ++++++++
>  lib/vsprintf.c                            | 58 +++++++++++++++++++++++
>  scripts/checkpatch.pl                     |  2 +-
>  3 files changed, 78 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/core-api/printk-formats.rst b/Documentation/core-api/printk-formats.rst
> index c0b1b6089307..e69f91a9dd9d 100644
> --- a/Documentation/core-api/printk-formats.rst
> +++ b/Documentation/core-api/printk-formats.rst
> @@ -696,6 +696,25 @@ Rust
>  Only intended to be used from Rust code to format ``core::fmt::Arguments``.
>  Do *not* use it from C.
>  
> +Page Table Entry
> +----------------
> +
> +::
> +
> +        %p[pgd|p4dp|pud|pmd|pte]

s/p4dp/p4d to match others


> +
> +Print page table entry at any level.
> +
> +Passed by reference.
> +
> +Examples for a 64 bit page table entry, given &(u64)0xc0ffee::
> +
> +        %ppte   0x0000000000c0ffee
> +        %ppmd   0x0000000000c0ffee
> +        %ppud   0x0000000000c0ffee
> +        %pp4d   0x0000000000c0ffee
> +        %ppgd   0x0000000000c0ffee
> +
>  Thanks
>  ======
>  
> diff --git a/lib/vsprintf.c b/lib/vsprintf.c
> index 9f359b31c8d1..d4ad3048a4db 100644
> --- a/lib/vsprintf.c
> +++ b/lib/vsprintf.c
> @@ -856,6 +856,59 @@ static char *default_pointer(char *buf, char *end, const void *ptr,
>  	return ptr_to_id(buf, end, ptr, spec);
>  }
>  
> +static char *pxd_pointer(char *buf, char *end, const void *ptr,
> +			 struct printf_spec spec, const char *fmt)
> +{
> +	if (check_pointer(&buf, end, ptr, spec))
> +		return buf;
> +
> +	if (fmt[1] == 't' && fmt[2] == 'e') {
> +		pte_t *pte = (pte_t *)ptr;
> +
> +		static_assert(sizeof(pte_t) == 4 ||
> +			      sizeof(pte_t) == 8,
> +			      "pte_t size must be 4 or 8 bytes");
> +		return special_hex_number(buf, end, pte_val(ptep_get(pte)), sizeof(pte_t));
> +	}
> +
> +	if (fmt[1] == 'm' && fmt[2] == 'd') {
> +		pmd_t *pmd = (pmd_t *)ptr;
> +
> +		static_assert(sizeof(pmd_t) == 4 ||
> +			      sizeof(pmd_t) == 8,
> +			      "pmd_t size must be 4 or 8 bytes");
> +		return special_hex_number(buf, end, pmd_val(pmdp_get(pmd)), sizeof(pmd_t));
> +	}
> +
> +	if (fmt[1] == 'u' && fmt[2] == 'd') {
> +		pud_t *pud = (pud_t *)ptr;
> +
> +		static_assert(sizeof(pud_t) == 4 ||
> +			      sizeof(pud_t) == 8,
> +			      "pud_t size must be 4 or 8 bytes");
> +		return special_hex_number(buf, end, pud_val(pudp_get(pud)), sizeof(pud_t));
> +	}
> +
> +	if (fmt[1] == '4' && fmt[2] == 'd') {
> +		p4d_t *p4d = (p4d_t *)ptr;
> +
> +		static_assert(sizeof(p4d_t) == 4 ||
> +			      sizeof(p4d_t) == 8,
> +			      "p4d_t size must be 4 or 8 bytes");
> +		return special_hex_number(buf, end, p4d_val(p4dp_get(p4d)), sizeof(p4d_t));
> +	}
> +
> +	if (fmt[1] == 'g' && fmt[2] == 'd') {
> +		pgd_t *pgd = (pgd_t *)ptr;
> +
> +		static_assert(sizeof(pgd_t) == 4 ||
> +			      sizeof(pgd_t) == 8,
> +			      "pgd_t size must be 4 or 8 bytes");
> +		return special_hex_number(buf, end, pgd_val(pgdp_get(pgd)), sizeof(pgd_t));

You mentioned in the coverletter that pgdp_get() is the reason arm32 builds dont work.
Just wanted to check what the issue is?

I had a look at arch/arm/include/asm/pgtable.h and I couldnt understand why
it reads pgdp_get(pgpd) instead of pgdp_get(pgdp)?
   

> +	}
> +	return default_pointer(buf, end, ptr, spec);
> +}
> +
>  int kptr_restrict __read_mostly;
>  
>  static noinline_for_stack
> @@ -2506,6 +2559,9 @@ early_param("no_hash_pointers", no_hash_pointers_enable);
>   *		Without an option prints the full name of the node
>   *		f full name
>   *		P node name, including a possible unit address
> + * - 'p[g|4|u|m|t|][d|e]' For a page table entry, this prints its
> + *			  contents in a hexadecimal format
> + *
>   * - 'x' For printing the address unmodified. Equivalent to "%lx".
>   *       Please read the documentation (path below) before using!
>   * - '[ku]s' For a BPF/tracing related format specifier, e.g. used out of
> @@ -2615,6 +2671,8 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
>  		default:
>  			return error_string(buf, end, "(einval)", spec);
>  		}
> +	case 'p':
> +		return pxd_pointer(buf, end, ptr, spec, fmt);
>  	default:
>  		return default_pointer(buf, end, ptr, spec);
>  	}
> diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
> index 0492d6afc9a1..f68955858e29 100755
> --- a/scripts/checkpatch.pl
> +++ b/scripts/checkpatch.pl
> @@ -6975,7 +6975,7 @@ sub process {
>  				my $fmt = get_quoted_string($lines[$count - 1], raw_line($count, 0));
>  				$fmt =~ s/%%//g;
>  
> -				while ($fmt =~ /(\%[\*\d\.]*p(\w)(\w*))/g) {
> +				while ($fmt =~ /(\%[\*\d\.]*p(\w)(\w*)(pte|pmd|pud|p4d|pgd))/g) {
>  					$specifier = $1;
>  					$extension = $2;
>  					$qualifier = $3;
> -- 
> 2.30.2
> 
> 


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC V2 1/3] lib/vsprintf: Add support for pgtable entries
  2026-06-10 11:13   ` Usama Arif
@ 2026-06-11  5:15     ` Anshuman Khandual
  2026-06-11  7:17       ` Andy Shevchenko
  0 siblings, 1 reply; 15+ messages in thread
From: Anshuman Khandual @ 2026-06-11  5:15 UTC (permalink / raw)
  To: Usama Arif
  Cc: linux-mm, Andy Shevchenko, Rasmus Villemoes, Sergey Senozhatsky,
	Petr Mladek, Steven Rostedt, Jonathan Corbet, Andrew Morton,
	David Hildenbrand, linux-kernel, linux-doc, David Hildenbrand,
	Lorenzo Stoakes, Andy Whitcroft



On 10/06/26 4:43 PM, Usama Arif wrote:
> On Wed, 10 Jun 2026 05:35:43 +0100 Anshuman Khandual <anshuman.khandual@arm.com> wrote:
> 
>> Add some print formats for pgtable entries at any pgtable level. These new
>> formats are %pp[g|4|u|m|t][d|e] i.e %ppgd, %pp4d, %ppud, %ppmd, and %ppte.
>> These currently support both 32 bit and 64 bit pgtable entries that can be
>> extended up to 128 bit when required.
>>
>> Signed-off-by: Anshuman Khandual <anshuman.khandual@arm.com>
>> ---
>> Cc: Andrew Morton <akpm@linux-foundation.org>
>> Cc: David Hildenbrand <david@kernel.org>
>> Cc: Lorenzo Stoakes <ljs@kernel.org>
>> Cc: Petr Mladek <pmladek@suse.com>
>> Cc: Steven Rostedt <rostedt@goodmis.org>
>> Cc: Jonathan Corbet <corbet@lwn.net>
>> Cc: Andy Whitcroft <apw@canonical.com>
>> Cc: linux-mm@kvack.org
>> Cc: linux-kernel@vger.kernel.org
>> Cc: linux-doc@vger.kernel.org
>>
>>  Documentation/core-api/printk-formats.rst | 19 ++++++++
>>  lib/vsprintf.c                            | 58 +++++++++++++++++++++++
>>  scripts/checkpatch.pl                     |  2 +-
>>  3 files changed, 78 insertions(+), 1 deletion(-)
>>
>> diff --git a/Documentation/core-api/printk-formats.rst b/Documentation/core-api/printk-formats.rst
>> index c0b1b6089307..e69f91a9dd9d 100644
>> --- a/Documentation/core-api/printk-formats.rst
>> +++ b/Documentation/core-api/printk-formats.rst
>> @@ -696,6 +696,25 @@ Rust
>>  Only intended to be used from Rust code to format ``core::fmt::Arguments``.
>>  Do *not* use it from C.
>>  
>> +Page Table Entry
>> +----------------
>> +
>> +::
>> +
>> +        %p[pgd|p4dp|pud|pmd|pte]
> 
> s/p4dp/p4d to match others

Will fix.
> 
> 
>> +
>> +Print page table entry at any level.
>> +
>> +Passed by reference.
>> +
>> +Examples for a 64 bit page table entry, given &(u64)0xc0ffee::
>> +
>> +        %ppte   0x0000000000c0ffee
>> +        %ppmd   0x0000000000c0ffee
>> +        %ppud   0x0000000000c0ffee
>> +        %pp4d   0x0000000000c0ffee
>> +        %ppgd   0x0000000000c0ffee
>> +
>>  Thanks
>>  ======
>>  
>> diff --git a/lib/vsprintf.c b/lib/vsprintf.c
>> index 9f359b31c8d1..d4ad3048a4db 100644
>> --- a/lib/vsprintf.c
>> +++ b/lib/vsprintf.c
>> @@ -856,6 +856,59 @@ static char *default_pointer(char *buf, char *end, const void *ptr,
>>  	return ptr_to_id(buf, end, ptr, spec);
>>  }
>>  
>> +static char *pxd_pointer(char *buf, char *end, const void *ptr,
>> +			 struct printf_spec spec, const char *fmt)
>> +{
>> +	if (check_pointer(&buf, end, ptr, spec))
>> +		return buf;
>> +
>> +	if (fmt[1] == 't' && fmt[2] == 'e') {
>> +		pte_t *pte = (pte_t *)ptr;
>> +
>> +		static_assert(sizeof(pte_t) == 4 ||
>> +			      sizeof(pte_t) == 8,
>> +			      "pte_t size must be 4 or 8 bytes");
>> +		return special_hex_number(buf, end, pte_val(ptep_get(pte)), sizeof(pte_t));
>> +	}
>> +
>> +	if (fmt[1] == 'm' && fmt[2] == 'd') {
>> +		pmd_t *pmd = (pmd_t *)ptr;
>> +
>> +		static_assert(sizeof(pmd_t) == 4 ||
>> +			      sizeof(pmd_t) == 8,
>> +			      "pmd_t size must be 4 or 8 bytes");
>> +		return special_hex_number(buf, end, pmd_val(pmdp_get(pmd)), sizeof(pmd_t));
>> +	}
>> +
>> +	if (fmt[1] == 'u' && fmt[2] == 'd') {
>> +		pud_t *pud = (pud_t *)ptr;
>> +
>> +		static_assert(sizeof(pud_t) == 4 ||
>> +			      sizeof(pud_t) == 8,
>> +			      "pud_t size must be 4 or 8 bytes");
>> +		return special_hex_number(buf, end, pud_val(pudp_get(pud)), sizeof(pud_t));
>> +	}
>> +
>> +	if (fmt[1] == '4' && fmt[2] == 'd') {
>> +		p4d_t *p4d = (p4d_t *)ptr;
>> +
>> +		static_assert(sizeof(p4d_t) == 4 ||
>> +			      sizeof(p4d_t) == 8,
>> +			      "p4d_t size must be 4 or 8 bytes");
>> +		return special_hex_number(buf, end, p4d_val(p4dp_get(p4d)), sizeof(p4d_t));
>> +	}
>> +
>> +	if (fmt[1] == 'g' && fmt[2] == 'd') {
>> +		pgd_t *pgd = (pgd_t *)ptr;
>> +
>> +		static_assert(sizeof(pgd_t) == 4 ||
>> +			      sizeof(pgd_t) == 8,
>> +			      "pgd_t size must be 4 or 8 bytes");
>> +		return special_hex_number(buf, end, pgd_val(pgdp_get(pgd)), sizeof(pgd_t));
> 
> You mentioned in the coverletter that pgdp_get() is the reason arm32 builds dont work.
> Just wanted to check what the issue is?
> 
> I had a look at arch/arm/include/asm/pgtable.h and I couldnt understand why
> it reads pgdp_get(pgpd) instead of pgdp_get(pgdp)?

Right - that's a typo.

Following arm32 pgtable header change enables the build.

diff --git a/arch/arm/include/asm/pgtable-2level-types.h b/arch/arm/include/asm/pgtable-2level-types.h
index 650e793f4142..3f1d52402129 100644
--- a/arch/arm/include/asm/pgtable-2level-types.h
+++ b/arch/arm/include/asm/pgtable-2level-types.h
@@ -31,6 +31,7 @@ typedef struct { pteval_t pgprot; } pgprot_t;
 #define __pte(x)        ((pte_t) { (x) } )
 #define __pmd(x)        ((pmd_t) { (x) } )
 #define __pgprot(x)     ((pgprot_t) { (x) } )
+#define __pgd(x)        ((pgd_t) { { (x), 0 } })

 #else
 /*
@@ -49,6 +50,7 @@ typedef pteval_t pgprot_t;
 #define __pte(x)        (x)
 #define __pmd(x)        (x)
 #define __pgprot(x)     (x)
+#define __pgd(x)        { (x), 0 }

 #endif /* STRICT_MM_TYPECHECKS */

diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index 982795cf4563..349e1f819385 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -141,7 +141,7 @@ extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,

 extern pgd_t swapper_pg_dir[PTRS_PER_PGD];

-#define pgdp_get(pgpd)         READ_ONCE(*pgdp)
+#define pgdp_get(pgdp)         READ_ONCE(*pgdp)

 #define pud_page(pud)          pmd_page(__pmd(pud_val(pud)))
 #define pud_write(pud)         pmd_write(__pmd(pud_val(pud)))
>    
> 
>> +	}
>> +	return default_pointer(buf, end, ptr, spec);
>> +}
>> +
>>  int kptr_restrict __read_mostly;
>>  
>>  static noinline_for_stack
>> @@ -2506,6 +2559,9 @@ early_param("no_hash_pointers", no_hash_pointers_enable);
>>   *		Without an option prints the full name of the node
>>   *		f full name
>>   *		P node name, including a possible unit address
>> + * - 'p[g|4|u|m|t|][d|e]' For a page table entry, this prints its
>> + *			  contents in a hexadecimal format
>> + *
>>   * - 'x' For printing the address unmodified. Equivalent to "%lx".
>>   *       Please read the documentation (path below) before using!
>>   * - '[ku]s' For a BPF/tracing related format specifier, e.g. used out of
>> @@ -2615,6 +2671,8 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
>>  		default:
>>  			return error_string(buf, end, "(einval)", spec);
>>  		}
>> +	case 'p':
>> +		return pxd_pointer(buf, end, ptr, spec, fmt);
>>  	default:
>>  		return default_pointer(buf, end, ptr, spec);
>>  	}
>> diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
>> index 0492d6afc9a1..f68955858e29 100755
>> --- a/scripts/checkpatch.pl
>> +++ b/scripts/checkpatch.pl
>> @@ -6975,7 +6975,7 @@ sub process {
>>  				my $fmt = get_quoted_string($lines[$count - 1], raw_line($count, 0));
>>  				$fmt =~ s/%%//g;
>>  
>> -				while ($fmt =~ /(\%[\*\d\.]*p(\w)(\w*))/g) {
>> +				while ($fmt =~ /(\%[\*\d\.]*p(\w)(\w*)(pte|pmd|pud|p4d|pgd))/g) {
>>  					$specifier = $1;
>>  					$extension = $2;
>>  					$qualifier = $3;
>> -- 
>> 2.30.2
>>
>>



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [RFC V2 1/3] lib/vsprintf: Add support for pgtable entries
  2026-06-11  5:15     ` Anshuman Khandual
@ 2026-06-11  7:17       ` Andy Shevchenko
  2026-06-11  9:50         ` Anshuman Khandual
  0 siblings, 1 reply; 15+ messages in thread
From: Andy Shevchenko @ 2026-06-11  7:17 UTC (permalink / raw)
  To: Anshuman Khandual
  Cc: Usama Arif, linux-mm, Rasmus Villemoes, Sergey Senozhatsky,
	Petr Mladek, Steven Rostedt, Jonathan Corbet, Andrew Morton,
	David Hildenbrand, linux-kernel, linux-doc, David Hildenbrand,
	Lorenzo Stoakes, Andy Whitcroft

On Thu, Jun 11, 2026 at 10:45:01AM +0530, Anshuman Khandual wrote:
> On 10/06/26 4:43 PM, Usama Arif wrote:
> > On Wed, 10 Jun 2026 05:35:43 +0100 Anshuman Khandual <anshuman.khandual@arm.com> wrote:

...

> >> +		static_assert(sizeof(pte_t) == 4 ||
> >> +			      sizeof(pte_t) == 8,
> >> +			      "pte_t size must be 4 or 8 bytes");

Besides occupying too many lines, why are these static asserts hidden here and
not declared in the global space? More wide Q is why they are needed at all?

-- 
With Best Regards,
Andy Shevchenko




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC V2 1/3] lib/vsprintf: Add support for pgtable entries
  2026-06-11  7:17       ` Andy Shevchenko
@ 2026-06-11  9:50         ` Anshuman Khandual
  2026-06-11 18:59           ` Andy Shevchenko
  0 siblings, 1 reply; 15+ messages in thread
From: Anshuman Khandual @ 2026-06-11  9:50 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Usama Arif, linux-mm, Rasmus Villemoes, Sergey Senozhatsky,
	Petr Mladek, Steven Rostedt, Jonathan Corbet, Andrew Morton,
	David Hildenbrand, linux-kernel, linux-doc, David Hildenbrand,
	Lorenzo Stoakes, Andy Whitcroft



On 11/06/26 12:47 PM, Andy Shevchenko wrote:
> On Thu, Jun 11, 2026 at 10:45:01AM +0530, Anshuman Khandual wrote:
>> On 10/06/26 4:43 PM, Usama Arif wrote:
>>> On Wed, 10 Jun 2026 05:35:43 +0100 Anshuman Khandual <anshuman.khandual@arm.com> wrote:
> 
> ...
> 
>>>> +		static_assert(sizeof(pte_t) == 4 ||
>>>> +			      sizeof(pte_t) == 8,
>>>> +			      "pte_t size must be 4 or 8 bytes");
> 
> Besides occupying too many lines, why are these static asserts hidden here and
> not declared in the global space? More wide Q is why they are needed at all?

Sure, will move these static_assert just above pxd_pointer()
These asserts ensure

- Platforms have either 32 bit or 64 bit pgtable descriptors
- special_hex_number() can be used to print such descriptors



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC V2 3/3] mm: Replace pgtable entry prints with new format
  2026-06-10  4:35 ` [RFC V2 3/3] mm: Replace pgtable entry prints with new format Anshuman Khandual
@ 2026-06-11 11:32   ` David Hildenbrand (Arm)
  2026-06-12 11:08   ` David Hildenbrand (Arm)
  1 sibling, 0 replies; 15+ messages in thread
From: David Hildenbrand (Arm) @ 2026-06-11 11:32 UTC (permalink / raw)
  To: Anshuman Khandual, linux-mm
  Cc: Andy Shevchenko, Rasmus Villemoes, Sergey Senozhatsky,
	Petr Mladek, Steven Rostedt, Jonathan Corbet, Andrew Morton,
	linux-kernel, linux-doc, Lorenzo Stoakes

On 6/10/26 06:35, Anshuman Khandual wrote:
> Replace all existing pgtable entry prints with recently added new format in
> __print_bad_page_map_pgtable().
> 
> Signed-off-by: Anshuman Khandual <anshuman.khandual@arm.com>
> ---
> Cc: Andrew Morton <akpm@linux-foundation.org>
> Cc: David Hildenbrand <david@kernel.org>
> Cc: Lorenzo Stoakes <ljs@kernel.org>
> Cc: linux-mm@kvack.org
> Cc: linux-kernel@vger.kernel.org
> 
>  mm/memory.c | 15 +++++----------
>  1 file changed, 5 insertions(+), 10 deletions(-)
> 
> diff --git a/mm/memory.c b/mm/memory.c
> index 86a973119bd4..8a25790f7c24 100644
> --- a/mm/memory.c
> +++ b/mm/memory.c
> @@ -521,7 +521,6 @@ static bool is_bad_page_map_ratelimited(void)
>  
>  static void __print_bad_page_map_pgtable(struct mm_struct *mm, unsigned long addr)
>  {
> -	unsigned long long pgdv, p4dv, pudv, pmdv;
>  	p4d_t p4d, *p4dp;
>  	pud_t pud, *pudp;
>  	pmd_t pmd, *pmdp;
> @@ -532,34 +531,30 @@ static void __print_bad_page_map_pgtable(struct mm_struct *mm, unsigned long add
>  	 * see locking requirements for print_bad_page_map().
>  	 */
>  	pgdp = pgd_offset(mm, addr);
> -	pgdv = pgd_val(*pgdp);
>  
>  	if (!pgd_present(*pgdp) || pgd_leaf(*pgdp)) {
> -		pr_alert("pgd:%08llx\n", pgdv);
> +		pr_alert("pgd:%ppgd\n", pgdp);
>  		return;
>  	}
>  
>  	p4dp = p4d_offset(pgdp, addr);
>  	p4d = p4dp_get(p4dp);
> -	p4dv = p4d_val(p4d);
>  
>  	if (!p4d_present(p4d) || p4d_leaf(p4d)) {
> -		pr_alert("pgd:%08llx p4d:%08llx\n", pgdv, p4dv);
> +		pr_alert("pgd:%ppgd p4d:%pp4d\n", pgdp, p4dp);
>  		return;
>  	}
>  
>  	pudp = pud_offset(p4dp, addr);
>  	pud = pudp_get(pudp);
> -	pudv = pud_val(pud);
>  
>  	if (!pud_present(pud) || pud_leaf(pud)) {
> -		pr_alert("pgd:%08llx p4d:%08llx pud:%08llx\n", pgdv, p4dv, pudv);
> +		pr_alert("pgd:%ppgd p4d:%pp4d pud:%ppud\n", pgdp, p4dp, pudp);
>  		return;
>  	}
>  
>  	pmdp = pmd_offset(pudp, addr);
>  	pmd = pmdp_get(pmdp);
> -	pmdv = pmd_val(pmd);
>  
>  	/*
>  	 * Dumping the PTE would be nice, but it's tricky with CONFIG_HIGHPTE,
> @@ -567,8 +562,8 @@ static void __print_bad_page_map_pgtable(struct mm_struct *mm, unsigned long add
>  	 * doing another map would be bad. print_bad_page_map() should
>  	 * already take care of printing the PTE.
>  	 */
> -	pr_alert("pgd:%08llx p4d:%08llx pud:%08llx pmd:%08llx\n", pgdv,
> -		 p4dv, pudv, pmdv);
> +	pr_alert("pgd:%ppgd p4d:%pp4d pud:%ppud pmd:%ppmd\n", pgdp,
> +		 p4dp, pudp, pmdp);
>  }
>  
>  /*

I like that! I guess having per-level format identifiers is the right approach
given that we have per-level types.

Acked-by: David Hildenbrand (Arm) <david@kernel.org>


-- 
Cheers,

David


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC V2 1/3] lib/vsprintf: Add support for pgtable entries
  2026-06-11  9:50         ` Anshuman Khandual
@ 2026-06-11 18:59           ` Andy Shevchenko
  0 siblings, 0 replies; 15+ messages in thread
From: Andy Shevchenko @ 2026-06-11 18:59 UTC (permalink / raw)
  To: Anshuman Khandual
  Cc: Usama Arif, linux-mm, Rasmus Villemoes, Sergey Senozhatsky,
	Petr Mladek, Steven Rostedt, Jonathan Corbet, Andrew Morton,
	David Hildenbrand, linux-kernel, linux-doc, David Hildenbrand,
	Lorenzo Stoakes, Andy Whitcroft

On Thu, Jun 11, 2026 at 03:20:13PM +0530, Anshuman Khandual wrote:
> On 11/06/26 12:47 PM, Andy Shevchenko wrote:
> > On Thu, Jun 11, 2026 at 10:45:01AM +0530, Anshuman Khandual wrote:
> >> On 10/06/26 4:43 PM, Usama Arif wrote:
> >>> On Wed, 10 Jun 2026 05:35:43 +0100 Anshuman Khandual <anshuman.khandual@arm.com> wrote:

...

> >>>> +		static_assert(sizeof(pte_t) == 4 ||
> >>>> +			      sizeof(pte_t) == 8,
> >>>> +			      "pte_t size must be 4 or 8 bytes");
> > 
> > Besides occupying too many lines, why are these static asserts hidden here and
> > not declared in the global space? More wide Q is why they are needed at all?
> 
> Sure, will move these static_assert just above pxd_pointer()
> These asserts ensure
> 
> - Platforms have either 32 bit or 64 bit pgtable descriptors
> - special_hex_number() can be used to print such descriptors

I understand that. My question is do we actually _need_ them? In other words
when this may be not satisfied? Any real (non-theoretical) example?

-- 
With Best Regards,
Andy Shevchenko




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC V2 0/3] lib/vsprintf: Add support for pgtable entries
  2026-06-10  4:35 [RFC V2 0/3] lib/vsprintf: Add support for pgtable entries Anshuman Khandual
                   ` (2 preceding siblings ...)
  2026-06-10  4:35 ` [RFC V2 3/3] mm: Replace pgtable entry prints with new format Anshuman Khandual
@ 2026-06-11 19:15 ` Matthew Wilcox
  2026-06-11 19:33   ` Andy Shevchenko
  3 siblings, 1 reply; 15+ messages in thread
From: Matthew Wilcox @ 2026-06-11 19:15 UTC (permalink / raw)
  To: Anshuman Khandual
  Cc: linux-mm, Andy Shevchenko, Rasmus Villemoes, Sergey Senozhatsky,
	Petr Mladek, Steven Rostedt, Jonathan Corbet, Andrew Morton,
	David Hildenbrand, linux-kernel, linux-doc

On Wed, Jun 10, 2026 at 05:35:42AM +0100, Anshuman Khandual wrote:
> Printing page table entries has been a common requirement both in generic
> and platform memory management for various purposes. Hence let's create a
> dedicated printk format for such entries which will also help standardize
> pgtable printing across different platforms.

You didn't address my objection here:

https://lore.kernel.org/linux-mm/aFQP8LzVMctf6XH5@casper.infradead.org/

ie there is now no typechecking possible.  So you've made it more
dangerous.  I reiterate my NACK to the concept, not to the implementation.


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC V2 0/3] lib/vsprintf: Add support for pgtable entries
  2026-06-11 19:15 ` [RFC V2 0/3] lib/vsprintf: Add support for pgtable entries Matthew Wilcox
@ 2026-06-11 19:33   ` Andy Shevchenko
  2026-06-11 19:37     ` Matthew Wilcox
  0 siblings, 1 reply; 15+ messages in thread
From: Andy Shevchenko @ 2026-06-11 19:33 UTC (permalink / raw)
  To: Matthew Wilcox
  Cc: Anshuman Khandual, linux-mm, Rasmus Villemoes, Sergey Senozhatsky,
	Petr Mladek, Steven Rostedt, Jonathan Corbet, Andrew Morton,
	David Hildenbrand, linux-kernel, linux-doc

On Thu, Jun 11, 2026 at 08:15:57PM +0100, Matthew Wilcox wrote:
> On Wed, Jun 10, 2026 at 05:35:42AM +0100, Anshuman Khandual wrote:
> > Printing page table entries has been a common requirement both in generic
> > and platform memory management for various purposes. Hence let's create a
> > dedicated printk format for such entries which will also help standardize
> > pgtable printing across different platforms.
> 
> You didn't address my objection here:
> 
> https://lore.kernel.org/linux-mm/aFQP8LzVMctf6XH5@casper.infradead.org/
> 
> ie there is now no typechecking possible.  So you've made it more
> dangerous.  I reiterate my NACK to the concept, not to the implementation.

But this is more of a global question, how do we check the validity of
the parameters of pointer extensions in the kernel? Does anybody go to
commit into GCC plugin or so for this job?

-- 
With Best Regards,
Andy Shevchenko




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC V2 0/3] lib/vsprintf: Add support for pgtable entries
  2026-06-11 19:33   ` Andy Shevchenko
@ 2026-06-11 19:37     ` Matthew Wilcox
  2026-06-12 11:14       ` David Hildenbrand (Arm)
  0 siblings, 1 reply; 15+ messages in thread
From: Matthew Wilcox @ 2026-06-11 19:37 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Anshuman Khandual, linux-mm, Rasmus Villemoes, Sergey Senozhatsky,
	Petr Mladek, Steven Rostedt, Jonathan Corbet, Andrew Morton,
	David Hildenbrand, linux-kernel, linux-doc

On Thu, Jun 11, 2026 at 10:33:35PM +0300, Andy Shevchenko wrote:
> On Thu, Jun 11, 2026 at 08:15:57PM +0100, Matthew Wilcox wrote:
> > On Wed, Jun 10, 2026 at 05:35:42AM +0100, Anshuman Khandual wrote:
> > > Printing page table entries has been a common requirement both in generic
> > > and platform memory management for various purposes. Hence let's create a
> > > dedicated printk format for such entries which will also help standardize
> > > pgtable printing across different platforms.
> > 
> > You didn't address my objection here:
> > 
> > https://lore.kernel.org/linux-mm/aFQP8LzVMctf6XH5@casper.infradead.org/
> > 
> > ie there is now no typechecking possible.  So you've made it more
> > dangerous.  I reiterate my NACK to the concept, not to the implementation.
> 
> But this is more of a global question, how do we check the validity of
> the parameters of pointer extensions in the kernel? Does anybody go to
> commit into GCC plugin or so for this job?

I agree that it's a global question that it would be great for somebody
to answer.  But it's specifically a problem for this patchset because:

 - It's really easy to get confused about which page table level you're
   working on.  And hugetlbfs deliberately increases that confusion.
 - Different levels of the page tables actually do have different sizes
   on some architectures, so if you think you're looking at a pointer to a
   64-bit quantity when it's really a pointer to a 32-bit quantity, things
   Will Go Wrong (or vice-versa.  And some architctures are big-endian)
 - But on x86-64, Everything Is Fine because all levels of the page table
   are basically identical, so you'll never notice there's a problem.


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC V2 3/3] mm: Replace pgtable entry prints with new format
  2026-06-10  4:35 ` [RFC V2 3/3] mm: Replace pgtable entry prints with new format Anshuman Khandual
  2026-06-11 11:32   ` David Hildenbrand (Arm)
@ 2026-06-12 11:08   ` David Hildenbrand (Arm)
  1 sibling, 0 replies; 15+ messages in thread
From: David Hildenbrand (Arm) @ 2026-06-12 11:08 UTC (permalink / raw)
  To: Anshuman Khandual, linux-mm
  Cc: Andy Shevchenko, Rasmus Villemoes, Sergey Senozhatsky,
	Petr Mladek, Steven Rostedt, Jonathan Corbet, Andrew Morton,
	linux-kernel, linux-doc, Lorenzo Stoakes

On 6/10/26 06:35, Anshuman Khandual wrote:
> Replace all existing pgtable entry prints with recently added new format in
> __print_bad_page_map_pgtable().
> 
> Signed-off-by: Anshuman Khandual <anshuman.khandual@arm.com>
> ---
> Cc: Andrew Morton <akpm@linux-foundation.org>
> Cc: David Hildenbrand <david@kernel.org>
> Cc: Lorenzo Stoakes <ljs@kernel.org>
> Cc: linux-mm@kvack.org
> Cc: linux-kernel@vger.kernel.org
> 
>  mm/memory.c | 15 +++++----------
>  1 file changed, 5 insertions(+), 10 deletions(-)
> 
> diff --git a/mm/memory.c b/mm/memory.c
> index 86a973119bd4..8a25790f7c24 100644
> --- a/mm/memory.c
> +++ b/mm/memory.c
> @@ -521,7 +521,6 @@ static bool is_bad_page_map_ratelimited(void)
>  
>  static void __print_bad_page_map_pgtable(struct mm_struct *mm, unsigned long addr)
>  {
> -	unsigned long long pgdv, p4dv, pudv, pmdv;
>  	p4d_t p4d, *p4dp;
>  	pud_t pud, *pudp;
>  	pmd_t pmd, *pmdp;
> @@ -532,34 +531,30 @@ static void __print_bad_page_map_pgtable(struct mm_struct *mm, unsigned long add
>  	 * see locking requirements for print_bad_page_map().
>  	 */
>  	pgdp = pgd_offset(mm, addr);
> -	pgdv = pgd_val(*pgdp);
>  
>  	if (!pgd_present(*pgdp) || pgd_leaf(*pgdp)) {
> -		pr_alert("pgd:%08llx\n", pgdv);
> +		pr_alert("pgd:%ppgd\n", pgdp);
>  		return;
>  	}
>  
>  	p4dp = p4d_offset(pgdp, addr);
>  	p4d = p4dp_get(p4dp);
> -	p4dv = p4d_val(p4d);
>  
>  	if (!p4d_present(p4d) || p4d_leaf(p4d)) {
> -		pr_alert("pgd:%08llx p4d:%08llx\n", pgdv, p4dv);
> +		pr_alert("pgd:%ppgd p4d:%pp4d\n", pgdp, p4dp);
>  		return;
>  	}
>  
>  	pudp = pud_offset(p4dp, addr);
>  	pud = pudp_get(pudp);
> -	pudv = pud_val(pud);
>  
>  	if (!pud_present(pud) || pud_leaf(pud)) {
> -		pr_alert("pgd:%08llx p4d:%08llx pud:%08llx\n", pgdv, p4dv, pudv);
> +		pr_alert("pgd:%ppgd p4d:%pp4d pud:%ppud\n", pgdp, p4dp, pudp);
>  		return;
>  	}
>  
>  	pmdp = pmd_offset(pudp, addr);
>  	pmd = pmdp_get(pmdp);
> -	pmdv = pmd_val(pmd);
>  
>  	/*
>  	 * Dumping the PTE would be nice, but it's tricky with CONFIG_HIGHPTE,
> @@ -567,8 +562,8 @@ static void __print_bad_page_map_pgtable(struct mm_struct *mm, unsigned long add
>  	 * doing another map would be bad. print_bad_page_map() should
>  	 * already take care of printing the PTE.
>  	 */
> -	pr_alert("pgd:%08llx p4d:%08llx pud:%08llx pmd:%08llx\n", pgdv,
> -		 p4dv, pudv, pmdv);
> +	pr_alert("pgd:%ppgd p4d:%pp4d pud:%ppud pmd:%ppmd\n", pgdp,
> +		 p4dp, pudp, pmdp);
>  }
>  
>  /*


After some off-list discussion, I wonder if we can make our life easier.

I think, even with your patch, there is still the case:

pr_alert("BUG: Bad page map in process %s  %s:%08llx", current->comm,
	 pgtable_level_to_str(level), entry);

Where we cast all entries to an "unsigned long" in the callers. We'd have to rework all
that for 128bit entries either way (passing them in some struct instead).

I really just extended what we used to do here in print_bad_pte() before commit ec63a44011d.

Maybe we should just drop the "print the involved page table entries" thing?

I mean, we do have the actual page, and we do have the address in the address space, which
we all print.

Not sure if the actual page table entries are that relevant? Would clean up nicely:


From a1673198f9687b307496903b3f516a3c00f76199 Mon Sep 17 00:00:00 2001
From: "David Hildenbrand (Arm)" <david@kernel.org>
Date: Fri, 12 Jun 2026 13:06:00 +0200
Subject: [PATCH] tmp

Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/memory.c | 80 +++++++++--------------------------------------------
 1 file changed, 13 insertions(+), 67 deletions(-)

diff --git a/mm/memory.c b/mm/memory.c
index d4b3540ae659..989f7d6b280d 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -519,58 +519,6 @@ static bool is_bad_page_map_ratelimited(void)
 	return false;
 }
 
-static void __print_bad_page_map_pgtable(struct mm_struct *mm, unsigned long addr)
-{
-	unsigned long long pgdv, p4dv, pudv, pmdv;
-	p4d_t p4d, *p4dp;
-	pud_t pud, *pudp;
-	pmd_t pmd, *pmdp;
-	pgd_t *pgdp;
-
-	/*
-	 * Although this looks like a fully lockless pgtable walk, it is not:
-	 * see locking requirements for print_bad_page_map().
-	 */
-	pgdp = pgd_offset(mm, addr);
-	pgdv = pgd_val(*pgdp);
-
-	if (!pgd_present(*pgdp) || pgd_leaf(*pgdp)) {
-		pr_alert("pgd:%08llx\n", pgdv);
-		return;
-	}
-
-	p4dp = p4d_offset(pgdp, addr);
-	p4d = p4dp_get(p4dp);
-	p4dv = p4d_val(p4d);
-
-	if (!p4d_present(p4d) || p4d_leaf(p4d)) {
-		pr_alert("pgd:%08llx p4d:%08llx\n", pgdv, p4dv);
-		return;
-	}
-
-	pudp = pud_offset(p4dp, addr);
-	pud = pudp_get(pudp);
-	pudv = pud_val(pud);
-
-	if (!pud_present(pud) || pud_leaf(pud)) {
-		pr_alert("pgd:%08llx p4d:%08llx pud:%08llx\n", pgdv, p4dv, pudv);
-		return;
-	}
-
-	pmdp = pmd_offset(pudp, addr);
-	pmd = pmdp_get(pmdp);
-	pmdv = pmd_val(pmd);
-
-	/*
-	 * Dumping the PTE would be nice, but it's tricky with CONFIG_HIGHPTE,
-	 * because the table should already be mapped by the caller and
-	 * doing another map would be bad. print_bad_page_map() should
-	 * already take care of printing the PTE.
-	 */
-	pr_alert("pgd:%08llx p4d:%08llx pud:%08llx pmd:%08llx\n", pgdv,
-		 p4dv, pudv, pmdv);
-}
-
 /*
  * This function is called to print an error when a bad page table entry (e.g.,
  * corrupted page table entry) is found. For example, we might have a
@@ -584,8 +532,7 @@ static void __print_bad_page_map_pgtable(struct mm_struct *mm, unsigned long add
  * page table lock.
  */
 static void print_bad_page_map(struct vm_area_struct *vma,
-		unsigned long addr, unsigned long long entry, struct page *page,
-		enum pgtable_level level)
+		unsigned long addr, struct page *page, enum pgtable_level level)
 {
 	struct address_space *mapping;
 	pgoff_t index;
@@ -596,9 +543,8 @@ static void print_bad_page_map(struct vm_area_struct *vma,
 	mapping = vma->vm_file ? vma->vm_file->f_mapping : NULL;
 	index = linear_page_index(vma, addr);
 
-	pr_alert("BUG: Bad page map in process %s  %s:%08llx", current->comm,
-		 pgtable_level_to_str(level), entry);
-	__print_bad_page_map_pgtable(vma->vm_mm, addr);
+	pr_alert("BUG: Bad page map in process %s on %s level", current->comm,
+		 pgtable_level_to_str(level));
 	if (page)
 		dump_page(page, "bad page map");
 	pr_alert("addr:%px vm_flags:%08lx anon_vma:%px mapping:%px index:%lx\n",
@@ -627,8 +573,8 @@ static inline bool pgtable_level_has_pxx_special(enum pgtable_level level)
 	}
 }
 
-#define print_bad_pte(vma, addr, pte, page) \
-	print_bad_page_map(vma, addr, pte_val(pte), page, PGTABLE_LEVEL_PTE)
+#define print_bad_pte(vma, addr, page) \
+	print_bad_page_map(vma, addr, page, PGTABLE_LEVEL_PTE)
 
 /**
  * __vm_normal_page() - Get the "struct page" associated with a page table entry.
@@ -697,7 +643,7 @@ static inline bool pgtable_level_has_pxx_special(enum pgtable_level level)
  */
 static inline struct page *__vm_normal_page(struct vm_area_struct *vma,
 		unsigned long addr, unsigned long pfn, bool special,
-		unsigned long long entry, enum pgtable_level level)
+		enum pgtable_level level)
 {
 	if (pgtable_level_has_pxx_special(level)) {
 		if (unlikely(special)) {
@@ -710,7 +656,7 @@ static inline struct page *__vm_normal_page(struct vm_area_struct *vma,
 			if (is_zero_pfn(pfn) || is_huge_zero_pfn(pfn))
 				return NULL;
 
-			print_bad_page_map(vma, addr, entry, NULL, level);
+			print_bad_page_map(vma, addr, NULL, level);
 			return NULL;
 		}
 		/*
@@ -741,7 +687,7 @@ static inline struct page *__vm_normal_page(struct vm_area_struct *vma,
 
 	if (unlikely(pfn > highest_memmap_pfn)) {
 		/* Corrupted page table entry. */
-		print_bad_page_map(vma, addr, entry, NULL, level);
+		print_bad_page_map(vma, addr, NULL, level);
 		return NULL;
 	}
 	/*
@@ -768,7 +714,7 @@ struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr,
 			    pte_t pte)
 {
 	return __vm_normal_page(vma, addr, pte_pfn(pte), pte_special(pte),
-				pte_val(pte), PGTABLE_LEVEL_PTE);
+				PGTABLE_LEVEL_PTE);
 }
 
 /**
@@ -810,7 +756,7 @@ struct page *vm_normal_page_pmd(struct vm_area_struct *vma, unsigned long addr,
 				pmd_t pmd)
 {
 	return __vm_normal_page(vma, addr, pmd_pfn(pmd), pmd_special(pmd),
-				pmd_val(pmd), PGTABLE_LEVEL_PMD);
+				PGTABLE_LEVEL_PMD);
 }
 
 /**
@@ -851,7 +797,7 @@ struct page *vm_normal_page_pud(struct vm_area_struct *vma,
 		unsigned long addr, pud_t pud)
 {
 	return __vm_normal_page(vma, addr, pud_pfn(pud), pud_special(pud),
-				pud_val(pud), PGTABLE_LEVEL_PUD);
+				PGTABLE_LEVEL_PUD);
 }
 #endif
 
@@ -1672,7 +1618,7 @@ static __always_inline void zap_present_folio_ptes(struct mmu_gather *tlb,
 		folio_remove_rmap_ptes(folio, page, nr, vma);
 
 		if (unlikely(folio_mapcount(folio) < 0))
-			print_bad_pte(vma, addr, ptent, page);
+			print_bad_pte(vma, addr, page);
 	}
 	if (unlikely(__tlb_remove_folio_pages(tlb, page, nr, delay_rmap))) {
 		*force_flush = true;
@@ -4812,7 +4758,7 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
 		} else if (softleaf_is_marker(entry)) {
 			ret = handle_pte_marker(vmf);
 		} else {
-			print_bad_pte(vma, vmf->address, vmf->orig_pte, NULL);
+			print_bad_pte(vma, vmf->address, NULL);
 			ret = VM_FAULT_SIGBUS;
 		}
 		goto out;
-- 
2.43.0



-- 
Cheers,

David


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [RFC V2 0/3] lib/vsprintf: Add support for pgtable entries
  2026-06-11 19:37     ` Matthew Wilcox
@ 2026-06-12 11:14       ` David Hildenbrand (Arm)
  0 siblings, 0 replies; 15+ messages in thread
From: David Hildenbrand (Arm) @ 2026-06-12 11:14 UTC (permalink / raw)
  To: Matthew Wilcox, Andy Shevchenko
  Cc: Anshuman Khandual, linux-mm, Rasmus Villemoes, Sergey Senozhatsky,
	Petr Mladek, Steven Rostedt, Jonathan Corbet, Andrew Morton,
	linux-kernel, linux-doc

On 6/11/26 21:37, Matthew Wilcox wrote:
> On Thu, Jun 11, 2026 at 10:33:35PM +0300, Andy Shevchenko wrote:
>> On Thu, Jun 11, 2026 at 08:15:57PM +0100, Matthew Wilcox wrote:
>>>
>>> You didn't address my objection here:
>>>
>>> https://lore.kernel.org/linux-mm/aFQP8LzVMctf6XH5@casper.infradead.org/
>>>
>>> ie there is now no typechecking possible.  So you've made it more
>>> dangerous.  I reiterate my NACK to the concept, not to the implementation.
>>
>> But this is more of a global question, how do we check the validity of
>> the parameters of pointer extensions in the kernel? Does anybody go to
>> commit into GCC plugin or so for this job?
> 
> I agree that it's a global question that it would be great for somebody
> to answer.  But it's specifically a problem for this patchset because:
> 
>  - It's really easy to get confused about which page table level you're
>    working on.  And hugetlbfs deliberately increases that confusion.

Yeah ... so far I was assuming that for hugetlb, all relevant entries (what we
call a PTE although it isn't ....) would have to be the same size. I mean, at
least in the callers they are the same size (pte_t)

>  - Different levels of the page tables actually do have different sizes
>    on some architectures, so if you think you're looking at a pointer to a
>    64-bit quantity when it's really a pointer to a 32-bit quantity, things
>    Will Go Wrong (or vice-versa.  And some architctures are big-endian)

I see your point with the pass-by-pointer.

>  - But on x86-64, Everything Is Fine because all levels of the page table
>    are basically identical, so you'll never notice there's a problem.

I assume on most architectures.


Let's see if we can stop printing that information completely, so we can avoid
messing with this at all.

-- 
Cheers,

David


^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2026-06-12 11:14 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-10  4:35 [RFC V2 0/3] lib/vsprintf: Add support for pgtable entries Anshuman Khandual
2026-06-10  4:35 ` [RFC V2 1/3] " Anshuman Khandual
2026-06-10 11:13   ` Usama Arif
2026-06-11  5:15     ` Anshuman Khandual
2026-06-11  7:17       ` Andy Shevchenko
2026-06-11  9:50         ` Anshuman Khandual
2026-06-11 18:59           ` Andy Shevchenko
2026-06-10  4:35 ` [RFC V2 2/3] kunit: printf: Add test " Anshuman Khandual
2026-06-10  4:35 ` [RFC V2 3/3] mm: Replace pgtable entry prints with new format Anshuman Khandual
2026-06-11 11:32   ` David Hildenbrand (Arm)
2026-06-12 11:08   ` David Hildenbrand (Arm)
2026-06-11 19:15 ` [RFC V2 0/3] lib/vsprintf: Add support for pgtable entries Matthew Wilcox
2026-06-11 19:33   ` Andy Shevchenko
2026-06-11 19:37     ` Matthew Wilcox
2026-06-12 11:14       ` David Hildenbrand (Arm)

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox