mm, printk: introduce new format %pGt for page_type
%pGp format is used to display 'flags' field of a struct page. However, some page flags (i.e. PG_buddy, see page-flags.h for more details) are stored in page_type field. To display human-readable output of page_type, introduce %pGt format. It is important to note the meaning of bits are different in page_type. if page_type is 0xffffffff, no flags are set. Setting PG_buddy (0x00000080) flag results in a page_type of 0xffffff7f. Clearing a bit actually means setting a flag. Bits in page_type are inverted when displaying type names. Only values for which page_type_has_type() returns true are considered as page_type, to avoid confusion with mapcount values. if it returns false, only raw values are displayed and not page type names. Link: https://lkml.kernel.org/r/20230130042514.2418-3-42.hyeyoo@gmail.com Signed-off-by: Hyeonggon Yoo <42.hyeyoo@gmail.com> Reviewed-by: Petr Mladek <pmladek@suse.com> [vsprintf part] Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Cc: David Hildenbrand <david@redhat.com> Cc: Joe Perches <joe@perches.com> Cc: John Ogness <john.ogness@linutronix.de> Cc: Matthew Wilcox <willy@infradead.org> Cc: Sergey Senozhatsky <senozhatsky@chromium.org> Cc: Steven Rostedt (Google) <rostedt@goodmis.org> Cc: Vlastimil Babka <vbabka@suse.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
parent
e26fcc02c7
commit
4c85c0be3d
|
@ -575,20 +575,26 @@ The field width is passed by value, the bitmap is passed by reference.
|
|||
Helper macros cpumask_pr_args() and nodemask_pr_args() are available to ease
|
||||
printing cpumask and nodemask.
|
||||
|
||||
Flags bitfields such as page flags, gfp_flags
|
||||
---------------------------------------------
|
||||
Flags bitfields such as page flags, page_type, gfp_flags
|
||||
--------------------------------------------------------
|
||||
|
||||
::
|
||||
|
||||
%pGp 0x17ffffc0002036(referenced|uptodate|lru|active|private|node=0|zone=2|lastcpupid=0x1fffff)
|
||||
%pGt 0xffffff7f(buddy)
|
||||
%pGg GFP_USER|GFP_DMA32|GFP_NOWARN
|
||||
%pGv read|exec|mayread|maywrite|mayexec|denywrite
|
||||
|
||||
For printing flags bitfields as a collection of symbolic constants that
|
||||
would construct the value. The type of flags is given by the third
|
||||
character. Currently supported are [p]age flags, [v]ma_flags (both
|
||||
expect ``unsigned long *``) and [g]fp_flags (expects ``gfp_t *``). The flag
|
||||
names and print order depends on the particular type.
|
||||
character. Currently supported are:
|
||||
|
||||
- p - [p]age flags, expects value of type (``unsigned long *``)
|
||||
- t - page [t]ype, expects value of type (``unsigned int *``)
|
||||
- v - [v]ma_flags, expects value of type (``unsigned long *``)
|
||||
- g - [g]fp_flags, expects value of type (``gfp_t *``)
|
||||
|
||||
The flag names and print order depends on the particular type.
|
||||
|
||||
Note that this format should not be used directly in the
|
||||
:c:func:`TP_printk()` part of a tracepoint. Instead, use the show_*_flags()
|
||||
|
|
|
@ -926,9 +926,14 @@ static inline bool is_page_hwpoison(struct page *page)
|
|||
#define PageType(page, flag) \
|
||||
((page->page_type & (PAGE_TYPE_BASE | flag)) == PAGE_TYPE_BASE)
|
||||
|
||||
static inline int page_type_has_type(unsigned int page_type)
|
||||
{
|
||||
return (int)page_type < PAGE_MAPCOUNT_RESERVE;
|
||||
}
|
||||
|
||||
static inline int page_has_type(struct page *page)
|
||||
{
|
||||
return (int)page->page_type < PAGE_MAPCOUNT_RESERVE;
|
||||
return page_type_has_type(page->page_type);
|
||||
}
|
||||
|
||||
#define PAGE_TYPE_OPS(uname, lname) \
|
||||
|
|
|
@ -141,6 +141,14 @@ IF_HAVE_PG_SKIP_KASAN_POISON(skip_kasan_poison)
|
|||
__def_pageflag_names \
|
||||
) : "none"
|
||||
|
||||
#define DEF_PAGETYPE_NAME(_name) { PG_##_name, __stringify(_name) }
|
||||
|
||||
#define __def_pagetype_names \
|
||||
DEF_PAGETYPE_NAME(offline), \
|
||||
DEF_PAGETYPE_NAME(guard), \
|
||||
DEF_PAGETYPE_NAME(table), \
|
||||
DEF_PAGETYPE_NAME(buddy)
|
||||
|
||||
#if defined(CONFIG_X86)
|
||||
#define __VM_ARCH_SPECIFIC_1 {VM_PAT, "pat" }
|
||||
#elif defined(CONFIG_PPC)
|
||||
|
|
|
@ -642,12 +642,26 @@ page_flags_test(int section, int node, int zone, int last_cpupid,
|
|||
test(cmp_buf, "%pGp", &flags);
|
||||
}
|
||||
|
||||
static void __init page_type_test(unsigned int page_type, const char *name,
|
||||
char *cmp_buf)
|
||||
{
|
||||
unsigned long size;
|
||||
|
||||
size = scnprintf(cmp_buf, BUF_SIZE, "%#x(", page_type);
|
||||
if (page_type_has_type(page_type))
|
||||
size += scnprintf(cmp_buf + size, BUF_SIZE - size, "%s", name);
|
||||
|
||||
snprintf(cmp_buf + size, BUF_SIZE - size, ")");
|
||||
test(cmp_buf, "%pGt", &page_type);
|
||||
}
|
||||
|
||||
static void __init
|
||||
flags(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
char *cmp_buffer;
|
||||
gfp_t gfp;
|
||||
unsigned int page_type;
|
||||
|
||||
cmp_buffer = kmalloc(BUF_SIZE, GFP_KERNEL);
|
||||
if (!cmp_buffer)
|
||||
|
@ -687,6 +701,18 @@ flags(void)
|
|||
gfp |= __GFP_HIGH;
|
||||
test(cmp_buffer, "%pGg", &gfp);
|
||||
|
||||
page_type = ~0;
|
||||
page_type_test(page_type, "", cmp_buffer);
|
||||
|
||||
page_type = 10;
|
||||
page_type_test(page_type, "", cmp_buffer);
|
||||
|
||||
page_type = ~PG_buddy;
|
||||
page_type_test(page_type, "buddy", cmp_buffer);
|
||||
|
||||
page_type = ~(PG_table | PG_buddy);
|
||||
page_type_test(page_type, "table|buddy", cmp_buffer);
|
||||
|
||||
kfree(cmp_buffer);
|
||||
}
|
||||
|
||||
|
|
|
@ -2052,6 +2052,25 @@ char *format_page_flags(char *buf, char *end, unsigned long flags)
|
|||
return buf;
|
||||
}
|
||||
|
||||
static
|
||||
char *format_page_type(char *buf, char *end, unsigned int page_type)
|
||||
{
|
||||
buf = number(buf, end, page_type, default_flag_spec);
|
||||
|
||||
if (buf < end)
|
||||
*buf = '(';
|
||||
buf++;
|
||||
|
||||
if (page_type_has_type(page_type))
|
||||
buf = format_flags(buf, end, ~page_type, pagetype_names);
|
||||
|
||||
if (buf < end)
|
||||
*buf = ')';
|
||||
buf++;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static noinline_for_stack
|
||||
char *flags_string(char *buf, char *end, void *flags_ptr,
|
||||
struct printf_spec spec, const char *fmt)
|
||||
|
@ -2065,6 +2084,8 @@ char *flags_string(char *buf, char *end, void *flags_ptr,
|
|||
switch (fmt[1]) {
|
||||
case 'p':
|
||||
return format_page_flags(buf, end, *(unsigned long *)flags_ptr);
|
||||
case 't':
|
||||
return format_page_type(buf, end, *(unsigned int *)flags_ptr);
|
||||
case 'v':
|
||||
flags = *(unsigned long *)flags_ptr;
|
||||
names = vmaflag_names;
|
||||
|
|
|
@ -36,6 +36,11 @@ const struct trace_print_flags pageflag_names[] = {
|
|||
{0, NULL}
|
||||
};
|
||||
|
||||
const struct trace_print_flags pagetype_names[] = {
|
||||
__def_pagetype_names,
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
const struct trace_print_flags gfpflag_names[] = {
|
||||
__def_gfpflag_names,
|
||||
{0, NULL}
|
||||
|
|
|
@ -802,6 +802,7 @@ static inline void flush_tlb_batched_pending(struct mm_struct *mm)
|
|||
#endif /* CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH */
|
||||
|
||||
extern const struct trace_print_flags pageflag_names[];
|
||||
extern const struct trace_print_flags pagetype_names[];
|
||||
extern const struct trace_print_flags vmaflag_names[];
|
||||
extern const struct trace_print_flags gfpflag_names[];
|
||||
|
||||
|
|
Loading…
Reference in New Issue