* [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
* 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 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
* [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 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 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-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 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