Skip to content

Commit c244297

Browse files
laoarpmladek
authored andcommitted
vsprintf: dump full information of page flags in pGp
Currently the pGp only shows the names of page flags, rather than the full information including section, node, zone, last cpupid and kasan tag. While it is not easy to parse these information manually because there're so many flavors. Let's interpret them in pGp as well. To be compitable with the existed format of pGp, the new introduced ones also use '|' as the separator, then the user tools parsing pGp won't need to make change, suggested by Matthew. The new information is tracked onto the end of the existed one. On example of the output in mm/slub.c as follows, - Before the patch, [ 6343.396602] Slab 0x000000004382e02b objects=33 used=3 fp=0x000000009ae06ffc flags=0x17ffffc0010200(slab|head) - After the patch, [ 8448.272530] Slab 0x0000000090797883 objects=33 used=3 fp=0x00000000790f1c26 flags=0x17ffffc0010200(slab|head|node=0|zone=2|lastcpupid=0x1fffff) The documentation and test cases are also updated. The output of the test cases as follows, [68599.816764] test_printf: loaded. [68599.819068] test_printf: all 388 tests passed [68599.830367] test_printf: unloaded. [lkp@intel.com: reported issues in the prev version in test_printf.c] Signed-off-by: Yafang Shao <laoar.shao@gmail.com> Cc: David Hildenbrand <david@redhat.com> Cc: Joe Perches <joe@perches.com> Cc: Miaohe Lin <linmiaohe@huawei.com> Cc: Vlastimil Babka <vbabka@suse.cz> Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Cc: Matthew Wilcox <willy@infradead.org> Cc: Petr Mladek <pmladek@suse.com> Cc: kernel test robot <lkp@intel.com> Reviewed-by: Sergey Senozhatsky <senozhatsky@chromium.org> Reviewed-by: Petr Mladek <pmladek@suse.com> Signed-off-by: Petr Mladek <pmladek@suse.com> Link: https://lore.kernel.org/r/20210319101246.73513-4-laoar.shao@gmail.com
1 parent 96b94ab commit c244297

3 files changed

Lines changed: 142 additions & 16 deletions

File tree

Documentation/core-api/printk-formats.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ Flags bitfields such as page flags, gfp_flags
540540

541541
::
542542

543-
%pGp referenced|uptodate|lru|active|private
543+
%pGp referenced|uptodate|lru|active|private|node=0|zone=2|lastcpupid=0x1fffff
544544
%pGg GFP_USER|GFP_DMA32|GFP_NOWARN
545545
%pGv read|exec|mayread|maywrite|mayexec|denywrite
546546

lib/test_printf.c

Lines changed: 80 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -577,24 +577,98 @@ netdev_features(void)
577577
{
578578
}
579579

580+
struct page_flags_test {
581+
int width;
582+
int shift;
583+
int mask;
584+
unsigned long value;
585+
const char *fmt;
586+
const char *name;
587+
};
588+
589+
static struct page_flags_test pft[] = {
590+
{SECTIONS_WIDTH, SECTIONS_PGSHIFT, SECTIONS_MASK,
591+
0, "%d", "section"},
592+
{NODES_WIDTH, NODES_PGSHIFT, NODES_MASK,
593+
0, "%d", "node"},
594+
{ZONES_WIDTH, ZONES_PGSHIFT, ZONES_MASK,
595+
0, "%d", "zone"},
596+
{LAST_CPUPID_WIDTH, LAST_CPUPID_PGSHIFT, LAST_CPUPID_MASK,
597+
0, "%#x", "lastcpupid"},
598+
{KASAN_TAG_WIDTH, KASAN_TAG_PGSHIFT, KASAN_TAG_MASK,
599+
0, "%#x", "kasantag"},
600+
};
601+
602+
static void __init
603+
page_flags_test(int section, int node, int zone, int last_cpupid,
604+
int kasan_tag, int flags, const char *name, char *cmp_buf)
605+
{
606+
unsigned long values[] = {section, node, zone, last_cpupid, kasan_tag};
607+
unsigned long page_flags = 0;
608+
unsigned long size = 0;
609+
bool append = false;
610+
int i;
611+
612+
flags &= BIT(NR_PAGEFLAGS) - 1;
613+
if (flags) {
614+
page_flags |= flags;
615+
snprintf(cmp_buf + size, BUF_SIZE - size, "%s", name);
616+
size = strlen(cmp_buf);
617+
#if SECTIONS_WIDTH || NODES_WIDTH || ZONES_WIDTH || \
618+
LAST_CPUPID_WIDTH || KASAN_TAG_WIDTH
619+
/* Other information also included in page flags */
620+
snprintf(cmp_buf + size, BUF_SIZE - size, "|");
621+
size = strlen(cmp_buf);
622+
#endif
623+
}
624+
625+
/* Set the test value */
626+
for (i = 0; i < ARRAY_SIZE(pft); i++)
627+
pft[i].value = values[i];
628+
629+
for (i = 0; i < ARRAY_SIZE(pft); i++) {
630+
if (!pft[i].width)
631+
continue;
632+
633+
if (append) {
634+
snprintf(cmp_buf + size, BUF_SIZE - size, "|");
635+
size = strlen(cmp_buf);
636+
}
637+
638+
page_flags |= (pft[i].value & pft[i].mask) << pft[i].shift;
639+
snprintf(cmp_buf + size, BUF_SIZE - size, "%s=", pft[i].name);
640+
size = strlen(cmp_buf);
641+
snprintf(cmp_buf + size, BUF_SIZE - size, pft[i].fmt,
642+
pft[i].value & pft[i].mask);
643+
size = strlen(cmp_buf);
644+
append = true;
645+
}
646+
647+
test(cmp_buf, "%pGp", &page_flags);
648+
}
649+
580650
static void __init
581651
flags(void)
582652
{
583653
unsigned long flags;
584-
gfp_t gfp;
585654
char *cmp_buffer;
655+
gfp_t gfp;
656+
657+
cmp_buffer = kmalloc(BUF_SIZE, GFP_KERNEL);
658+
if (!cmp_buffer)
659+
return;
586660

587661
flags = 0;
588-
test("", "%pGp", &flags);
662+
page_flags_test(0, 0, 0, 0, 0, flags, "", cmp_buffer);
589663

590-
/* Page flags should filter the zone id */
591664
flags = 1UL << NR_PAGEFLAGS;
592-
test("", "%pGp", &flags);
665+
page_flags_test(0, 0, 0, 0, 0, flags, "", cmp_buffer);
593666

594667
flags |= 1UL << PG_uptodate | 1UL << PG_dirty | 1UL << PG_lru
595668
| 1UL << PG_active | 1UL << PG_swapbacked;
596-
test("uptodate|dirty|lru|active|swapbacked", "%pGp", &flags);
597-
669+
page_flags_test(1, 1, 1, 0x1fffff, 1, flags,
670+
"uptodate|dirty|lru|active|swapbacked",
671+
cmp_buffer);
598672

599673
flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC
600674
| VM_DENYWRITE;
@@ -609,10 +683,6 @@ flags(void)
609683
gfp = __GFP_ATOMIC;
610684
test("__GFP_ATOMIC", "%pGg", &gfp);
611685

612-
cmp_buffer = kmalloc(BUF_SIZE, GFP_KERNEL);
613-
if (!cmp_buffer)
614-
return;
615-
616686
/* Any flags not translated by the table should remain numeric */
617687
gfp = ~__GFP_BITS_MASK;
618688
snprintf(cmp_buffer, BUF_SIZE, "%#lx", (unsigned long) gfp);

lib/vsprintf.c

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1916,6 +1916,66 @@ char *format_flags(char *buf, char *end, unsigned long flags,
19161916
return buf;
19171917
}
19181918

1919+
struct page_flags_fields {
1920+
int width;
1921+
int shift;
1922+
int mask;
1923+
const struct printf_spec *spec;
1924+
const char *name;
1925+
};
1926+
1927+
static const struct page_flags_fields pff[] = {
1928+
{SECTIONS_WIDTH, SECTIONS_PGSHIFT, SECTIONS_MASK,
1929+
&default_dec_spec, "section"},
1930+
{NODES_WIDTH, NODES_PGSHIFT, NODES_MASK,
1931+
&default_dec_spec, "node"},
1932+
{ZONES_WIDTH, ZONES_PGSHIFT, ZONES_MASK,
1933+
&default_dec_spec, "zone"},
1934+
{LAST_CPUPID_WIDTH, LAST_CPUPID_PGSHIFT, LAST_CPUPID_MASK,
1935+
&default_flag_spec, "lastcpupid"},
1936+
{KASAN_TAG_WIDTH, KASAN_TAG_PGSHIFT, KASAN_TAG_MASK,
1937+
&default_flag_spec, "kasantag"},
1938+
};
1939+
1940+
static
1941+
char *format_page_flags(char *buf, char *end, unsigned long flags)
1942+
{
1943+
unsigned long main_flags = flags & (BIT(NR_PAGEFLAGS) - 1);
1944+
bool append = false;
1945+
int i;
1946+
1947+
/* Page flags from the main area. */
1948+
if (main_flags) {
1949+
buf = format_flags(buf, end, main_flags, pageflag_names);
1950+
append = true;
1951+
}
1952+
1953+
/* Page flags from the fields area */
1954+
for (i = 0; i < ARRAY_SIZE(pff); i++) {
1955+
/* Skip undefined fields. */
1956+
if (!pff[i].width)
1957+
continue;
1958+
1959+
/* Format: Flag Name + '=' (equals sign) + Number + '|' (separator) */
1960+
if (append) {
1961+
if (buf < end)
1962+
*buf = '|';
1963+
buf++;
1964+
}
1965+
1966+
buf = string(buf, end, pff[i].name, default_str_spec);
1967+
if (buf < end)
1968+
*buf = '=';
1969+
buf++;
1970+
buf = number(buf, end, (flags >> pff[i].shift) & pff[i].mask,
1971+
*pff[i].spec);
1972+
1973+
append = true;
1974+
}
1975+
1976+
return buf;
1977+
}
1978+
19191979
static noinline_for_stack
19201980
char *flags_string(char *buf, char *end, void *flags_ptr,
19211981
struct printf_spec spec, const char *fmt)
@@ -1928,11 +1988,7 @@ char *flags_string(char *buf, char *end, void *flags_ptr,
19281988

19291989
switch (fmt[1]) {
19301990
case 'p':
1931-
flags = *(unsigned long *)flags_ptr;
1932-
/* Remove zone id */
1933-
flags &= (1UL << NR_PAGEFLAGS) - 1;
1934-
names = pageflag_names;
1935-
break;
1991+
return format_page_flags(buf, end, *(unsigned long *)flags_ptr);
19361992
case 'v':
19371993
flags = *(unsigned long *)flags_ptr;
19381994
names = vmaflag_names;

0 commit comments

Comments
 (0)