All of lore.kernel.org
 help / color / mirror / Atom feed
From: Michal Hocko <mhocko@kernel.org>
To: Vlastimil Babka <vbabka@suse.cz>
Cc: Andrew Morton <akpm@linux-foundation.org>,
	linux-mm@kvack.org, linux-kernel@vger.kernel.org,
	Steven Rostedt <rostedt@goodmis.org>,
	Peter Zijlstra <peterz@infradead.org>,
	Arnaldo Carvalho de Melo <acme@kernel.org>,
	Ingo Molnar <mingo@redhat.com>,
	Rasmus Villemoes <linux@rasmusvillemoes.dk>,
	Joonsoo Kim <iamjoonsoo.kim@lge.com>,
	Minchan Kim <minchan@kernel.org>,
	Sasha Levin <sasha.levin@oracle.com>,
	"Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>,
	Mel Gorman <mgorman@suse.de>
Subject: Re: [PATCH v3 05/14] mm, printk: introduce new format string for flags
Date: Thu, 7 Jan 2016 10:53:24 +0100	[thread overview]
Message-ID: <20160107095324.GE27868@dhcp22.suse.cz> (raw)
In-Reply-To: <1450429406-7081-6-git-send-email-vbabka@suse.cz>

On Fri 18-12-15 10:03:17, Vlastimil Babka wrote:
> In mm we use several kinds of flags bitfields that are sometimes printed for
> debugging purposes, or exported to userspace via sysfs. To make them easier to
> interpret independently on kernel version and config, we want to dump also the
> symbolic flag names. So far this has been done with repeated calls to
> pr_cont(), which is unreliable on SMP, and not usable for e.g. sysfs export.
> 
> To get a more reliable and universal solution, this patch extends printk()
> format string for pointers to handle the page flags (%pgp), gfp_flags (%pgg)
> and vma flags (%pgv). Existing users of dump_flag_names() are converted and
> simplified.
> 
> It would be possible to pass flags by value instead of pointer, but the %p
> format string for pointers already has extensions for various kernel
> structures, so it's a good fit, and the extra indirection in a non-critical
> path is negligible.
> 
> [linux@rasmusvillemoes.dk: lots of good implementation suggestions]
> Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
> Cc: Steven Rostedt <rostedt@goodmis.org>
> Cc: Peter Zijlstra <peterz@infradead.org>
> Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
> Cc: Ingo Molnar <mingo@redhat.com>
> Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk>
> Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
> Cc: Minchan Kim <minchan@kernel.org>
> Cc: Sasha Levin <sasha.levin@oracle.com>
> Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
> Cc: Mel Gorman <mgorman@suse.de>
> Cc: Michal Hocko <mhocko@suse.cz>

With my limitted familiarity of the printk code this looks reasonable.
Acked-by: Michal Hocko <mhocko@suse.com>

> ---
>  Documentation/printk-formats.txt | 18 ++++++++++
>  include/linux/mmdebug.h          |  6 ++++
>  lib/test_printf.c                | 53 ++++++++++++++++++++++++++++
>  lib/vsprintf.c                   | 75 ++++++++++++++++++++++++++++++++++++++++
>  mm/debug.c                       | 34 ++++++++++--------
>  mm/internal.h                    |  6 ++++
>  6 files changed, 178 insertions(+), 14 deletions(-)
> 
> diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt
> index 602fee945d1d..e878e99ad686 100644
> --- a/Documentation/printk-formats.txt
> +++ b/Documentation/printk-formats.txt
> @@ -292,6 +292,24 @@ Raw pointer value SHOULD be printed with %p. The kernel supports
>  
>  	Passed by reference.
>  
> +Flags bitfields such as page flags, gfp_flags:
> +
> +	%pgp	referenced|uptodate|lru|active|private
> +	%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.
> +
> +	Note that this format should not be used directly in TP_printk() part
> +	of a tracepoint. Instead, use the show_*_flags() functions from
> +	<trace/events/mmflags.h>.
> +
> +	Passed by reference.
> +
>  Network device features:
>  
>  	%pNF	0x000000000000c000
> diff --git a/include/linux/mmdebug.h b/include/linux/mmdebug.h
> index c447d8055e50..2c8286cf162e 100644
> --- a/include/linux/mmdebug.h
> +++ b/include/linux/mmdebug.h
> @@ -2,11 +2,17 @@
>  #define LINUX_MM_DEBUG_H 1
>  
>  #include <linux/stringify.h>
> +#include <linux/types.h>
> +#include <linux/tracepoint.h>
>  
>  struct page;
>  struct vm_area_struct;
>  struct mm_struct;
>  
> +extern const struct trace_print_flags pageflag_names[];
> +extern const struct trace_print_flags vmaflag_names[];
> +extern const struct trace_print_flags gfpflag_names[];
> +
>  extern void dump_page(struct page *page, const char *reason);
>  extern void dump_page_badflags(struct page *page, const char *reason,
>  			       unsigned long badflags);
> diff --git a/lib/test_printf.c b/lib/test_printf.c
> index 4f6ae60433bc..5c7c8ebf3689 100644
> --- a/lib/test_printf.c
> +++ b/lib/test_printf.c
> @@ -17,6 +17,9 @@
>  #include <linux/socket.h>
>  #include <linux/in.h>
>  
> +#include <linux/gfp.h>
> +#include <linux/mm.h>
> +
>  #define BUF_SIZE 256
>  #define PAD_SIZE 16
>  #define FILL_CHAR '$'
> @@ -411,6 +414,55 @@ netdev_features(void)
>  }
>  
>  static void __init
> +flags(void)
> +{
> +	unsigned long flags;
> +	gfp_t gfp;
> +	char *cmp_buffer;
> +
> +	flags = 0;
> +	test("", "%pgp", &flags);
> +
> +	/* Page flags should filter the zone id */
> +	flags = 1UL << NR_PAGEFLAGS;
> +	test("", "%pgp", &flags);
> +
> +	flags |= 1UL << PG_uptodate | 1UL << PG_dirty | 1UL << PG_lru
> +		| 1UL << PG_active | 1UL << PG_swapbacked;
> +	test("uptodate|dirty|lru|active|swapbacked", "%pgp", &flags);
> +
> +
> +	flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC
> +			| VM_DENYWRITE;
> +	test("read|exec|mayread|maywrite|mayexec|denywrite", "%pgv", &flags);
> +
> +	gfp = GFP_TRANSHUGE;
> +	test("GFP_TRANSHUGE", "%pgg", &gfp);
> +
> +	gfp = GFP_ATOMIC|__GFP_DMA;
> +	test("GFP_ATOMIC|GFP_DMA", "%pgg", &gfp);
> +
> +	gfp = __GFP_ATOMIC;
> +	test("__GFP_ATOMIC", "%pgg", &gfp);
> +
> +	cmp_buffer = kmalloc(BUF_SIZE, GFP_KERNEL);
> +	if (!cmp_buffer)
> +		return;
> +
> +	/* Any flags not translated by the table should remain numeric */
> +	gfp = ~__GFP_BITS_MASK;
> +	snprintf(cmp_buffer, BUF_SIZE, "%#lx", (unsigned long) gfp);
> +	test(cmp_buffer, "%pgg", &gfp);
> +
> +	snprintf(cmp_buffer, BUF_SIZE, "__GFP_ATOMIC|%#lx",
> +							(unsigned long) gfp);
> +	gfp |= __GFP_ATOMIC;
> +	test(cmp_buffer, "%pgg", &gfp);
> +
> +	kfree(cmp_buffer);
> +}
> +
> +static void __init
>  test_pointer(void)
>  {
>  	plain();
> @@ -428,6 +480,7 @@ test_pointer(void)
>  	struct_clk();
>  	bitmap();
>  	netdev_features();
> +	flags();
>  }
>  
>  static int __init
> diff --git a/lib/vsprintf.c b/lib/vsprintf.c
> index cf064b17c50c..a254973d005d 100644
> --- a/lib/vsprintf.c
> +++ b/lib/vsprintf.c
> @@ -32,6 +32,8 @@
>  #include <linux/cred.h>
>  #include <net/addrconf.h>
>  
> +#include "../mm/internal.h"	/* For the trace_print_flags arrays */
> +
>  #include <asm/page.h>		/* for PAGE_SIZE */
>  #include <asm/sections.h>	/* for dereference_function_descriptor() */
>  #include <asm/byteorder.h>	/* cpu_to_le16 */
> @@ -1372,6 +1374,72 @@ char *clock(char *buf, char *end, struct clk *clk, struct printf_spec spec,
>  	}
>  }
>  
> +static
> +char *format_flags(char *buf, char *end, unsigned long flags,
> +					const struct trace_print_flags *names)
> +{
> +	unsigned long mask;
> +	const struct printf_spec strspec = {
> +		.field_width = -1,
> +		.precision = -1,
> +	};
> +	const struct printf_spec numspec = {
> +		.flags = SPECIAL|SMALL,
> +		.field_width = -1,
> +		.precision = -1,
> +		.base = 16,
> +	};
> +
> +	for ( ; flags && names->name; names++) {
> +		mask = names->mask;
> +		if ((flags & mask) != mask)
> +			continue;
> +
> +		buf = string(buf, end, names->name, strspec);
> +
> +		flags &= ~mask;
> +		if (flags) {
> +			if (buf < end)
> +				*buf = '|';
> +			buf++;
> +		}
> +	}
> +
> +	if (flags)
> +		buf = number(buf, end, flags, numspec);
> +
> +	return buf;
> +}
> +
> +static noinline_for_stack
> +char *flags_string(char *buf, char *end, void *flags_ptr, const char *fmt)
> +{
> +	unsigned long flags;
> +	const struct trace_print_flags *names;
> +
> +	switch (fmt[1]) {
> +	case 'p':
> +		flags = *(unsigned long *)flags_ptr;
> +		/* Remove zone id */
> +		flags &= (1UL << NR_PAGEFLAGS) - 1;
> +		names = pageflag_names;
> +		break;
> +	case 'v':
> +		flags = *(unsigned long *)flags_ptr;
> +		names = vmaflag_names;
> +		break;
> +	case 'g':
> +		flags = *(gfp_t *)flags_ptr;
> +		names = gfpflag_names;
> +		break;
> +	default:
> +		WARN_ONCE(1, "Unsupported flags modifier: %c\n", fmt[1]);
> +		return buf;
> +	}
> +
> +	return format_flags(buf, end, flags, names);
> +}
> +
>  int kptr_restrict __read_mostly;
>  
>  /*
> @@ -1459,6 +1527,11 @@ int kptr_restrict __read_mostly;
>   * - 'Cn' For a clock, it prints the name (Common Clock Framework) or address
>   *        (legacy clock framework) of the clock
>   * - 'Cr' For a clock, it prints the current rate of the clock
> + * - 'g' For flags to be printed as a collection of symbolic strings that would
> + *       construct the specific value. Supported flags given by option:
> + *       p page flags (see struct page) given as pointer to unsigned long
> + *       g gfp flags (GFP_* and __GFP_*) given as pointer to gfp_t
> + *       v vma flags (VM_*) given as pointer to unsigned long
>   *
>   * ** Please update also Documentation/printk-formats.txt when making changes **
>   *
> @@ -1611,6 +1684,8 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
>  		return dentry_name(buf, end,
>  				   ((const struct file *)ptr)->f_path.dentry,
>  				   spec, fmt);
> +	case 'g':
> +		return flags_string(buf, end, ptr, fmt);
>  	}
>  	spec.flags |= SMALL;
>  	if (spec.field_width == -1) {
> diff --git a/mm/debug.c b/mm/debug.c
> index 85f71e4ce59f..79621a5ce46f 100644
> --- a/mm/debug.c
> +++ b/mm/debug.c
> @@ -11,12 +11,21 @@
>  #include <linux/memcontrol.h>
>  #include <trace/events/mmflags.h>
>  
> -static const struct trace_print_flags pageflag_names[] = {
> -	__def_pageflag_names
> +#include "internal.h"
> +
> +const struct trace_print_flags pageflag_names[] = {
> +	__def_pageflag_names,
> +	{0, NULL}
> +};
> +
> +const struct trace_print_flags gfpflag_names[] = {
> +	__def_gfpflag_names,
> +	{0, NULL}
>  };
>  
> -static const struct trace_print_flags gfpflag_names[] = {
> -	__def_gfpflag_names
> +const struct trace_print_flags vmaflag_names[] = {
> +	__def_vmaflag_names,
> +	{0, NULL}
>  };
>  
>  static void dump_flags(unsigned long flags,
> @@ -58,14 +67,15 @@ void dump_page_badflags(struct page *page, const char *reason,
>  	if (PageCompound(page))
>  		pr_cont(" compound_mapcount: %d", compound_mapcount(page));
>  	pr_cont("\n");
> -	BUILD_BUG_ON(ARRAY_SIZE(pageflag_names) != __NR_PAGEFLAGS);
> -	dump_flags(page->flags, pageflag_names, ARRAY_SIZE(pageflag_names));
> +	BUILD_BUG_ON(ARRAY_SIZE(pageflag_names) != __NR_PAGEFLAGS + 1);
> +	dump_flags(page->flags, pageflag_names,
> +					ARRAY_SIZE(pageflag_names) - 1);
>  	if (reason)
>  		pr_alert("page dumped because: %s\n", reason);
>  	if (page->flags & badflags) {
>  		pr_alert("bad because of flags:\n");
> -		dump_flags(page->flags & badflags,
> -				pageflag_names, ARRAY_SIZE(pageflag_names));
> +		dump_flags(page->flags & badflags, pageflag_names,
> +					ARRAY_SIZE(pageflag_names) - 1);
>  	}
>  #ifdef CONFIG_MEMCG
>  	if (page->mem_cgroup)
> @@ -81,10 +91,6 @@ EXPORT_SYMBOL(dump_page);
>  
>  #ifdef CONFIG_DEBUG_VM
>  
> -static const struct trace_print_flags vmaflag_names[] = {
> -	__def_vmaflag_names
> -};
> -
>  void dump_vma(const struct vm_area_struct *vma)
>  {
>  	pr_emerg("vma %p start %p end %p\n"
> @@ -96,7 +102,7 @@ void dump_vma(const struct vm_area_struct *vma)
>  		(unsigned long)pgprot_val(vma->vm_page_prot),
>  		vma->anon_vma, vma->vm_ops, vma->vm_pgoff,
>  		vma->vm_file, vma->vm_private_data);
> -	dump_flags(vma->vm_flags, vmaflag_names, ARRAY_SIZE(vmaflag_names));
> +	dump_flags(vma->vm_flags, vmaflag_names, ARRAY_SIZE(vmaflag_names) - 1);
>  }
>  EXPORT_SYMBOL(dump_vma);
>  
> @@ -168,7 +174,7 @@ void dump_mm(const struct mm_struct *mm)
>  		);
>  
>  		dump_flags(mm->def_flags, vmaflag_names,
> -				ARRAY_SIZE(vmaflag_names));
> +				ARRAY_SIZE(vmaflag_names) - 1);
>  }
>  
>  #endif		/* CONFIG_DEBUG_VM */
> diff --git a/mm/internal.h b/mm/internal.h
> index d01a41c00bec..8d2f8e3fd7d8 100644
> --- a/mm/internal.h
> +++ b/mm/internal.h
> @@ -14,6 +14,7 @@
>  #include <linux/fs.h>
>  #include <linux/mm.h>
>  #include <linux/pagemap.h>
> +#include <linux/tracepoint-defs.h>
>  
>  /*
>   * The set of flags that only affect watermark checking and reclaim
> @@ -441,4 +442,9 @@ static inline void try_to_unmap_flush_dirty(void)
>  }
>  
>  #endif /* CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH */
> +
> +extern const struct trace_print_flags pageflag_names[];
> +extern const struct trace_print_flags vmaflag_names[];
> +extern const struct trace_print_flags gfpflag_names[];
> +
>  #endif	/* __MM_INTERNAL_H */
> -- 
> 2.6.3

-- 
Michal Hocko
SUSE Labs

WARNING: multiple messages have this Message-ID (diff)
From: Michal Hocko <mhocko@kernel.org>
To: Vlastimil Babka <vbabka@suse.cz>
Cc: Andrew Morton <akpm@linux-foundation.org>,
	linux-mm@kvack.org, linux-kernel@vger.kernel.org,
	Steven Rostedt <rostedt@goodmis.org>,
	Peter Zijlstra <peterz@infradead.org>,
	Arnaldo Carvalho de Melo <acme@kernel.org>,
	Ingo Molnar <mingo@redhat.com>,
	Rasmus Villemoes <linux@rasmusvillemoes.dk>,
	Joonsoo Kim <iamjoonsoo.kim@lge.com>,
	Minchan Kim <minchan@kernel.org>,
	Sasha Levin <sasha.levin@oracle.com>,
	"Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>,
	Mel Gorman <mgorman@suse.de>
Subject: Re: [PATCH v3 05/14] mm, printk: introduce new format string for flags
Date: Thu, 7 Jan 2016 10:53:24 +0100	[thread overview]
Message-ID: <20160107095324.GE27868@dhcp22.suse.cz> (raw)
In-Reply-To: <1450429406-7081-6-git-send-email-vbabka@suse.cz>

On Fri 18-12-15 10:03:17, Vlastimil Babka wrote:
> In mm we use several kinds of flags bitfields that are sometimes printed for
> debugging purposes, or exported to userspace via sysfs. To make them easier to
> interpret independently on kernel version and config, we want to dump also the
> symbolic flag names. So far this has been done with repeated calls to
> pr_cont(), which is unreliable on SMP, and not usable for e.g. sysfs export.
> 
> To get a more reliable and universal solution, this patch extends printk()
> format string for pointers to handle the page flags (%pgp), gfp_flags (%pgg)
> and vma flags (%pgv). Existing users of dump_flag_names() are converted and
> simplified.
> 
> It would be possible to pass flags by value instead of pointer, but the %p
> format string for pointers already has extensions for various kernel
> structures, so it's a good fit, and the extra indirection in a non-critical
> path is negligible.
> 
> [linux@rasmusvillemoes.dk: lots of good implementation suggestions]
> Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
> Cc: Steven Rostedt <rostedt@goodmis.org>
> Cc: Peter Zijlstra <peterz@infradead.org>
> Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
> Cc: Ingo Molnar <mingo@redhat.com>
> Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk>
> Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
> Cc: Minchan Kim <minchan@kernel.org>
> Cc: Sasha Levin <sasha.levin@oracle.com>
> Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
> Cc: Mel Gorman <mgorman@suse.de>
> Cc: Michal Hocko <mhocko@suse.cz>

With my limitted familiarity of the printk code this looks reasonable.
Acked-by: Michal Hocko <mhocko@suse.com>

> ---
>  Documentation/printk-formats.txt | 18 ++++++++++
>  include/linux/mmdebug.h          |  6 ++++
>  lib/test_printf.c                | 53 ++++++++++++++++++++++++++++
>  lib/vsprintf.c                   | 75 ++++++++++++++++++++++++++++++++++++++++
>  mm/debug.c                       | 34 ++++++++++--------
>  mm/internal.h                    |  6 ++++
>  6 files changed, 178 insertions(+), 14 deletions(-)
> 
> diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt
> index 602fee945d1d..e878e99ad686 100644
> --- a/Documentation/printk-formats.txt
> +++ b/Documentation/printk-formats.txt
> @@ -292,6 +292,24 @@ Raw pointer value SHOULD be printed with %p. The kernel supports
>  
>  	Passed by reference.
>  
> +Flags bitfields such as page flags, gfp_flags:
> +
> +	%pgp	referenced|uptodate|lru|active|private
> +	%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.
> +
> +	Note that this format should not be used directly in TP_printk() part
> +	of a tracepoint. Instead, use the show_*_flags() functions from
> +	<trace/events/mmflags.h>.
> +
> +	Passed by reference.
> +
>  Network device features:
>  
>  	%pNF	0x000000000000c000
> diff --git a/include/linux/mmdebug.h b/include/linux/mmdebug.h
> index c447d8055e50..2c8286cf162e 100644
> --- a/include/linux/mmdebug.h
> +++ b/include/linux/mmdebug.h
> @@ -2,11 +2,17 @@
>  #define LINUX_MM_DEBUG_H 1
>  
>  #include <linux/stringify.h>
> +#include <linux/types.h>
> +#include <linux/tracepoint.h>
>  
>  struct page;
>  struct vm_area_struct;
>  struct mm_struct;
>  
> +extern const struct trace_print_flags pageflag_names[];
> +extern const struct trace_print_flags vmaflag_names[];
> +extern const struct trace_print_flags gfpflag_names[];
> +
>  extern void dump_page(struct page *page, const char *reason);
>  extern void dump_page_badflags(struct page *page, const char *reason,
>  			       unsigned long badflags);
> diff --git a/lib/test_printf.c b/lib/test_printf.c
> index 4f6ae60433bc..5c7c8ebf3689 100644
> --- a/lib/test_printf.c
> +++ b/lib/test_printf.c
> @@ -17,6 +17,9 @@
>  #include <linux/socket.h>
>  #include <linux/in.h>
>  
> +#include <linux/gfp.h>
> +#include <linux/mm.h>
> +
>  #define BUF_SIZE 256
>  #define PAD_SIZE 16
>  #define FILL_CHAR '$'
> @@ -411,6 +414,55 @@ netdev_features(void)
>  }
>  
>  static void __init
> +flags(void)
> +{
> +	unsigned long flags;
> +	gfp_t gfp;
> +	char *cmp_buffer;
> +
> +	flags = 0;
> +	test("", "%pgp", &flags);
> +
> +	/* Page flags should filter the zone id */
> +	flags = 1UL << NR_PAGEFLAGS;
> +	test("", "%pgp", &flags);
> +
> +	flags |= 1UL << PG_uptodate | 1UL << PG_dirty | 1UL << PG_lru
> +		| 1UL << PG_active | 1UL << PG_swapbacked;
> +	test("uptodate|dirty|lru|active|swapbacked", "%pgp", &flags);
> +
> +
> +	flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC
> +			| VM_DENYWRITE;
> +	test("read|exec|mayread|maywrite|mayexec|denywrite", "%pgv", &flags);
> +
> +	gfp = GFP_TRANSHUGE;
> +	test("GFP_TRANSHUGE", "%pgg", &gfp);
> +
> +	gfp = GFP_ATOMIC|__GFP_DMA;
> +	test("GFP_ATOMIC|GFP_DMA", "%pgg", &gfp);
> +
> +	gfp = __GFP_ATOMIC;
> +	test("__GFP_ATOMIC", "%pgg", &gfp);
> +
> +	cmp_buffer = kmalloc(BUF_SIZE, GFP_KERNEL);
> +	if (!cmp_buffer)
> +		return;
> +
> +	/* Any flags not translated by the table should remain numeric */
> +	gfp = ~__GFP_BITS_MASK;
> +	snprintf(cmp_buffer, BUF_SIZE, "%#lx", (unsigned long) gfp);
> +	test(cmp_buffer, "%pgg", &gfp);
> +
> +	snprintf(cmp_buffer, BUF_SIZE, "__GFP_ATOMIC|%#lx",
> +							(unsigned long) gfp);
> +	gfp |= __GFP_ATOMIC;
> +	test(cmp_buffer, "%pgg", &gfp);
> +
> +	kfree(cmp_buffer);
> +}
> +
> +static void __init
>  test_pointer(void)
>  {
>  	plain();
> @@ -428,6 +480,7 @@ test_pointer(void)
>  	struct_clk();
>  	bitmap();
>  	netdev_features();
> +	flags();
>  }
>  
>  static int __init
> diff --git a/lib/vsprintf.c b/lib/vsprintf.c
> index cf064b17c50c..a254973d005d 100644
> --- a/lib/vsprintf.c
> +++ b/lib/vsprintf.c
> @@ -32,6 +32,8 @@
>  #include <linux/cred.h>
>  #include <net/addrconf.h>
>  
> +#include "../mm/internal.h"	/* For the trace_print_flags arrays */
> +
>  #include <asm/page.h>		/* for PAGE_SIZE */
>  #include <asm/sections.h>	/* for dereference_function_descriptor() */
>  #include <asm/byteorder.h>	/* cpu_to_le16 */
> @@ -1372,6 +1374,72 @@ char *clock(char *buf, char *end, struct clk *clk, struct printf_spec spec,
>  	}
>  }
>  
> +static
> +char *format_flags(char *buf, char *end, unsigned long flags,
> +					const struct trace_print_flags *names)
> +{
> +	unsigned long mask;
> +	const struct printf_spec strspec = {
> +		.field_width = -1,
> +		.precision = -1,
> +	};
> +	const struct printf_spec numspec = {
> +		.flags = SPECIAL|SMALL,
> +		.field_width = -1,
> +		.precision = -1,
> +		.base = 16,
> +	};
> +
> +	for ( ; flags && names->name; names++) {
> +		mask = names->mask;
> +		if ((flags & mask) != mask)
> +			continue;
> +
> +		buf = string(buf, end, names->name, strspec);
> +
> +		flags &= ~mask;
> +		if (flags) {
> +			if (buf < end)
> +				*buf = '|';
> +			buf++;
> +		}
> +	}
> +
> +	if (flags)
> +		buf = number(buf, end, flags, numspec);
> +
> +	return buf;
> +}
> +
> +static noinline_for_stack
> +char *flags_string(char *buf, char *end, void *flags_ptr, const char *fmt)
> +{
> +	unsigned long flags;
> +	const struct trace_print_flags *names;
> +
> +	switch (fmt[1]) {
> +	case 'p':
> +		flags = *(unsigned long *)flags_ptr;
> +		/* Remove zone id */
> +		flags &= (1UL << NR_PAGEFLAGS) - 1;
> +		names = pageflag_names;
> +		break;
> +	case 'v':
> +		flags = *(unsigned long *)flags_ptr;
> +		names = vmaflag_names;
> +		break;
> +	case 'g':
> +		flags = *(gfp_t *)flags_ptr;
> +		names = gfpflag_names;
> +		break;
> +	default:
> +		WARN_ONCE(1, "Unsupported flags modifier: %c\n", fmt[1]);
> +		return buf;
> +	}
> +
> +	return format_flags(buf, end, flags, names);
> +}
> +
>  int kptr_restrict __read_mostly;
>  
>  /*
> @@ -1459,6 +1527,11 @@ int kptr_restrict __read_mostly;
>   * - 'Cn' For a clock, it prints the name (Common Clock Framework) or address
>   *        (legacy clock framework) of the clock
>   * - 'Cr' For a clock, it prints the current rate of the clock
> + * - 'g' For flags to be printed as a collection of symbolic strings that would
> + *       construct the specific value. Supported flags given by option:
> + *       p page flags (see struct page) given as pointer to unsigned long
> + *       g gfp flags (GFP_* and __GFP_*) given as pointer to gfp_t
> + *       v vma flags (VM_*) given as pointer to unsigned long
>   *
>   * ** Please update also Documentation/printk-formats.txt when making changes **
>   *
> @@ -1611,6 +1684,8 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
>  		return dentry_name(buf, end,
>  				   ((const struct file *)ptr)->f_path.dentry,
>  				   spec, fmt);
> +	case 'g':
> +		return flags_string(buf, end, ptr, fmt);
>  	}
>  	spec.flags |= SMALL;
>  	if (spec.field_width == -1) {
> diff --git a/mm/debug.c b/mm/debug.c
> index 85f71e4ce59f..79621a5ce46f 100644
> --- a/mm/debug.c
> +++ b/mm/debug.c
> @@ -11,12 +11,21 @@
>  #include <linux/memcontrol.h>
>  #include <trace/events/mmflags.h>
>  
> -static const struct trace_print_flags pageflag_names[] = {
> -	__def_pageflag_names
> +#include "internal.h"
> +
> +const struct trace_print_flags pageflag_names[] = {
> +	__def_pageflag_names,
> +	{0, NULL}
> +};
> +
> +const struct trace_print_flags gfpflag_names[] = {
> +	__def_gfpflag_names,
> +	{0, NULL}
>  };
>  
> -static const struct trace_print_flags gfpflag_names[] = {
> -	__def_gfpflag_names
> +const struct trace_print_flags vmaflag_names[] = {
> +	__def_vmaflag_names,
> +	{0, NULL}
>  };
>  
>  static void dump_flags(unsigned long flags,
> @@ -58,14 +67,15 @@ void dump_page_badflags(struct page *page, const char *reason,
>  	if (PageCompound(page))
>  		pr_cont(" compound_mapcount: %d", compound_mapcount(page));
>  	pr_cont("\n");
> -	BUILD_BUG_ON(ARRAY_SIZE(pageflag_names) != __NR_PAGEFLAGS);
> -	dump_flags(page->flags, pageflag_names, ARRAY_SIZE(pageflag_names));
> +	BUILD_BUG_ON(ARRAY_SIZE(pageflag_names) != __NR_PAGEFLAGS + 1);
> +	dump_flags(page->flags, pageflag_names,
> +					ARRAY_SIZE(pageflag_names) - 1);
>  	if (reason)
>  		pr_alert("page dumped because: %s\n", reason);
>  	if (page->flags & badflags) {
>  		pr_alert("bad because of flags:\n");
> -		dump_flags(page->flags & badflags,
> -				pageflag_names, ARRAY_SIZE(pageflag_names));
> +		dump_flags(page->flags & badflags, pageflag_names,
> +					ARRAY_SIZE(pageflag_names) - 1);
>  	}
>  #ifdef CONFIG_MEMCG
>  	if (page->mem_cgroup)
> @@ -81,10 +91,6 @@ EXPORT_SYMBOL(dump_page);
>  
>  #ifdef CONFIG_DEBUG_VM
>  
> -static const struct trace_print_flags vmaflag_names[] = {
> -	__def_vmaflag_names
> -};
> -
>  void dump_vma(const struct vm_area_struct *vma)
>  {
>  	pr_emerg("vma %p start %p end %p\n"
> @@ -96,7 +102,7 @@ void dump_vma(const struct vm_area_struct *vma)
>  		(unsigned long)pgprot_val(vma->vm_page_prot),
>  		vma->anon_vma, vma->vm_ops, vma->vm_pgoff,
>  		vma->vm_file, vma->vm_private_data);
> -	dump_flags(vma->vm_flags, vmaflag_names, ARRAY_SIZE(vmaflag_names));
> +	dump_flags(vma->vm_flags, vmaflag_names, ARRAY_SIZE(vmaflag_names) - 1);
>  }
>  EXPORT_SYMBOL(dump_vma);
>  
> @@ -168,7 +174,7 @@ void dump_mm(const struct mm_struct *mm)
>  		);
>  
>  		dump_flags(mm->def_flags, vmaflag_names,
> -				ARRAY_SIZE(vmaflag_names));
> +				ARRAY_SIZE(vmaflag_names) - 1);
>  }
>  
>  #endif		/* CONFIG_DEBUG_VM */
> diff --git a/mm/internal.h b/mm/internal.h
> index d01a41c00bec..8d2f8e3fd7d8 100644
> --- a/mm/internal.h
> +++ b/mm/internal.h
> @@ -14,6 +14,7 @@
>  #include <linux/fs.h>
>  #include <linux/mm.h>
>  #include <linux/pagemap.h>
> +#include <linux/tracepoint-defs.h>
>  
>  /*
>   * The set of flags that only affect watermark checking and reclaim
> @@ -441,4 +442,9 @@ static inline void try_to_unmap_flush_dirty(void)
>  }
>  
>  #endif /* CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH */
> +
> +extern const struct trace_print_flags pageflag_names[];
> +extern const struct trace_print_flags vmaflag_names[];
> +extern const struct trace_print_flags gfpflag_names[];
> +
>  #endif	/* __MM_INTERNAL_H */
> -- 
> 2.6.3

-- 
Michal Hocko
SUSE Labs

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

  reply	other threads:[~2016-01-07  9:53 UTC|newest]

Thread overview: 50+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-12-18  9:03 [PATCH v3 00/14] mm flags in printk, page_owner improvements for debugging Vlastimil Babka
2015-12-18  9:03 ` Vlastimil Babka
2015-12-18  9:03 ` [PATCH v3 01/14] tracepoints: move trace_print_flags definitions to tracepoint-defs.h Vlastimil Babka
2015-12-18  9:03   ` Vlastimil Babka
2015-12-18  9:03 ` [PATCH v3 02/14] mm, tracing: make show_gfp_flags() up to date Vlastimil Babka
2015-12-18  9:03   ` Vlastimil Babka
2016-01-07  9:29   ` Michal Hocko
2016-01-07  9:29     ` Michal Hocko
2015-12-18  9:03 ` [PATCH v3 03/14] tools, perf: make gfp_compact_table " Vlastimil Babka
2015-12-18  9:03   ` Vlastimil Babka
2015-12-18  9:03 ` [PATCH v3 04/14] mm, tracing: unify mm flags handling in tracepoints and printk Vlastimil Babka
2015-12-18  9:03   ` Vlastimil Babka
2016-01-07  9:46   ` Michal Hocko
2016-01-07  9:46     ` Michal Hocko
2015-12-18  9:03 ` [PATCH v3 05/14] mm, printk: introduce new format string for flags Vlastimil Babka
2015-12-18  9:03   ` Vlastimil Babka
2016-01-07  9:53   ` Michal Hocko [this message]
2016-01-07  9:53     ` Michal Hocko
2015-12-18  9:03 ` [PATCH v3 06/14] mm, debug: replace dump_flags() with the new printk formats Vlastimil Babka
2015-12-18  9:03   ` Vlastimil Babka
2016-01-07  9:57   ` Michal Hocko
2016-01-07  9:57     ` Michal Hocko
2015-12-18  9:03 ` [PATCH v3 07/14] mm, page_alloc: print symbolic gfp_flags on allocation failure Vlastimil Babka
2015-12-18  9:03   ` Vlastimil Babka
2015-12-18  9:03 ` [PATCH v3 08/14] mm, oom: print symbolic gfp_flags in oom warning Vlastimil Babka
2015-12-18  9:03   ` Vlastimil Babka
2015-12-18  9:03 ` [PATCH v3 09/14] mm, page_owner: print migratetype of page and pageblock, symbolic flags Vlastimil Babka
2015-12-18  9:03   ` Vlastimil Babka
2016-01-07 10:06   ` Michal Hocko
2016-01-07 10:06     ` Michal Hocko
2015-12-18  9:03 ` [PATCH v3 10/14] mm, page_owner: convert page_owner_inited to static key Vlastimil Babka
2015-12-18  9:03   ` Vlastimil Babka
2016-01-07 10:21   ` Michal Hocko
2016-01-07 10:21     ` Michal Hocko
2015-12-18  9:03 ` [PATCH v3 11/14] mm, page_owner: copy page owner info during migration Vlastimil Babka
2015-12-18  9:03   ` Vlastimil Babka
2016-01-07 10:44   ` Michal Hocko
2016-01-07 10:44     ` Michal Hocko
2015-12-18  9:03 ` [PATCH v3 12/14] mm, page_owner: track and print last migrate reason Vlastimil Babka
2015-12-18  9:03   ` Vlastimil Babka
2016-01-07 10:54   ` Michal Hocko
2016-01-07 10:54     ` Michal Hocko
2016-01-07 13:17     ` Vlastimil Babka
2016-01-07 13:17       ` Vlastimil Babka
2015-12-18  9:03 ` [PATCH v3 13/14] mm, page_owner: dump page owner info from dump_page() Vlastimil Babka
2015-12-18  9:03   ` Vlastimil Babka
2015-12-18  9:03 ` [PATCH v3 14/14] mm, debug: move bad flags printing to bad_page() Vlastimil Babka
2015-12-18  9:03   ` Vlastimil Babka
2016-01-07 13:10   ` Michal Hocko
2016-01-07 13:10     ` Michal Hocko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20160107095324.GE27868@dhcp22.suse.cz \
    --to=mhocko@kernel.org \
    --cc=acme@kernel.org \
    --cc=akpm@linux-foundation.org \
    --cc=iamjoonsoo.kim@lge.com \
    --cc=kirill.shutemov@linux.intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=linux@rasmusvillemoes.dk \
    --cc=mgorman@suse.de \
    --cc=minchan@kernel.org \
    --cc=mingo@redhat.com \
    --cc=peterz@infradead.org \
    --cc=rostedt@goodmis.org \
    --cc=sasha.levin@oracle.com \
    --cc=vbabka@suse.cz \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.