* [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
2026-06-10 4:35 ` [RFC V2 3/3] mm: Replace pgtable entry prints with new format Anshuman Khandual
2 siblings, 1 reply; 9+ 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] 9+ 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; 9+ 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] 9+ 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; 9+ 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] 9+ 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; 9+ 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] 9+ 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
0 siblings, 0 replies; 9+ 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] 9+ 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
2 siblings, 0 replies; 9+ 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] 9+ 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)
2 siblings, 1 reply; 9+ 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] 9+ 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)
0 siblings, 0 replies; 9+ 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] 9+ messages in thread