Commit 4c85c0be authored by Hyeonggon Yoo's avatar Hyeonggon Yoo Committed by Andrew Morton
Browse files

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: default avatarHyeonggon 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: default avatarAndrew Morton <akpm@linux-foundation.org>
parent e26fcc02
Loading
Loading
Loading
Loading
+11 −5
Original line number Diff line number Diff line
@@ -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()
+6 −1
Original line number Diff line number Diff line
@@ -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)					\
+8 −0
Original line number Diff line number Diff line
@@ -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)
+26 −0
Original line number Diff line number Diff line
@@ -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);
}

+21 −0
Original line number Diff line number Diff line
@@ -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;
Loading