linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 00/14] mm flags in printk, page_owner improvements for debugging
@ 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
                   ` (13 more replies)
  0 siblings, 14 replies; 25+ messages in thread
From: Vlastimil Babka @ 2015-12-18  9:03 UTC (permalink / raw)
  To: Andrew Morton
  Cc: linux-mm, linux-kernel, Vlastimil Babka,
	Arnaldo Carvalho de Melo, Hugh Dickins, Ingo Molnar, Joonsoo Kim,
	Kirill A. Shutemov, Mel Gorman, Michal Hocko, Michal Hocko,
	Minchan Kim, Peter Zijlstra, Rasmus Villemoes, Sasha Levin,
	Steven Rostedt

After v2 [1] of the page_owner series, I've moved mm-specific flags printing
into printk() and posted it on top of the series. But it makes more sense and
results in less code churn to do the printk() changes first. So this series
is two-part. Patches 1-6 are related to the flags handling in printk() and
tracepoints, and Cc the printk, ftrace and perf maintainers. The rest is
the original page_owner series, CCing only mm people.

The patches are intended to fully replace the v2 in -mm tree, so they can't
simply apply to -next. Furthermore, the first patch needs "tracepoints: Move
struct tracepoint to new tracepoint-defs.h header" from tip. I'm not sure how
the maintainer merging should work here, suggestions welcome.

To apply for testing/review, prepare a tree like this:
git checkout next-20151217
git revert --no-edit 75d89138243d1062acbd20fe2c13fed4889f4438..fcf95d5cb1cbb5c3ae18ae88f8073a8e0e2e57bf

Adapted description of v2:

For page_owner, the main changes are
o Use static key to further reduce overhead when compiled in but not enabled.
o Improve output wrt. page and pageblock migratetypes
o Transfer the info on page migrations and track last migration reason.
o Dump the info as part of dump_page() to hopefully help debugging.

For the last point, Kirill requested a human readable printing of gfp_mask and
migratetype after v1. At that point it probably makes a lot of sense to do the
same for page alloc failure and OOM warnings. The flags have been undergoing
revisions recently, and we might be getting reports from various kernel
versions that differ. The ./scripts/gfp-translate tool needs to be pointed at
the corresponding sources to be accurate.  The downside is potentially breaking
scripts that grep these warnings, but it's not a first change done there over
the years.

Other changes since v1:
o Change placement of page owner migration calls to cover missing cases (Hugh)
o Move dump_page_owner() call up from dump_page_badflags(), so the latter can
  be used for adding debugging prints without page owner info (Kirill)

[1] https://lkml.org/lkml/2015/11/24/342

Vlastimil Babka (14):
  tracepoints: move trace_print_flags definitions to tracepoint-defs.h
  mm, tracing: make show_gfp_flags() up to date
  tools, perf: make gfp_compact_table up to date
  mm, tracing: unify mm flags handling in tracepoints and printk
  mm, printk: introduce new format string for flags
  mm, debug: replace dump_flags() with the new printk formats
  mm, page_alloc: print symbolic gfp_flags on allocation failure
  mm, oom: print symbolic gfp_flags in oom warning
  mm, page_owner: print migratetype of page and pageblock, symbolic
    flags
  mm, page_owner: convert page_owner_inited to static key
  mm, page_owner: copy page owner info during migration
  mm, page_owner: track and print last migrate reason
  mm, page_owner: dump page owner info from dump_page()
  mm, debug: move bad flags printing to bad_page()

 Documentation/printk-formats.txt   |  18 ++++
 Documentation/vm/page_owner.txt    |   9 +-
 include/linux/gfp.h                |   5 ++
 include/linux/migrate.h            |   6 +-
 include/linux/mmdebug.h            |   9 +-
 include/linux/mmzone.h             |   3 +
 include/linux/page_ext.h           |   1 +
 include/linux/page_owner.h         |  50 ++++++++---
 include/linux/trace_events.h       |  10 ---
 include/linux/tracepoint-defs.h    |  14 +++-
 include/trace/events/btrfs.h       |   2 +-
 include/trace/events/compaction.h  |   2 +-
 include/trace/events/gfpflags.h    |  43 ----------
 include/trace/events/huge_memory.h |   2 -
 include/trace/events/kmem.h        |   2 +-
 include/trace/events/mmflags.h     | 161 ++++++++++++++++++++++++++++++++++++
 include/trace/events/vmscan.h      |   2 +-
 lib/test_printf.c                  |  53 ++++++++++++
 lib/vsprintf.c                     |  75 +++++++++++++++++
 mm/debug.c                         | 165 +++++++++----------------------------
 mm/internal.h                      |   6 ++
 mm/migrate.c                       |  13 ++-
 mm/oom_kill.c                      |   7 +-
 mm/page_alloc.c                    |  29 +++++--
 mm/page_owner.c                    | 100 +++++++++++++++++-----
 mm/vmstat.c                        |  15 +---
 tools/perf/builtin-kmem.c          |  13 ++-
 27 files changed, 559 insertions(+), 256 deletions(-)
 delete mode 100644 include/trace/events/gfpflags.h
 create mode 100644 include/trace/events/mmflags.h

-- 
2.6.3


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH v3 01/14] tracepoints: move trace_print_flags definitions to tracepoint-defs.h
  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 02/14] mm, tracing: make show_gfp_flags() up to date Vlastimil Babka
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Vlastimil Babka @ 2015-12-18  9:03 UTC (permalink / raw)
  To: Andrew Morton
  Cc: linux-mm, linux-kernel, Vlastimil Babka, Steven Rostedt,
	Peter Zijlstra, Arnaldo Carvalho de Melo, Ingo Molnar,
	Rasmus Villemoes, Joonsoo Kim, Minchan Kim, Sasha Levin,
	Kirill A. Shutemov, Mel Gorman, Michal Hocko

The following patch will need to declare array of struct trace_print_flags
in a header. To prevent this header from pulling in all of RCU through
trace_events.h, move the struct trace_print_flags{_64} definitions to the new
lightweight tracepoint-defs.h header.

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>
---
 include/linux/trace_events.h    | 10 ----------
 include/linux/tracepoint-defs.h | 14 ++++++++++++--
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h
index 429fdfc3baf5..d91404f89ff2 100644
--- a/include/linux/trace_events.h
+++ b/include/linux/trace_events.h
@@ -15,16 +15,6 @@ struct tracer;
 struct dentry;
 struct bpf_prog;
 
-struct trace_print_flags {
-	unsigned long		mask;
-	const char		*name;
-};
-
-struct trace_print_flags_u64 {
-	unsigned long long	mask;
-	const char		*name;
-};
-
 const char *trace_print_flags_seq(struct trace_seq *p, const char *delim,
 				  unsigned long flags,
 				  const struct trace_print_flags *flag_array);
diff --git a/include/linux/tracepoint-defs.h b/include/linux/tracepoint-defs.h
index e1ee97c713bf..4ac89acb6136 100644
--- a/include/linux/tracepoint-defs.h
+++ b/include/linux/tracepoint-defs.h
@@ -3,13 +3,23 @@
 
 /*
  * File can be included directly by headers who only want to access
- * tracepoint->key to guard out of line trace calls. Otherwise
- * linux/tracepoint.h should be used.
+ * tracepoint->key to guard out of line trace calls, or the definition of
+ * trace_print_flags{_u64}. Otherwise linux/tracepoint.h should be used.
  */
 
 #include <linux/atomic.h>
 #include <linux/static_key.h>
 
+struct trace_print_flags {
+	unsigned long		mask;
+	const char		*name;
+};
+
+struct trace_print_flags_u64 {
+	unsigned long long	mask;
+	const char		*name;
+};
+
 struct tracepoint_func {
 	void *func;
 	void *data;
-- 
2.6.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v3 02/14] mm, tracing: make show_gfp_flags() up to date
  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 ` [PATCH v3 01/14] tracepoints: move trace_print_flags definitions to tracepoint-defs.h Vlastimil Babka
@ 2015-12-18  9:03 ` Vlastimil Babka
  2016-01-07  9:29   ` Michal Hocko
  2015-12-18  9:03 ` [PATCH v3 03/14] tools, perf: make gfp_compact_table " Vlastimil Babka
                   ` (11 subsequent siblings)
  13 siblings, 1 reply; 25+ messages in thread
From: Vlastimil Babka @ 2015-12-18  9:03 UTC (permalink / raw)
  To: Andrew Morton
  Cc: linux-mm, linux-kernel, Vlastimil Babka, Steven Rostedt,
	Peter Zijlstra, Arnaldo Carvalho de Melo, Ingo Molnar,
	Rasmus Villemoes, Joonsoo Kim, Minchan Kim, Sasha Levin,
	Kirill A. Shutemov, Mel Gorman, Michal Hocko

The show_gfp_flags() macro provides human-friendly printing of gfp flags in
tracepoints. However, it is somewhat out of date and missing several flags.
This patches fills in the missing flags, and distinguishes properly between
GFP_ATOMIC and __GFP_ATOMIC which were both translated to "GFP_ATOMIC".

Also add a note in gfp.h so hopefully future changes will be synced better.

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>
---
 include/linux/gfp.h             | 5 +++++
 include/trace/events/gfpflags.h | 9 +++++++--
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index 91f74e741aa2..6ffee7f93af7 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -9,6 +9,11 @@
 
 struct vm_area_struct;
 
+/*
+ * In case of changes, please don't forget to update
+ * include/trace/events/gfpflags.h
+ */
+
 /* Plain integer GFP bitmasks. Do not use this directly. */
 #define ___GFP_DMA		0x01u
 #define ___GFP_HIGHMEM		0x02u
diff --git a/include/trace/events/gfpflags.h b/include/trace/events/gfpflags.h
index dde6bf092c8a..8395798d97b0 100644
--- a/include/trace/events/gfpflags.h
+++ b/include/trace/events/gfpflags.h
@@ -19,9 +19,13 @@
 	{(unsigned long)GFP_NOFS,		"GFP_NOFS"},		\
 	{(unsigned long)GFP_ATOMIC,		"GFP_ATOMIC"},		\
 	{(unsigned long)GFP_NOIO,		"GFP_NOIO"},		\
+	{(unsigned long)GFP_NOWAIT,		"GFP_NOWAIT"},		\
+	{(unsigned long)__GFP_DMA,		"GFP_DMA"},		\
+	{(unsigned long)__GFP_DMA32,		"GFP_DMA32"},		\
 	{(unsigned long)__GFP_HIGH,		"GFP_HIGH"},		\
-	{(unsigned long)__GFP_ATOMIC,		"GFP_ATOMIC"},		\
+	{(unsigned long)__GFP_ATOMIC,		"__GFP_ATOMIC"},	\
 	{(unsigned long)__GFP_IO,		"GFP_IO"},		\
+	{(unsigned long)__GFP_FS,		"GFP_FS"},		\
 	{(unsigned long)__GFP_COLD,		"GFP_COLD"},		\
 	{(unsigned long)__GFP_NOWARN,		"GFP_NOWARN"},		\
 	{(unsigned long)__GFP_REPEAT,		"GFP_REPEAT"},		\
@@ -36,8 +40,9 @@
 	{(unsigned long)__GFP_RECLAIMABLE,	"GFP_RECLAIMABLE"},	\
 	{(unsigned long)__GFP_MOVABLE,		"GFP_MOVABLE"},		\
 	{(unsigned long)__GFP_NOTRACK,		"GFP_NOTRACK"},		\
+	{(unsigned long)__GFP_WRITE,		"GFP_WRITE"},		\
 	{(unsigned long)__GFP_DIRECT_RECLAIM,	"GFP_DIRECT_RECLAIM"},	\
 	{(unsigned long)__GFP_KSWAPD_RECLAIM,	"GFP_KSWAPD_RECLAIM"},	\
 	{(unsigned long)__GFP_OTHER_NODE,	"GFP_OTHER_NODE"}	\
-	) : "GFP_NOWAIT"
+	) : "none"
 
-- 
2.6.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v3 03/14] tools, perf: make gfp_compact_table up to date
  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 ` [PATCH v3 01/14] tracepoints: move trace_print_flags definitions to tracepoint-defs.h 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
  2015-12-18  9:03 ` [PATCH v3 04/14] mm, tracing: unify mm flags handling in tracepoints and printk Vlastimil Babka
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Vlastimil Babka @ 2015-12-18  9:03 UTC (permalink / raw)
  To: Andrew Morton
  Cc: linux-mm, linux-kernel, Vlastimil Babka, Steven Rostedt,
	Peter Zijlstra, Arnaldo Carvalho de Melo, Ingo Molnar,
	Rasmus Villemoes, Joonsoo Kim, Minchan Kim, Sasha Levin,
	Kirill A. Shutemov, Mel Gorman, Michal Hocko

When updating tracing's show_gfp_flags() I have noticed that perf's
gfp_compact_table is also outdated. Fill in the missing flags and place a
note in gfp.h to increase chance that future updates are synced.

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>
---
 include/linux/gfp.h       |  2 +-
 tools/perf/builtin-kmem.c | 11 ++++++++---
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index 6ffee7f93af7..eed323f58547 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -11,7 +11,7 @@ struct vm_area_struct;
 
 /*
  * In case of changes, please don't forget to update
- * include/trace/events/gfpflags.h
+ * include/trace/events/gfpflags.h and tools/perf/builtin-kmem.c
  */
 
 /* Plain integer GFP bitmasks. Do not use this directly. */
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 93ce665f976f..acb0d011803a 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -616,9 +616,13 @@ static const struct {
 	{ "GFP_NOFS",			"NF" },
 	{ "GFP_ATOMIC",			"A" },
 	{ "GFP_NOIO",			"NI" },
+	{ "GFP_NOWAIT",			"NW" },
+	{ "GFP_DMA",			"D" },
+	{ "GFP_DMA32",			"D32" },
 	{ "GFP_HIGH",			"H" },
-	{ "GFP_WAIT",			"W" },
+	{ "__GFP_ATOMIC",		"_A" },
 	{ "GFP_IO",			"I" },
+	{ "GFP_FS",			"F" },
 	{ "GFP_COLD",			"CO" },
 	{ "GFP_NOWARN",			"NWR" },
 	{ "GFP_REPEAT",			"R" },
@@ -633,9 +637,10 @@ static const struct {
 	{ "GFP_RECLAIMABLE",		"RC" },
 	{ "GFP_MOVABLE",		"M" },
 	{ "GFP_NOTRACK",		"NT" },
-	{ "GFP_NO_KSWAPD",		"NK" },
+	{ "GFP_WRITE",			"WR" },
+	{ "GFP_DIRECT_RECLAIM",		"DR" },
+	{ "GFP_KSWAPD_RECLAIM",		"KR" },
 	{ "GFP_OTHER_NODE",		"ON" },
-	{ "GFP_NOWAIT",			"NW" },
 };
 
 static size_t max_gfp_len;
-- 
2.6.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v3 04/14] mm, tracing: unify mm flags handling in tracepoints and printk
  2015-12-18  9:03 [PATCH v3 00/14] mm flags in printk, page_owner improvements for debugging Vlastimil Babka
                   ` (2 preceding siblings ...)
  2015-12-18  9:03 ` [PATCH v3 03/14] tools, perf: make gfp_compact_table " Vlastimil Babka
@ 2015-12-18  9:03 ` Vlastimil Babka
  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
                   ` (9 subsequent siblings)
  13 siblings, 1 reply; 25+ messages in thread
From: Vlastimil Babka @ 2015-12-18  9:03 UTC (permalink / raw)
  To: Andrew Morton
  Cc: linux-mm, linux-kernel, Vlastimil Babka, Steven Rostedt,
	Peter Zijlstra, Arnaldo Carvalho de Melo, Ingo Molnar,
	Rasmus Villemoes, Joonsoo Kim, Minchan Kim, Sasha Levin,
	Kirill A. Shutemov, Mel Gorman, Michal Hocko

In tracepoints, it's possible to print gfp flags in a human-friendly format
through a macro show_gfp_flags(), which defines a translation array and passes
is to __print_flags(). Since the following patch will introduce support for
gfp flags printing in printk(), it would be nice to reuse the array. This is
not straightforward, since __print_flags() can't simply reference an array
defined in a .c file such as mm/debug.c - it has to be a macro to allow the
macro magic to communicate the format to userspace tools such as trace-cmd.

The solution is to create a macro __def_gfpflag_names which is used both in
show_gfp_flags(), and to define the gfpflag_names[] array in mm/debug.c.

On the other hand, mm/debug.c also defines translation tables for page
flags and vma flags, and desire was expressed (but not implemented in this
series) to use these also from tracepoints. Thus, this patch also renames the
events/gfpflags.h file to events/mmflags.h and moves the table definitions
there, using the same macro approach as for gfpflags. This allows translating
all three kinds of mm-specific flags both in tracepoints and printk.

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>
---
 include/linux/gfp.h                |   2 +-
 include/trace/events/btrfs.h       |   2 +-
 include/trace/events/compaction.h  |   2 +-
 include/trace/events/gfpflags.h    |  48 -----------
 include/trace/events/huge_memory.h |   2 -
 include/trace/events/kmem.h        |   2 +-
 include/trace/events/mmflags.h     | 161 +++++++++++++++++++++++++++++++++++++
 include/trace/events/vmscan.h      |   2 +-
 mm/debug.c                         |  88 +++-----------------
 tools/perf/builtin-kmem.c          |   2 +-
 10 files changed, 178 insertions(+), 133 deletions(-)
 delete mode 100644 include/trace/events/gfpflags.h
 create mode 100644 include/trace/events/mmflags.h

diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index eed323f58547..f6a5e2ba7152 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -11,7 +11,7 @@ struct vm_area_struct;
 
 /*
  * In case of changes, please don't forget to update
- * include/trace/events/gfpflags.h and tools/perf/builtin-kmem.c
+ * include/trace/events/mmflags.h and tools/perf/builtin-kmem.c
  */
 
 /* Plain integer GFP bitmasks. Do not use this directly. */
diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h
index b4473dab39d6..27843f5eccde 100644
--- a/include/trace/events/btrfs.h
+++ b/include/trace/events/btrfs.h
@@ -6,7 +6,7 @@
 
 #include <linux/writeback.h>
 #include <linux/tracepoint.h>
-#include <trace/events/gfpflags.h>
+#include <trace/events/mmflags.h>
 
 struct btrfs_root;
 struct btrfs_fs_info;
diff --git a/include/trace/events/compaction.h b/include/trace/events/compaction.h
index c92d1e1cbad9..111e5666e5eb 100644
--- a/include/trace/events/compaction.h
+++ b/include/trace/events/compaction.h
@@ -7,7 +7,7 @@
 #include <linux/types.h>
 #include <linux/list.h>
 #include <linux/tracepoint.h>
-#include <trace/events/gfpflags.h>
+#include <trace/events/mmflags.h>
 
 #define COMPACTION_STATUS					\
 	EM( COMPACT_DEFERRED,		"deferred")		\
diff --git a/include/trace/events/gfpflags.h b/include/trace/events/gfpflags.h
deleted file mode 100644
index 8395798d97b0..000000000000
--- a/include/trace/events/gfpflags.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * The order of these masks is important. Matching masks will be seen
- * first and the left over flags will end up showing by themselves.
- *
- * For example, if we have GFP_KERNEL before GFP_USER we wil get:
- *
- *  GFP_KERNEL|GFP_HARDWALL
- *
- * Thus most bits set go first.
- */
-#define show_gfp_flags(flags)						\
-	(flags) ? __print_flags(flags, "|",				\
-	{(unsigned long)GFP_TRANSHUGE,		"GFP_TRANSHUGE"},	\
-	{(unsigned long)GFP_HIGHUSER_MOVABLE,	"GFP_HIGHUSER_MOVABLE"}, \
-	{(unsigned long)GFP_HIGHUSER,		"GFP_HIGHUSER"},	\
-	{(unsigned long)GFP_USER,		"GFP_USER"},		\
-	{(unsigned long)GFP_TEMPORARY,		"GFP_TEMPORARY"},	\
-	{(unsigned long)GFP_KERNEL,		"GFP_KERNEL"},		\
-	{(unsigned long)GFP_NOFS,		"GFP_NOFS"},		\
-	{(unsigned long)GFP_ATOMIC,		"GFP_ATOMIC"},		\
-	{(unsigned long)GFP_NOIO,		"GFP_NOIO"},		\
-	{(unsigned long)GFP_NOWAIT,		"GFP_NOWAIT"},		\
-	{(unsigned long)__GFP_DMA,		"GFP_DMA"},		\
-	{(unsigned long)__GFP_DMA32,		"GFP_DMA32"},		\
-	{(unsigned long)__GFP_HIGH,		"GFP_HIGH"},		\
-	{(unsigned long)__GFP_ATOMIC,		"__GFP_ATOMIC"},	\
-	{(unsigned long)__GFP_IO,		"GFP_IO"},		\
-	{(unsigned long)__GFP_FS,		"GFP_FS"},		\
-	{(unsigned long)__GFP_COLD,		"GFP_COLD"},		\
-	{(unsigned long)__GFP_NOWARN,		"GFP_NOWARN"},		\
-	{(unsigned long)__GFP_REPEAT,		"GFP_REPEAT"},		\
-	{(unsigned long)__GFP_NOFAIL,		"GFP_NOFAIL"},		\
-	{(unsigned long)__GFP_NORETRY,		"GFP_NORETRY"},		\
-	{(unsigned long)__GFP_COMP,		"GFP_COMP"},		\
-	{(unsigned long)__GFP_ZERO,		"GFP_ZERO"},		\
-	{(unsigned long)__GFP_NOMEMALLOC,	"GFP_NOMEMALLOC"},	\
-	{(unsigned long)__GFP_MEMALLOC,		"GFP_MEMALLOC"},	\
-	{(unsigned long)__GFP_HARDWALL,		"GFP_HARDWALL"},	\
-	{(unsigned long)__GFP_THISNODE,		"GFP_THISNODE"},	\
-	{(unsigned long)__GFP_RECLAIMABLE,	"GFP_RECLAIMABLE"},	\
-	{(unsigned long)__GFP_MOVABLE,		"GFP_MOVABLE"},		\
-	{(unsigned long)__GFP_NOTRACK,		"GFP_NOTRACK"},		\
-	{(unsigned long)__GFP_WRITE,		"GFP_WRITE"},		\
-	{(unsigned long)__GFP_DIRECT_RECLAIM,	"GFP_DIRECT_RECLAIM"},	\
-	{(unsigned long)__GFP_KSWAPD_RECLAIM,	"GFP_KSWAPD_RECLAIM"},	\
-	{(unsigned long)__GFP_OTHER_NODE,	"GFP_OTHER_NODE"}	\
-	) : "none"
-
diff --git a/include/trace/events/huge_memory.h b/include/trace/events/huge_memory.h
index bfcf4a16aa94..8c62d1cac3b6 100644
--- a/include/trace/events/huge_memory.h
+++ b/include/trace/events/huge_memory.h
@@ -6,8 +6,6 @@
 
 #include  <linux/tracepoint.h>
 
-#include <trace/events/gfpflags.h>
-
 #define SCAN_STATUS							\
 	EM( SCAN_FAIL,			"failed")			\
 	EM( SCAN_SUCCEED,		"succeeded")			\
diff --git a/include/trace/events/kmem.h b/include/trace/events/kmem.h
index f7554fd7fc62..ca7217389067 100644
--- a/include/trace/events/kmem.h
+++ b/include/trace/events/kmem.h
@@ -6,7 +6,7 @@
 
 #include <linux/types.h>
 #include <linux/tracepoint.h>
-#include <trace/events/gfpflags.h>
+#include <trace/events/mmflags.h>
 
 DECLARE_EVENT_CLASS(kmem_alloc,
 
diff --git a/include/trace/events/mmflags.h b/include/trace/events/mmflags.h
new file mode 100644
index 000000000000..1cabf464cd8f
--- /dev/null
+++ b/include/trace/events/mmflags.h
@@ -0,0 +1,161 @@
+/*
+ * The order of these masks is important. Matching masks will be seen
+ * first and the left over flags will end up showing by themselves.
+ *
+ * For example, if we have GFP_KERNEL before GFP_USER we wil get:
+ *
+ *  GFP_KERNEL|GFP_HARDWALL
+ *
+ * Thus most bits set go first.
+ */
+
+#define __def_gfpflag_names						\
+	{(unsigned long)GFP_TRANSHUGE,		"GFP_TRANSHUGE"},	\
+	{(unsigned long)GFP_HIGHUSER_MOVABLE,	"GFP_HIGHUSER_MOVABLE"},\
+	{(unsigned long)GFP_HIGHUSER,		"GFP_HIGHUSER"},	\
+	{(unsigned long)GFP_USER,		"GFP_USER"},		\
+	{(unsigned long)GFP_TEMPORARY,		"GFP_TEMPORARY"},	\
+	{(unsigned long)GFP_KERNEL,		"GFP_KERNEL"},		\
+	{(unsigned long)GFP_NOFS,		"GFP_NOFS"},		\
+	{(unsigned long)GFP_ATOMIC,		"GFP_ATOMIC"},		\
+	{(unsigned long)GFP_NOIO,		"GFP_NOIO"},		\
+	{(unsigned long)GFP_NOWAIT,		"GFP_NOWAIT"},		\
+	{(unsigned long)__GFP_DMA,		"GFP_DMA"},		\
+	{(unsigned long)__GFP_DMA32,		"GFP_DMA32"},		\
+	{(unsigned long)__GFP_HIGH,		"GFP_HIGH"},		\
+	{(unsigned long)__GFP_ATOMIC,		"__GFP_ATOMIC"},	\
+	{(unsigned long)__GFP_IO,		"GFP_IO"},		\
+	{(unsigned long)__GFP_FS,		"GFP_FS"},		\
+	{(unsigned long)__GFP_COLD,		"GFP_COLD"},		\
+	{(unsigned long)__GFP_NOWARN,		"GFP_NOWARN"},		\
+	{(unsigned long)__GFP_REPEAT,		"GFP_REPEAT"},		\
+	{(unsigned long)__GFP_NOFAIL,		"GFP_NOFAIL"},		\
+	{(unsigned long)__GFP_NORETRY,		"GFP_NORETRY"},		\
+	{(unsigned long)__GFP_COMP,		"GFP_COMP"},		\
+	{(unsigned long)__GFP_ZERO,		"GFP_ZERO"},		\
+	{(unsigned long)__GFP_NOMEMALLOC,	"GFP_NOMEMALLOC"},	\
+	{(unsigned long)__GFP_MEMALLOC,		"GFP_MEMALLOC"},	\
+	{(unsigned long)__GFP_HARDWALL,		"GFP_HARDWALL"},	\
+	{(unsigned long)__GFP_THISNODE,		"GFP_THISNODE"},	\
+	{(unsigned long)__GFP_RECLAIMABLE,	"GFP_RECLAIMABLE"},	\
+	{(unsigned long)__GFP_MOVABLE,		"GFP_MOVABLE"},		\
+	{(unsigned long)__GFP_NOTRACK,		"GFP_NOTRACK"},		\
+	{(unsigned long)__GFP_WRITE,		"GFP_WRITE"},		\
+	{(unsigned long)__GFP_DIRECT_RECLAIM,	"GFP_DIRECT_RECLAIM"},	\
+	{(unsigned long)__GFP_KSWAPD_RECLAIM,	"GFP_KSWAPD_RECLAIM"},	\
+	{(unsigned long)__GFP_OTHER_NODE,	"GFP_OTHER_NODE"}	\
+
+#define show_gfp_flags(flags)						\
+	(flags) ? __print_flags(flags, "|",				\
+	__def_gfpflag_names						\
+	) : "none"
+
+#ifdef CONFIG_MMU
+#define IF_HAVE_PG_MLOCK(flag,string) ,{1UL << flag, string}
+#else
+#define IF_HAVE_PG_MLOCK(flag,string)
+#endif
+
+#ifdef CONFIG_ARCH_USES_PG_UNCACHED
+#define IF_HAVE_PG_UNCACHED(flag,string) ,{1UL << flag, string}
+#else
+#define IF_HAVE_PG_UNCACHED(flag,string)
+#endif
+
+#ifdef CONFIG_MEMORY_FAILURE
+#define IF_HAVE_PG_HWPOISON(flag,string) ,{1UL << flag, string}
+#else
+#define IF_HAVE_PG_HWPOISON(flag,string)
+#endif
+
+#if defined(CONFIG_IDLE_PAGE_TRACKING) && defined(CONFIG_64BIT)
+#define IF_HAVE_PG_IDLE(flag,string) ,{1UL << flag, string}
+#else
+#define IF_HAVE_PG_IDLE(flag,string)
+#endif
+
+#define __def_pageflag_names						\
+	{1UL << PG_locked,		"locked"	},		\
+	{1UL << PG_error,		"error"		},		\
+	{1UL << PG_referenced,		"referenced"	},		\
+	{1UL << PG_uptodate,		"uptodate"	},		\
+	{1UL << PG_dirty,		"dirty"		},		\
+	{1UL << PG_lru,			"lru"		},		\
+	{1UL << PG_active,		"active"	},		\
+	{1UL << PG_slab,		"slab"		},		\
+	{1UL << PG_owner_priv_1,	"owner_priv_1"	},		\
+	{1UL << PG_arch_1,		"arch_1"	},		\
+	{1UL << PG_reserved,		"reserved"	},		\
+	{1UL << PG_private,		"private"	},		\
+	{1UL << PG_private_2,		"private_2"	},		\
+	{1UL << PG_writeback,		"writeback"	},		\
+	{1UL << PG_head,		"head"		},		\
+	{1UL << PG_swapcache,		"swapcache"	},		\
+	{1UL << PG_mappedtodisk,	"mappedtodisk"	},		\
+	{1UL << PG_reclaim,		"reclaim"	},		\
+	{1UL << PG_swapbacked,		"swapbacked"	},		\
+	{1UL << PG_unevictable,		"unevictable"	}		\
+IF_HAVE_PG_MLOCK(PG_mlocked,		"mlocked"	)		\
+IF_HAVE_PG_UNCACHED(PG_uncached,	"uncached"	)		\
+IF_HAVE_PG_HWPOISON(PG_hwpoison,	"hwpoison"	)		\
+IF_HAVE_PG_IDLE(PG_young,		"young"		)		\
+IF_HAVE_PG_IDLE(PG_idle,		"idle"		)
+
+#define show_page_flags(flags)						\
+	(flags) ? __print_flags(flags, "|",				\
+	__def_pageflag_names						\
+	) : "none"
+
+#if defined(CONFIG_X86)
+#define __VM_ARCH_SPECIFIC {VM_PAT,     "pat"           }
+#elif defined(CONFIG_PPC)
+#define __VM_ARCH_SPECIFIC {VM_SAO,     "sao"           }
+#elif defined(CONFIG_PARISC) || defined(CONFIG_METAG) || defined(CONFIG_IA64)
+#define __VM_ARCH_SPECIFIC {VM_GROWSUP,	"growsup"	}
+#elif !defined(CONFIG_MMU)
+#define __VM_ARCH_SPECIFIC {VM_MAPPED_COPY,"mappedcopy"	}
+#else
+#define __VM_ARCH_SPECIFIC {VM_ARCH_1,	"arch_1"	}
+#endif
+
+#ifdef CONFIG_MEM_SOFT_DIRTY
+#define IF_HAVE_VM_SOFTDIRTY(flag,name) {flag, name },
+#else
+#define IF_HAVE_VM_SOFTDIRTY(flag,name)
+#endif
+
+#define __def_vmaflag_names						\
+	{VM_READ,			"read"		},		\
+	{VM_WRITE,			"write"		},		\
+	{VM_EXEC,			"exec"		},		\
+	{VM_SHARED,			"shared"	},		\
+	{VM_MAYREAD,			"mayread"	},		\
+	{VM_MAYWRITE,			"maywrite"	},		\
+	{VM_MAYEXEC,			"mayexec"	},		\
+	{VM_MAYSHARE,			"mayshare"	},		\
+	{VM_GROWSDOWN,			"growsdown"	},		\
+	{VM_PFNMAP,			"pfnmap"	},		\
+	{VM_DENYWRITE,			"denywrite"	},		\
+	{VM_LOCKONFAULT,		"lockonfault"	},		\
+	{VM_LOCKED,			"locked"	},		\
+	{VM_IO,				"io"		},		\
+	{VM_SEQ_READ,			"seqread"	},		\
+	{VM_RAND_READ,			"randread"	},		\
+	{VM_DONTCOPY,			"dontcopy"	},		\
+	{VM_DONTEXPAND,			"dontexpand"	},		\
+	{VM_ACCOUNT,			"account"	},		\
+	{VM_NORESERVE,			"noreserve"	},		\
+	{VM_HUGETLB,			"hugetlb"	},		\
+	__VM_ARCH_SPECIFIC				,		\
+	{VM_DONTDUMP,			"dontdump"	},		\
+IF_HAVE_VM_SOFTDIRTY(VM_SOFTDIRTY,	"softdirty"	)		\
+	{VM_MIXEDMAP,			"mixedmap"	},		\
+	{VM_HUGEPAGE,			"hugepage"	},		\
+	{VM_NOHUGEPAGE,			"nohugepage"	},		\
+	{VM_MERGEABLE,			"mergeable"	}		\
+
+#define show_vma_flags(flags)						\
+	(flags) ? __print_flags(flags, "|",				\
+	__def_vmaflag_names						\
+	) : "none"
+
diff --git a/include/trace/events/vmscan.h b/include/trace/events/vmscan.h
index 31763dd8db1c..0101ef37f1ee 100644
--- a/include/trace/events/vmscan.h
+++ b/include/trace/events/vmscan.h
@@ -8,7 +8,7 @@
 #include <linux/tracepoint.h>
 #include <linux/mm.h>
 #include <linux/memcontrol.h>
-#include <trace/events/gfpflags.h>
+#include <trace/events/mmflags.h>
 
 #define RECLAIM_WB_ANON		0x0001u
 #define RECLAIM_WB_FILE		0x0002u
diff --git a/mm/debug.c b/mm/debug.c
index 836276586185..85f71e4ce59f 100644
--- a/mm/debug.c
+++ b/mm/debug.c
@@ -9,41 +9,14 @@
 #include <linux/mm.h>
 #include <linux/trace_events.h>
 #include <linux/memcontrol.h>
+#include <trace/events/mmflags.h>
 
 static const struct trace_print_flags pageflag_names[] = {
-	{1UL << PG_locked,		"locked"	},
-	{1UL << PG_error,		"error"		},
-	{1UL << PG_referenced,		"referenced"	},
-	{1UL << PG_uptodate,		"uptodate"	},
-	{1UL << PG_dirty,		"dirty"		},
-	{1UL << PG_lru,			"lru"		},
-	{1UL << PG_active,		"active"	},
-	{1UL << PG_slab,		"slab"		},
-	{1UL << PG_owner_priv_1,	"owner_priv_1"	},
-	{1UL << PG_arch_1,		"arch_1"	},
-	{1UL << PG_reserved,		"reserved"	},
-	{1UL << PG_private,		"private"	},
-	{1UL << PG_private_2,		"private_2"	},
-	{1UL << PG_writeback,		"writeback"	},
-	{1UL << PG_head,		"head"		},
-	{1UL << PG_swapcache,		"swapcache"	},
-	{1UL << PG_mappedtodisk,	"mappedtodisk"	},
-	{1UL << PG_reclaim,		"reclaim"	},
-	{1UL << PG_swapbacked,		"swapbacked"	},
-	{1UL << PG_unevictable,		"unevictable"	},
-#ifdef CONFIG_MMU
-	{1UL << PG_mlocked,		"mlocked"	},
-#endif
-#ifdef CONFIG_ARCH_USES_PG_UNCACHED
-	{1UL << PG_uncached,		"uncached"	},
-#endif
-#ifdef CONFIG_MEMORY_FAILURE
-	{1UL << PG_hwpoison,		"hwpoison"	},
-#endif
-#if defined(CONFIG_IDLE_PAGE_TRACKING) && defined(CONFIG_64BIT)
-	{1UL << PG_young,		"young"		},
-	{1UL << PG_idle,		"idle"		},
-#endif
+	__def_pageflag_names
+};
+
+static const struct trace_print_flags gfpflag_names[] = {
+	__def_gfpflag_names
 };
 
 static void dump_flags(unsigned long flags,
@@ -108,47 +81,8 @@ EXPORT_SYMBOL(dump_page);
 
 #ifdef CONFIG_DEBUG_VM
 
-static const struct trace_print_flags vmaflags_names[] = {
-	{VM_READ,			"read"		},
-	{VM_WRITE,			"write"		},
-	{VM_EXEC,			"exec"		},
-	{VM_SHARED,			"shared"	},
-	{VM_MAYREAD,			"mayread"	},
-	{VM_MAYWRITE,			"maywrite"	},
-	{VM_MAYEXEC,			"mayexec"	},
-	{VM_MAYSHARE,			"mayshare"	},
-	{VM_GROWSDOWN,			"growsdown"	},
-	{VM_PFNMAP,			"pfnmap"	},
-	{VM_DENYWRITE,			"denywrite"	},
-	{VM_LOCKONFAULT,		"lockonfault"	},
-	{VM_LOCKED,			"locked"	},
-	{VM_IO,				"io"		},
-	{VM_SEQ_READ,			"seqread"	},
-	{VM_RAND_READ,			"randread"	},
-	{VM_DONTCOPY,			"dontcopy"	},
-	{VM_DONTEXPAND,			"dontexpand"	},
-	{VM_ACCOUNT,			"account"	},
-	{VM_NORESERVE,			"noreserve"	},
-	{VM_HUGETLB,			"hugetlb"	},
-#if defined(CONFIG_X86)
-	{VM_PAT,			"pat"		},
-#elif defined(CONFIG_PPC)
-	{VM_SAO,			"sao"		},
-#elif defined(CONFIG_PARISC) || defined(CONFIG_METAG) || defined(CONFIG_IA64)
-	{VM_GROWSUP,			"growsup"	},
-#elif !defined(CONFIG_MMU)
-	{VM_MAPPED_COPY,		"mappedcopy"	},
-#else
-	{VM_ARCH_1,			"arch_1"	},
-#endif
-	{VM_DONTDUMP,			"dontdump"	},
-#ifdef CONFIG_MEM_SOFT_DIRTY
-	{VM_SOFTDIRTY,			"softdirty"	},
-#endif
-	{VM_MIXEDMAP,			"mixedmap"	},
-	{VM_HUGEPAGE,			"hugepage"	},
-	{VM_NOHUGEPAGE,			"nohugepage"	},
-	{VM_MERGEABLE,			"mergeable"	},
+static const struct trace_print_flags vmaflag_names[] = {
+	__def_vmaflag_names
 };
 
 void dump_vma(const struct vm_area_struct *vma)
@@ -162,7 +96,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, vmaflags_names, ARRAY_SIZE(vmaflags_names));
+	dump_flags(vma->vm_flags, vmaflag_names, ARRAY_SIZE(vmaflag_names));
 }
 EXPORT_SYMBOL(dump_vma);
 
@@ -233,8 +167,8 @@ void dump_mm(const struct mm_struct *mm)
 		""		/* This is here to not have a comma! */
 		);
 
-		dump_flags(mm->def_flags, vmaflags_names,
-				ARRAY_SIZE(vmaflags_names));
+		dump_flags(mm->def_flags, vmaflag_names,
+				ARRAY_SIZE(vmaflag_names));
 }
 
 #endif		/* CONFIG_DEBUG_VM */
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index acb0d011803a..d99083170315 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -602,7 +602,7 @@ static int gfpcmp(const void *a, const void *b)
 	return fa->flags - fb->flags;
 }
 
-/* see include/trace/events/gfpflags.h */
+/* see include/trace/events/mmflags.h */
 static const struct {
 	const char *original;
 	const char *compact;
-- 
2.6.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v3 05/14] mm, printk: introduce new format string for flags
  2015-12-18  9:03 [PATCH v3 00/14] mm flags in printk, page_owner improvements for debugging Vlastimil Babka
                   ` (3 preceding siblings ...)
  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:53   ` Michal Hocko
  2015-12-18  9:03 ` [PATCH v3 06/14] mm, debug: replace dump_flags() with the new printk formats Vlastimil Babka
                   ` (8 subsequent siblings)
  13 siblings, 1 reply; 25+ messages in thread
From: Vlastimil Babka @ 2015-12-18  9:03 UTC (permalink / raw)
  To: Andrew Morton
  Cc: linux-mm, linux-kernel, Vlastimil Babka, Steven Rostedt,
	Peter Zijlstra, Arnaldo Carvalho de Melo, Ingo Molnar,
	Rasmus Villemoes, Joonsoo Kim, Minchan Kim, Sasha Levin,
	Kirill A. Shutemov, Mel Gorman, Michal Hocko

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


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v3 06/14] mm, debug: replace dump_flags() with the new printk formats
  2015-12-18  9:03 [PATCH v3 00/14] mm flags in printk, page_owner improvements for debugging Vlastimil Babka
                   ` (4 preceding siblings ...)
  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:57   ` Michal Hocko
  2015-12-18  9:03 ` [PATCH v3 07/14] mm, page_alloc: print symbolic gfp_flags on allocation failure Vlastimil Babka
                   ` (7 subsequent siblings)
  13 siblings, 1 reply; 25+ messages in thread
From: Vlastimil Babka @ 2015-12-18  9:03 UTC (permalink / raw)
  To: Andrew Morton
  Cc: linux-mm, linux-kernel, Vlastimil Babka, Steven Rostedt,
	Peter Zijlstra, Arnaldo Carvalho de Melo, Ingo Molnar,
	Rasmus Villemoes, Joonsoo Kim, Minchan Kim, Sasha Levin,
	Kirill A. Shutemov, Mel Gorman, Michal Hocko

With the new printk format strings for flags, we can get rid of dump_flags()
in mm/debug.c.

This also fixes dump_vma() which used dump_flags() for printing vma flags.
However dump_flags() did a page-flags specific filtering of bits higher than
NR_PAGEFLAGS in order to remove the zone id part. For dump_vma() this resulted
in removing several VM_* flags from the symbolic translation.

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>
---
 mm/debug.c | 60 ++++++++++++++----------------------------------------------
 1 file changed, 14 insertions(+), 46 deletions(-)

diff --git a/mm/debug.c b/mm/debug.c
index 79621a5ce46f..5ea57bc49ef6 100644
--- a/mm/debug.c
+++ b/mm/debug.c
@@ -28,36 +28,6 @@ const struct trace_print_flags vmaflag_names[] = {
 	{0, NULL}
 };
 
-static void dump_flags(unsigned long flags,
-			const struct trace_print_flags *names, int count)
-{
-	const char *delim = "";
-	unsigned long mask;
-	int i;
-
-	pr_emerg("flags: %#lx(", flags);
-
-	/* remove zone id */
-	flags &= (1UL << NR_PAGEFLAGS) - 1;
-
-	for (i = 0; i < count && flags; i++) {
-
-		mask = names[i].mask;
-		if ((flags & mask) != mask)
-			continue;
-
-		flags &= ~mask;
-		pr_cont("%s%s", delim, names[i].name);
-		delim = "|";
-	}
-
-	/* check for left over flags */
-	if (flags)
-		pr_cont("%s%#lx", delim, flags);
-
-	pr_cont(")\n");
-}
-
 void dump_page_badflags(struct page *page, const char *reason,
 		unsigned long badflags)
 {
@@ -68,15 +38,15 @@ void dump_page_badflags(struct page *page, const char *reason,
 		pr_cont(" compound_mapcount: %d", compound_mapcount(page));
 	pr_cont("\n");
 	BUILD_BUG_ON(ARRAY_SIZE(pageflag_names) != __NR_PAGEFLAGS + 1);
-	dump_flags(page->flags, pageflag_names,
-					ARRAY_SIZE(pageflag_names) - 1);
+	pr_emerg("flags: %#lx(%pgp)\n", page->flags, &page->flags);
+
 	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) - 1);
-	}
+
+	badflags &= page->flags;
+	if (badflags)
+		pr_alert("bad because of flags: %#lx(%pgp)\n", badflags,
+								&badflags);
 #ifdef CONFIG_MEMCG
 	if (page->mem_cgroup)
 		pr_alert("page->mem_cgroup:%p\n", page->mem_cgroup);
@@ -96,13 +66,14 @@ void dump_vma(const struct vm_area_struct *vma)
 	pr_emerg("vma %p start %p end %p\n"
 		"next %p prev %p mm %p\n"
 		"prot %lx anon_vma %p vm_ops %p\n"
-		"pgoff %lx file %p private_data %p\n",
+		"pgoff %lx file %p private_data %p\n"
+		"flags: %#lx(%pgv)\n",
 		vma, (void *)vma->vm_start, (void *)vma->vm_end, vma->vm_next,
 		vma->vm_prev, vma->vm_mm,
 		(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) - 1);
+		vma->vm_file, vma->vm_private_data,
+		vma->vm_flags, &vma->vm_flags);
 }
 EXPORT_SYMBOL(dump_vma);
 
@@ -136,7 +107,7 @@ void dump_mm(const struct mm_struct *mm)
 #if defined(CONFIG_NUMA_BALANCING) || defined(CONFIG_COMPACTION)
 		"tlb_flush_pending %d\n"
 #endif
-		"%s",	/* This is here to hold the comma */
+		"def_flags: %#lx(%pgv)\n",
 
 		mm, mm->mmap, mm->vmacache_seqnum, mm->task_size,
 #ifdef CONFIG_MMU
@@ -170,11 +141,8 @@ void dump_mm(const struct mm_struct *mm)
 #if defined(CONFIG_NUMA_BALANCING) || defined(CONFIG_COMPACTION)
 		mm->tlb_flush_pending,
 #endif
-		""		/* This is here to not have a comma! */
-		);
-
-		dump_flags(mm->def_flags, vmaflag_names,
-				ARRAY_SIZE(vmaflag_names) - 1);
+		mm->def_flags, &mm->def_flags
+	);
 }
 
 #endif		/* CONFIG_DEBUG_VM */
-- 
2.6.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v3 07/14] mm, page_alloc: print symbolic gfp_flags on allocation failure
  2015-12-18  9:03 [PATCH v3 00/14] mm flags in printk, page_owner improvements for debugging Vlastimil Babka
                   ` (5 preceding siblings ...)
  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
  2015-12-18  9:03 ` [PATCH v3 08/14] mm, oom: print symbolic gfp_flags in oom warning Vlastimil Babka
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Vlastimil Babka @ 2015-12-18  9:03 UTC (permalink / raw)
  To: Andrew Morton
  Cc: linux-mm, linux-kernel, Vlastimil Babka, Joonsoo Kim,
	Minchan Kim, Sasha Levin, Kirill A. Shutemov, Mel Gorman,
	Michal Hocko

It would be useful to translate gfp_flags into string representation when
printing in case of an allocation failure, especially as the flags have been
undergoing some changes recently and the script ./scripts/gfp-translate needs
a matching source version to be accurate.

Example output:

stapio: page allocation failure: order:9, mode:0x2080020(GFP_ATOMIC)

Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
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>
Acked-by: Michal Hocko <mhocko@suse.com>
---
 mm/page_alloc.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 25409714160e..08e514721a57 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -2689,9 +2689,8 @@ void warn_alloc_failed(gfp_t gfp_mask, unsigned int order, const char *fmt, ...)
 		va_end(args);
 	}
 
-	pr_warn("%s: page allocation failure: order:%u, mode:0x%x\n",
-		current->comm, order, gfp_mask);
-
+	pr_warn("%s: page allocation failure: order:%u, mode:%#x(%pgg)\n",
+		current->comm, order, gfp_mask, &gfp_mask);
 	dump_stack();
 	if (!should_suppress_show_mem())
 		show_mem(filter);
-- 
2.6.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v3 08/14] mm, oom: print symbolic gfp_flags in oom warning
  2015-12-18  9:03 [PATCH v3 00/14] mm flags in printk, page_owner improvements for debugging Vlastimil Babka
                   ` (6 preceding siblings ...)
  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 09/14] mm, page_owner: print migratetype of page and pageblock, symbolic flags Vlastimil Babka
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Vlastimil Babka @ 2015-12-18  9:03 UTC (permalink / raw)
  To: Andrew Morton
  Cc: linux-mm, linux-kernel, Vlastimil Babka, Joonsoo Kim,
	Minchan Kim, Sasha Levin, Kirill A. Shutemov, Mel Gorman,
	Michal Hocko

It would be useful to translate gfp_flags into string representation when
printing in case of an OOM, especially as the flags have been undergoing some
changes recently and the script ./scripts/gfp-translate needs a matching source
version to be accurate.

Example output:

a.out invoked oom-killer: order=0, gfp_mask=0x24280ca(GFP_HIGHUSER_MOVABLE|GFP_ZERO), om_score_adj=0

Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
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>
Acked-by: Michal Hocko <mhocko@suse.com>
---
 mm/oom_kill.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index dc490c06941b..f92b75750fc5 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -386,10 +386,11 @@ static void dump_tasks(struct mem_cgroup *memcg, const nodemask_t *nodemask)
 static void dump_header(struct oom_control *oc, struct task_struct *p,
 			struct mem_cgroup *memcg)
 {
-	pr_warning("%s invoked oom-killer: gfp_mask=0x%x, order=%d, "
-		"oom_score_adj=%hd\n",
-		current->comm, oc->gfp_mask, oc->order,
+	pr_warn("%s invoked oom-killer: order=%d, gfp_mask=%#x(%pgg), "
+			"oom_score_adj=%hd\n",
+		current->comm, oc->order, oc->gfp_mask, &oc->gfp_mask,
 		current->signal->oom_score_adj);
+
 	cpuset_print_current_mems_allowed();
 	dump_stack();
 	if (memcg)
-- 
2.6.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v3 09/14] mm, page_owner: print migratetype of page and pageblock, symbolic flags
  2015-12-18  9:03 [PATCH v3 00/14] mm flags in printk, page_owner improvements for debugging Vlastimil Babka
                   ` (7 preceding siblings ...)
  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
  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
                   ` (4 subsequent siblings)
  13 siblings, 1 reply; 25+ messages in thread
From: Vlastimil Babka @ 2015-12-18  9:03 UTC (permalink / raw)
  To: Andrew Morton
  Cc: linux-mm, linux-kernel, Vlastimil Babka, Joonsoo Kim,
	Minchan Kim, Sasha Levin, Kirill A. Shutemov, Mel Gorman,
	Michal Hocko

The information in /sys/kernel/debug/page_owner includes the migratetype of
the pageblock the page belongs to. This is also checked against the page's
migratetype (as declared by gfp_flags during its allocation), and the page is
reported as Fallback if its migratetype differs from the pageblock's one.
t
This is somewhat misleading because in fact fallback allocation is not the only
reason why these two can differ. It also doesn't direcly provide the page's
migratetype, although it's possible to derive that from the gfp_flags.

It's arguably better to print both page and pageblock's migratetype and leave
the interpretation to the consumer than to suggest fallback allocation as the
only possible reason. While at it, we can print the migratetypes as string
the same way as /proc/pagetypeinfo does, as some of the numeric values depend
on kernel configuration. For that, this patch moves the migratetype_names
array from #ifdef CONFIG_PROC_FS part of mm/vmstat.c to mm/page_alloc.c and
exports it.

With the new format strings for flags, we can now also provide symbolic page
and gfp flags in the /sys/kernel/debug/page_owner file. This replaces the
positional printing of page flags as single letters, which might have looked
nicer, but was limited to a subset of flags, and required the user to remember
the letters.

Example page_owner entry after the patch:

Page allocated via order 0, mask 0x24213ca(GFP_HIGHUSER_MOVABLE|GFP_COLD|GFP_NOWARN|GFP_NORETRY)
PFN 674308 type Movable Block 1317 type Movable Flags 0x1fffff80010068(uptodate|lru|active|mappedtodisk)
 [<ffffffff81164e9a>] __alloc_pages_nodemask+0x15a/0xa30
 [<ffffffff811ab938>] alloc_pages_current+0x88/0x120
 [<ffffffff8115bc46>] __page_cache_alloc+0xe6/0x120
 [<ffffffff81168b9b>] __do_page_cache_readahead+0xdb/0x200
 [<ffffffff81168df5>] ondemand_readahead+0x135/0x260
 [<ffffffff81168f8c>] page_cache_async_readahead+0x6c/0x70
 [<ffffffff8115d5f8>] generic_file_read_iter+0x378/0x590
 [<ffffffff811d12a7>] __vfs_read+0xa7/0xd0

Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
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>
---
 include/linux/mmzone.h |  3 +++
 mm/page_alloc.c        | 13 +++++++++++++
 mm/page_owner.c        | 24 +++++++-----------------
 mm/vmstat.c            | 13 -------------
 4 files changed, 23 insertions(+), 30 deletions(-)

diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 33bb1b19273e..68cc063bf0b7 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -63,6 +63,9 @@ enum {
 	MIGRATE_TYPES
 };
 
+/* In mm/page_alloc.c; keep in sync also with show_migration_types() there */
+extern char * const migratetype_names[MIGRATE_TYPES];
+
 #ifdef CONFIG_CMA
 #  define is_migrate_cma(migratetype) unlikely((migratetype) == MIGRATE_CMA)
 #else
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 08e514721a57..67538b58e478 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -222,6 +222,19 @@ static char * const zone_names[MAX_NR_ZONES] = {
 #endif
 };
 
+char * const migratetype_names[MIGRATE_TYPES] = {
+	"Unmovable",
+	"Movable",
+	"Reclaimable",
+	"HighAtomic",
+#ifdef CONFIG_CMA
+	"CMA",
+#endif
+#ifdef CONFIG_MEMORY_ISOLATION
+	"Isolate",
+#endif
+};
+
 compound_page_dtor * const compound_page_dtors[] = {
 	NULL,
 	free_compound_page,
diff --git a/mm/page_owner.c b/mm/page_owner.c
index 983c3a10fa07..5392195fca61 100644
--- a/mm/page_owner.c
+++ b/mm/page_owner.c
@@ -100,8 +100,9 @@ print_page_owner(char __user *buf, size_t count, unsigned long pfn,
 		return -ENOMEM;
 
 	ret = snprintf(kbuf, count,
-			"Page allocated via order %u, mask 0x%x\n",
-			page_ext->order, page_ext->gfp_mask);
+			"Page allocated via order %u, mask %#x(%pgg)\n",
+			page_ext->order, page_ext->gfp_mask,
+			&page_ext->gfp_mask);
 
 	if (ret >= count)
 		goto err;
@@ -110,23 +111,12 @@ print_page_owner(char __user *buf, size_t count, unsigned long pfn,
 	pageblock_mt = get_pfnblock_migratetype(page, pfn);
 	page_mt  = gfpflags_to_migratetype(page_ext->gfp_mask);
 	ret += snprintf(kbuf + ret, count - ret,
-			"PFN %lu Block %lu type %d %s Flags %s%s%s%s%s%s%s%s%s%s%s%s\n",
+			"PFN %lu type %s Block %lu type %s Flags %#lx(%pgp)\n",
 			pfn,
+			migratetype_names[page_mt],
 			pfn >> pageblock_order,
-			pageblock_mt,
-			pageblock_mt != page_mt ? "Fallback" : "        ",
-			PageLocked(page)	? "K" : " ",
-			PageError(page)		? "E" : " ",
-			PageReferenced(page)	? "R" : " ",
-			PageUptodate(page)	? "U" : " ",
-			PageDirty(page)		? "D" : " ",
-			PageLRU(page)		? "L" : " ",
-			PageActive(page)	? "A" : " ",
-			PageSlab(page)		? "S" : " ",
-			PageWriteback(page)	? "W" : " ",
-			PageCompound(page)	? "C" : " ",
-			PageSwapCache(page)	? "B" : " ",
-			PageMappedToDisk(page)	? "M" : " ");
+			migratetype_names[pageblock_mt],
+			page->flags, &page->flags);
 
 	if (ret >= count)
 		goto err;
diff --git a/mm/vmstat.c b/mm/vmstat.c
index dfe7315f2db6..475d154411f0 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -924,19 +924,6 @@ static void walk_zones_in_node(struct seq_file *m, pg_data_t *pgdat,
 #endif
 
 #ifdef CONFIG_PROC_FS
-static char * const migratetype_names[MIGRATE_TYPES] = {
-	"Unmovable",
-	"Movable",
-	"Reclaimable",
-	"HighAtomic",
-#ifdef CONFIG_CMA
-	"CMA",
-#endif
-#ifdef CONFIG_MEMORY_ISOLATION
-	"Isolate",
-#endif
-};
-
 static void frag_show_print(struct seq_file *m, pg_data_t *pgdat,
 						struct zone *zone)
 {
-- 
2.6.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v3 10/14] mm, page_owner: convert page_owner_inited to static key
  2015-12-18  9:03 [PATCH v3 00/14] mm flags in printk, page_owner improvements for debugging Vlastimil Babka
                   ` (8 preceding siblings ...)
  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:21   ` Michal Hocko
  2015-12-18  9:03 ` [PATCH v3 11/14] mm, page_owner: copy page owner info during migration Vlastimil Babka
                   ` (3 subsequent siblings)
  13 siblings, 1 reply; 25+ messages in thread
From: Vlastimil Babka @ 2015-12-18  9:03 UTC (permalink / raw)
  To: Andrew Morton
  Cc: linux-mm, linux-kernel, Vlastimil Babka, Joonsoo Kim,
	Minchan Kim, Sasha Levin, Kirill A. Shutemov, Mel Gorman,
	Michal Hocko

CONFIG_PAGE_OWNER attempts to impose negligible runtime overhead when enabled
during compilation, but not actually enabled during runtime by boot param
page_owner=on. This overhead can be further reduced using the static key
mechanism, which this patch does.

Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
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>
---
 Documentation/vm/page_owner.txt |  9 +++++----
 include/linux/page_owner.h      | 22 ++++++++++------------
 mm/page_owner.c                 |  9 +++++----
 mm/vmstat.c                     |  2 +-
 4 files changed, 21 insertions(+), 21 deletions(-)

diff --git a/Documentation/vm/page_owner.txt b/Documentation/vm/page_owner.txt
index 8f3ce9b3aa11..ffff1439076a 100644
--- a/Documentation/vm/page_owner.txt
+++ b/Documentation/vm/page_owner.txt
@@ -28,10 +28,11 @@ with page owner and page owner is disabled in runtime due to no enabling
 boot option, runtime overhead is marginal. If disabled in runtime, it
 doesn't require memory to store owner information, so there is no runtime
 memory overhead. And, page owner inserts just two unlikely branches into
-the page allocator hotpath and if it returns false then allocation is
-done like as the kernel without page owner. These two unlikely branches
-would not affect to allocation performance. Following is the kernel's
-code size change due to this facility.
+the page allocator hotpath and if not enabled, then allocation is done
+like as the kernel without page owner. These two unlikely branches should
+not affect to allocation performance, especially if the static keys jump
+label patching functionality is available. Following is the kernel's code
+size change due to this facility.
 
 - Without page owner
    text    data     bss     dec     hex filename
diff --git a/include/linux/page_owner.h b/include/linux/page_owner.h
index cacaabea8a09..8e2eb153c7b9 100644
--- a/include/linux/page_owner.h
+++ b/include/linux/page_owner.h
@@ -1,8 +1,10 @@
 #ifndef __LINUX_PAGE_OWNER_H
 #define __LINUX_PAGE_OWNER_H
 
+#include <linux/jump_label.h>
+
 #ifdef CONFIG_PAGE_OWNER
-extern bool page_owner_inited;
+extern struct static_key_false page_owner_inited;
 extern struct page_ext_operations page_owner_ops;
 
 extern void __reset_page_owner(struct page *page, unsigned int order);
@@ -12,27 +14,23 @@ extern gfp_t __get_page_owner_gfp(struct page *page);
 
 static inline void reset_page_owner(struct page *page, unsigned int order)
 {
-	if (likely(!page_owner_inited))
-		return;
-
-	__reset_page_owner(page, order);
+	if (static_branch_unlikely(&page_owner_inited))
+		__reset_page_owner(page, order);
 }
 
 static inline void set_page_owner(struct page *page,
 			unsigned int order, gfp_t gfp_mask)
 {
-	if (likely(!page_owner_inited))
-		return;
-
-	__set_page_owner(page, order, gfp_mask);
+	if (static_branch_unlikely(&page_owner_inited))
+		__set_page_owner(page, order, gfp_mask);
 }
 
 static inline gfp_t get_page_owner_gfp(struct page *page)
 {
-	if (likely(!page_owner_inited))
+	if (static_branch_unlikely(&page_owner_inited))
+		return __get_page_owner_gfp(page);
+	else
 		return 0;
-
-	return __get_page_owner_gfp(page);
 }
 #else
 static inline void reset_page_owner(struct page *page, unsigned int order)
diff --git a/mm/page_owner.c b/mm/page_owner.c
index 5392195fca61..c8ea1361146e 100644
--- a/mm/page_owner.c
+++ b/mm/page_owner.c
@@ -5,10 +5,11 @@
 #include <linux/bootmem.h>
 #include <linux/stacktrace.h>
 #include <linux/page_owner.h>
+#include <linux/jump_label.h>
 #include "internal.h"
 
 static bool page_owner_disabled = true;
-bool page_owner_inited __read_mostly;
+DEFINE_STATIC_KEY_FALSE(page_owner_inited);
 
 static void init_early_allocated_pages(void);
 
@@ -37,7 +38,7 @@ static void init_page_owner(void)
 	if (page_owner_disabled)
 		return;
 
-	page_owner_inited = true;
+	static_branch_enable(&page_owner_inited);
 	init_early_allocated_pages();
 }
 
@@ -147,7 +148,7 @@ read_page_owner(struct file *file, char __user *buf, size_t count, loff_t *ppos)
 	struct page *page;
 	struct page_ext *page_ext;
 
-	if (!page_owner_inited)
+	if (!static_branch_unlikely(&page_owner_inited))
 		return -EINVAL;
 
 	page = NULL;
@@ -295,7 +296,7 @@ static int __init pageowner_init(void)
 {
 	struct dentry *dentry;
 
-	if (!page_owner_inited) {
+	if (!static_branch_unlikely(&page_owner_inited)) {
 		pr_info("page_owner is disabled\n");
 		return 0;
 	}
diff --git a/mm/vmstat.c b/mm/vmstat.c
index 475d154411f0..649680698afe 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -1120,7 +1120,7 @@ static void pagetypeinfo_showmixedcount(struct seq_file *m, pg_data_t *pgdat)
 #ifdef CONFIG_PAGE_OWNER
 	int mtype;
 
-	if (!page_owner_inited)
+	if (!static_branch_unlikely(&page_owner_inited))
 		return;
 
 	drain_all_pages(NULL);
-- 
2.6.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v3 11/14] mm, page_owner: copy page owner info during migration
  2015-12-18  9:03 [PATCH v3 00/14] mm flags in printk, page_owner improvements for debugging Vlastimil Babka
                   ` (9 preceding siblings ...)
  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:44   ` Michal Hocko
  2015-12-18  9:03 ` [PATCH v3 12/14] mm, page_owner: track and print last migrate reason Vlastimil Babka
                   ` (2 subsequent siblings)
  13 siblings, 1 reply; 25+ messages in thread
From: Vlastimil Babka @ 2015-12-18  9:03 UTC (permalink / raw)
  To: Andrew Morton
  Cc: linux-mm, linux-kernel, Vlastimil Babka, Joonsoo Kim,
	Minchan Kim, Sasha Levin, Kirill A. Shutemov, Mel Gorman,
	Michal Hocko, Hugh Dickins

The page_owner mechanism stores gfp_flags of an allocation and stack trace
that lead to it. During page migration, the original information is
practically replaced by the allocation of free page as the migration target.
Arguably this is less useful and might lead to all the page_owner info for
migratable pages gradually converge towards compaction or numa balancing
migrations. It has also lead to inaccuracies such as one fixed by commit
e2cfc91120fa ("mm/page_owner: set correct gfp_mask on page_owner").

This patch thus introduces copying the page_owner info during migration.
However, since the fact that the page has been migrated from its original
place might be useful for debugging, the next patch will introduce a way to
track that information as well.

Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
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>
Cc: Hugh Dickins <hughd@google.com>
---
 include/linux/page_owner.h | 10 +++++++++-
 mm/migrate.c               |  3 +++
 mm/page_owner.c            | 25 +++++++++++++++++++++++++
 3 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/include/linux/page_owner.h b/include/linux/page_owner.h
index 8e2eb153c7b9..6440daab4ef8 100644
--- a/include/linux/page_owner.h
+++ b/include/linux/page_owner.h
@@ -11,6 +11,7 @@ extern void __reset_page_owner(struct page *page, unsigned int order);
 extern void __set_page_owner(struct page *page,
 			unsigned int order, gfp_t gfp_mask);
 extern gfp_t __get_page_owner_gfp(struct page *page);
+extern void __copy_page_owner(struct page *oldpage, struct page *newpage);
 
 static inline void reset_page_owner(struct page *page, unsigned int order)
 {
@@ -32,6 +33,11 @@ static inline gfp_t get_page_owner_gfp(struct page *page)
 	else
 		return 0;
 }
+static inline void copy_page_owner(struct page *oldpage, struct page *newpage)
+{
+	if (static_branch_unlikely(&page_owner_inited))
+		__copy_page_owner(oldpage, newpage);
+}
 #else
 static inline void reset_page_owner(struct page *page, unsigned int order)
 {
@@ -44,6 +50,8 @@ static inline gfp_t get_page_owner_gfp(struct page *page)
 {
 	return 0;
 }
-
+static inline void copy_page_owner(struct page *oldpage, struct page *newpage)
+{
+}
 #endif /* CONFIG_PAGE_OWNER */
 #endif /* __LINUX_PAGE_OWNER_H */
diff --git a/mm/migrate.c b/mm/migrate.c
index b1034f9c77e7..863a0f1fe23f 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -38,6 +38,7 @@
 #include <linux/balloon_compaction.h>
 #include <linux/mmu_notifier.h>
 #include <linux/page_idle.h>
+#include <linux/page_owner.h>
 
 #include <asm/tlbflush.h>
 
@@ -578,6 +579,8 @@ void migrate_page_copy(struct page *newpage, struct page *page)
 	 */
 	if (PageWriteback(newpage))
 		end_page_writeback(newpage);
+
+	copy_page_owner(page, newpage);
 }
 
 /************************************************************
diff --git a/mm/page_owner.c b/mm/page_owner.c
index c8ea1361146e..a390d2665df2 100644
--- a/mm/page_owner.c
+++ b/mm/page_owner.c
@@ -84,6 +84,31 @@ gfp_t __get_page_owner_gfp(struct page *page)
 	return page_ext->gfp_mask;
 }
 
+void __copy_page_owner(struct page *oldpage, struct page *newpage)
+{
+	struct page_ext *old_ext = lookup_page_ext(oldpage);
+	struct page_ext *new_ext = lookup_page_ext(newpage);
+	int i;
+
+	new_ext->order = old_ext->order;
+	new_ext->gfp_mask = old_ext->gfp_mask;
+	new_ext->nr_entries = old_ext->nr_entries;
+
+	for (i = 0; i < ARRAY_SIZE(new_ext->trace_entries); i++)
+		new_ext->trace_entries[i] = old_ext->trace_entries[i];
+
+	/*
+	 * We don't clear the bit on the oldpage as it's going to be freed
+	 * after migration. Until then, the info can be useful in case of
+	 * a bug, and the overal stats will be off a bit only temporarily.
+	 * Also, migrate_misplaced_transhuge_page() can still fail the
+	 * migration and then we want the oldpage to retain the info. But
+	 * in that case we also don't need to explicitly clear the info from
+	 * the new page, which will be freed.
+	 */
+	__set_bit(PAGE_EXT_OWNER, &new_ext->flags);
+}
+
 static ssize_t
 print_page_owner(char __user *buf, size_t count, unsigned long pfn,
 		struct page *page, struct page_ext *page_ext)
-- 
2.6.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v3 12/14] mm, page_owner: track and print last migrate reason
  2015-12-18  9:03 [PATCH v3 00/14] mm flags in printk, page_owner improvements for debugging Vlastimil Babka
                   ` (10 preceding siblings ...)
  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:54   ` Michal Hocko
  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 ` [PATCH v3 14/14] mm, debug: move bad flags printing to bad_page() Vlastimil Babka
  13 siblings, 1 reply; 25+ messages in thread
From: Vlastimil Babka @ 2015-12-18  9:03 UTC (permalink / raw)
  To: Andrew Morton
  Cc: linux-mm, linux-kernel, Vlastimil Babka, Joonsoo Kim,
	Minchan Kim, Sasha Levin, Kirill A. Shutemov, Mel Gorman,
	Michal Hocko, Hugh Dickins

During migration, page_owner info is now copied with the rest of the page, so
the stacktrace leading to free page allocation during migration is overwritten.
For debugging purposes, it might be however useful to know that the page has
been migrated since its initial allocation. This might happen many times during
the lifetime for different reasons and fully tracking this, especially with
stacktraces would incur extra memory costs. As a compromise, store and print
the migrate_reason of the last migration that occurred to the page. This is
enough to distinguish compaction, numa balancing etc.

Example page_owner entry after the patch:

Page allocated via order 0, mask 0x24213ca(GFP_HIGHUSER_MOVABLE|GFP_COLD|GFP_NOWARN|GFP_NORETRY)
PFN 674308 type Movable Block 1317 type Movable Flags 0x1fffff80010068(uptodate|lru|active|mappedtodisk)
 [<ffffffff81164e9a>] __alloc_pages_nodemask+0x15a/0xa30
 [<ffffffff811ab938>] alloc_pages_current+0x88/0x120
 [<ffffffff8115bc46>] __page_cache_alloc+0xe6/0x120
 [<ffffffff81168b9b>] __do_page_cache_readahead+0xdb/0x200
 [<ffffffff81168df5>] ondemand_readahead+0x135/0x260
 [<ffffffff81168f8c>] page_cache_async_readahead+0x6c/0x70
 [<ffffffff8115d5f8>] generic_file_read_iter+0x378/0x590
 [<ffffffff811d12a7>] __vfs_read+0xa7/0xd0
Page has been migrated, last migrate reason: compaction

Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
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>
Cc: Hugh Dickins <hughd@google.com>
---
 include/linux/migrate.h    |  6 +++++-
 include/linux/page_ext.h   |  1 +
 include/linux/page_owner.h |  9 +++++++++
 mm/debug.c                 | 11 +++++++++++
 mm/migrate.c               | 10 +++++++---
 mm/page_owner.c            | 17 +++++++++++++++++
 6 files changed, 50 insertions(+), 4 deletions(-)

diff --git a/include/linux/migrate.h b/include/linux/migrate.h
index cac1c0904d5f..9b50325e4ddf 100644
--- a/include/linux/migrate.h
+++ b/include/linux/migrate.h
@@ -23,9 +23,13 @@ enum migrate_reason {
 	MR_SYSCALL,		/* also applies to cpusets */
 	MR_MEMPOLICY_MBIND,
 	MR_NUMA_MISPLACED,
-	MR_CMA
+	MR_CMA,
+	MR_TYPES
 };
 
+/* In mm/debug.c; also keep sync with include/trace/events/migrate.h */
+extern char *migrate_reason_names[MR_TYPES];
+
 #ifdef CONFIG_MIGRATION
 
 extern void putback_movable_pages(struct list_head *l);
diff --git a/include/linux/page_ext.h b/include/linux/page_ext.h
index 17f118a82854..e1fe7cf5bddf 100644
--- a/include/linux/page_ext.h
+++ b/include/linux/page_ext.h
@@ -45,6 +45,7 @@ struct page_ext {
 	unsigned int order;
 	gfp_t gfp_mask;
 	unsigned int nr_entries;
+	int last_migrate_reason;
 	unsigned long trace_entries[8];
 #endif
 };
diff --git a/include/linux/page_owner.h b/include/linux/page_owner.h
index 6440daab4ef8..555893bf13d7 100644
--- a/include/linux/page_owner.h
+++ b/include/linux/page_owner.h
@@ -12,6 +12,7 @@ extern void __set_page_owner(struct page *page,
 			unsigned int order, gfp_t gfp_mask);
 extern gfp_t __get_page_owner_gfp(struct page *page);
 extern void __copy_page_owner(struct page *oldpage, struct page *newpage);
+extern void __set_page_owner_migrate_reason(struct page *page, int reason);
 
 static inline void reset_page_owner(struct page *page, unsigned int order)
 {
@@ -38,6 +39,11 @@ static inline void copy_page_owner(struct page *oldpage, struct page *newpage)
 	if (static_branch_unlikely(&page_owner_inited))
 		__copy_page_owner(oldpage, newpage);
 }
+static inline void set_page_owner_migrate_reason(struct page *page, int reason)
+{
+	if (static_branch_unlikely(&page_owner_inited))
+		__set_page_owner_migrate_reason(page, reason);
+}
 #else
 static inline void reset_page_owner(struct page *page, unsigned int order)
 {
@@ -53,5 +59,8 @@ static inline gfp_t get_page_owner_gfp(struct page *page)
 static inline void copy_page_owner(struct page *oldpage, struct page *newpage)
 {
 }
+static inline void set_page_owner_migrate_reason(struct page *page, int reason)
+{
+}
 #endif /* CONFIG_PAGE_OWNER */
 #endif /* __LINUX_PAGE_OWNER_H */
diff --git a/mm/debug.c b/mm/debug.c
index 5ea57bc49ef6..f13778ae84a2 100644
--- a/mm/debug.c
+++ b/mm/debug.c
@@ -10,9 +10,20 @@
 #include <linux/trace_events.h>
 #include <linux/memcontrol.h>
 #include <trace/events/mmflags.h>
+#include <linux/migrate.h>
 
 #include "internal.h"
 
+char *migrate_reason_names[MR_TYPES] = {
+	"compaction",
+	"memory_failure",
+	"memory_hotplug",
+	"syscall_or_cpuset",
+	"mempolicy_mbind",
+	"numa_misplaced",
+	"cma",
+};
+
 const struct trace_print_flags pageflag_names[] = {
 	__def_pageflag_names,
 	{0, NULL}
diff --git a/mm/migrate.c b/mm/migrate.c
index 863a0f1fe23f..1c11b73cd834 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -955,8 +955,10 @@ static ICE_noinline int unmap_and_move(new_page_t get_new_page,
 	}
 
 	rc = __unmap_and_move(page, newpage, force, mode);
-	if (rc == MIGRATEPAGE_SUCCESS)
+	if (rc == MIGRATEPAGE_SUCCESS) {
 		put_new_page = NULL;
+		set_page_owner_migrate_reason(newpage, reason);
+	}
 
 out:
 	if (rc != -EAGAIN) {
@@ -1021,7 +1023,7 @@ static ICE_noinline int unmap_and_move(new_page_t get_new_page,
 static int unmap_and_move_huge_page(new_page_t get_new_page,
 				free_page_t put_new_page, unsigned long private,
 				struct page *hpage, int force,
-				enum migrate_mode mode)
+				enum migrate_mode mode, int reason)
 {
 	int rc = -EAGAIN;
 	int *result = NULL;
@@ -1079,6 +1081,7 @@ static int unmap_and_move_huge_page(new_page_t get_new_page,
 	if (rc == MIGRATEPAGE_SUCCESS) {
 		hugetlb_cgroup_migrate(hpage, new_hpage);
 		put_new_page = NULL;
+		set_page_owner_migrate_reason(new_hpage, reason);
 	}
 
 	unlock_page(hpage);
@@ -1151,7 +1154,7 @@ int migrate_pages(struct list_head *from, new_page_t get_new_page,
 			if (PageHuge(page))
 				rc = unmap_and_move_huge_page(get_new_page,
 						put_new_page, private, page,
-						pass > 2, mode);
+						pass > 2, mode, reason);
 			else
 				rc = unmap_and_move(get_new_page, put_new_page,
 						private, page, pass > 2, mode,
@@ -1842,6 +1845,7 @@ int migrate_misplaced_transhuge_page(struct mm_struct *mm,
 	set_page_memcg(new_page, page_memcg(page));
 	set_page_memcg(page, NULL);
 	page_remove_rmap(page, true);
+	set_page_owner_migrate_reason(new_page, MR_NUMA_MISPLACED);
 
 	spin_unlock(ptl);
 	mmu_notifier_invalidate_range_end(mm, mmun_start, mmun_end);
diff --git a/mm/page_owner.c b/mm/page_owner.c
index a390d2665df2..58ce2816e2c2 100644
--- a/mm/page_owner.c
+++ b/mm/page_owner.c
@@ -6,6 +6,7 @@
 #include <linux/stacktrace.h>
 #include <linux/page_owner.h>
 #include <linux/jump_label.h>
+#include <linux/migrate.h>
 #include "internal.h"
 
 static bool page_owner_disabled = true;
@@ -73,10 +74,18 @@ void __set_page_owner(struct page *page, unsigned int order, gfp_t gfp_mask)
 	page_ext->order = order;
 	page_ext->gfp_mask = gfp_mask;
 	page_ext->nr_entries = trace.nr_entries;
+	page_ext->last_migrate_reason = -1;
 
 	__set_bit(PAGE_EXT_OWNER, &page_ext->flags);
 }
 
+void __set_page_owner_migrate_reason(struct page *page, int reason)
+{
+	struct page_ext *page_ext = lookup_page_ext(page);
+
+	page_ext->last_migrate_reason = reason;
+}
+
 gfp_t __get_page_owner_gfp(struct page *page)
 {
 	struct page_ext *page_ext = lookup_page_ext(page);
@@ -151,6 +160,14 @@ print_page_owner(char __user *buf, size_t count, unsigned long pfn,
 	if (ret >= count)
 		goto err;
 
+	if (page_ext->last_migrate_reason != -1) {
+		ret += snprintf(kbuf + ret, count - ret,
+			"Page has been migrated, last migrate reason: %s\n",
+			migrate_reason_names[page_ext->last_migrate_reason]);
+		if (ret >= count)
+			goto err;
+	}
+
 	ret += snprintf(kbuf + ret, count - ret, "\n");
 	if (ret >= count)
 		goto err;
-- 
2.6.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v3 13/14] mm, page_owner: dump page owner info from dump_page()
  2015-12-18  9:03 [PATCH v3 00/14] mm flags in printk, page_owner improvements for debugging Vlastimil Babka
                   ` (11 preceding siblings ...)
  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
  2015-12-18  9:03 ` [PATCH v3 14/14] mm, debug: move bad flags printing to bad_page() Vlastimil Babka
  13 siblings, 0 replies; 25+ messages in thread
From: Vlastimil Babka @ 2015-12-18  9:03 UTC (permalink / raw)
  To: Andrew Morton
  Cc: linux-mm, linux-kernel, Vlastimil Babka, Joonsoo Kim,
	Minchan Kim, Sasha Levin, Kirill A. Shutemov, Mel Gorman,
	Michal Hocko

The page_owner mechanism is useful for dealing with memory leaks. By reading
/sys/kernel/debug/page_owner one can determine the stack traces leading to
allocations of all pages, and find e.g. a buggy driver.

This information might be also potentially useful for debugging, such as the
VM_BUG_ON_PAGE() calls to dump_page(). So let's print the stored info from
dump_page().

Example output:

page:ffffea0002868a00 count:1 mapcount:0 mapping:ffff8800bba8e958 index:0x63a22c
flags: 0x1fffff80000060(lru|active)
page dumped because: VM_BUG_ON_PAGE(1)
page->mem_cgroup:ffff880138efdc00
page allocated via order 0, migratetype Movable, gfp_mask 0x2420848(GFP_NOFS|GFP_NOFAIL|GFP_HARDWALL|GFP_MOVABLE)
 [<ffffffff81164e8a>] __alloc_pages_nodemask+0x15a/0xa30
 [<ffffffff811ab808>] alloc_pages_current+0x88/0x120
 [<ffffffff8115bc36>] __page_cache_alloc+0xe6/0x120
 [<ffffffff8115c226>] pagecache_get_page+0x56/0x200
 [<ffffffff812058c2>] __getblk_slow+0xd2/0x2b0
 [<ffffffff81205ae0>] __getblk_gfp+0x40/0x50
 [<ffffffffa0283abe>] jbd2_journal_get_descriptor_buffer+0x3e/0x90 [jbd2]
 [<ffffffffa027c793>] jbd2_journal_commit_transaction+0x8e3/0x1870 [jbd2]
page has been migrated, last migrate reason: compaction

Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
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>
Acked-by: Michal Hocko <mhocko@suse.com>
---
 include/linux/page_owner.h |  9 +++++++++
 mm/debug.c                 |  2 ++
 mm/page_alloc.c            |  1 +
 mm/page_owner.c            | 25 +++++++++++++++++++++++++
 4 files changed, 37 insertions(+)

diff --git a/include/linux/page_owner.h b/include/linux/page_owner.h
index 555893bf13d7..46f1b939948c 100644
--- a/include/linux/page_owner.h
+++ b/include/linux/page_owner.h
@@ -13,6 +13,7 @@ extern void __set_page_owner(struct page *page,
 extern gfp_t __get_page_owner_gfp(struct page *page);
 extern void __copy_page_owner(struct page *oldpage, struct page *newpage);
 extern void __set_page_owner_migrate_reason(struct page *page, int reason);
+extern void __dump_page_owner(struct page *page);
 
 static inline void reset_page_owner(struct page *page, unsigned int order)
 {
@@ -44,6 +45,11 @@ static inline void set_page_owner_migrate_reason(struct page *page, int reason)
 	if (static_branch_unlikely(&page_owner_inited))
 		__set_page_owner_migrate_reason(page, reason);
 }
+static inline void dump_page_owner(struct page *page)
+{
+	if (static_branch_unlikely(&page_owner_inited))
+		__dump_page_owner(page);
+}
 #else
 static inline void reset_page_owner(struct page *page, unsigned int order)
 {
@@ -62,5 +68,8 @@ static inline void copy_page_owner(struct page *oldpage, struct page *newpage)
 static inline void set_page_owner_migrate_reason(struct page *page, int reason)
 {
 }
+static inline void dump_page_owner(struct page *page)
+{
+}
 #endif /* CONFIG_PAGE_OWNER */
 #endif /* __LINUX_PAGE_OWNER_H */
diff --git a/mm/debug.c b/mm/debug.c
index f13778ae84a2..7260644d8cc1 100644
--- a/mm/debug.c
+++ b/mm/debug.c
@@ -11,6 +11,7 @@
 #include <linux/memcontrol.h>
 #include <trace/events/mmflags.h>
 #include <linux/migrate.h>
+#include <linux/page_owner.h>
 
 #include "internal.h"
 
@@ -67,6 +68,7 @@ void dump_page_badflags(struct page *page, const char *reason,
 void dump_page(struct page *page, const char *reason)
 {
 	dump_page_badflags(page, reason, 0);
+	dump_page_owner(page);
 }
 EXPORT_SYMBOL(dump_page);
 
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 67538b58e478..7718ee40726a 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -441,6 +441,7 @@ static void bad_page(struct page *page, const char *reason,
 	printk(KERN_ALERT "BUG: Bad page state in process %s  pfn:%05lx\n",
 		current->comm, page_to_pfn(page));
 	dump_page_badflags(page, reason, bad_flags);
+	dump_page_owner(page);
 
 	print_modules();
 	dump_stack();
diff --git a/mm/page_owner.c b/mm/page_owner.c
index 58ce2816e2c2..011377548b4f 100644
--- a/mm/page_owner.c
+++ b/mm/page_owner.c
@@ -183,6 +183,31 @@ print_page_owner(char __user *buf, size_t count, unsigned long pfn,
 	return -ENOMEM;
 }
 
+void __dump_page_owner(struct page *page)
+{
+	struct page_ext *page_ext = lookup_page_ext(page);
+	struct stack_trace trace = {
+		.nr_entries = page_ext->nr_entries,
+		.entries = &page_ext->trace_entries[0],
+	};
+	gfp_t gfp_mask = page_ext->gfp_mask;
+	int mt = gfpflags_to_migratetype(gfp_mask);
+
+	if (!test_bit(PAGE_EXT_OWNER, &page_ext->flags)) {
+		pr_alert("page_owner info is not active (free page?)\n");
+		return;
+	}
+
+	pr_alert("page allocated via order %u, migratetype %s, "
+			"gfp_mask %#x(%pgg)\n", page_ext->order,
+			migratetype_names[mt], gfp_mask, &gfp_mask);
+	print_stack_trace(&trace, 0);
+
+	if (page_ext->last_migrate_reason != -1)
+		pr_alert("page has been migrated, last migrate reason: %s\n",
+			migrate_reason_names[page_ext->last_migrate_reason]);
+}
+
 static ssize_t
 read_page_owner(struct file *file, char __user *buf, size_t count, loff_t *ppos)
 {
-- 
2.6.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v3 14/14] mm, debug: move bad flags printing to bad_page()
  2015-12-18  9:03 [PATCH v3 00/14] mm flags in printk, page_owner improvements for debugging Vlastimil Babka
                   ` (12 preceding siblings ...)
  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
  2016-01-07 13:10   ` Michal Hocko
  13 siblings, 1 reply; 25+ messages in thread
From: Vlastimil Babka @ 2015-12-18  9:03 UTC (permalink / raw)
  To: Andrew Morton
  Cc: linux-mm, linux-kernel, Vlastimil Babka, Joonsoo Kim,
	Minchan Kim, Sasha Levin, Kirill A. Shutemov, Mel Gorman,
	Michal Hocko

Since bad_page() is the only user of the badflags parameter of
dump_page_badflags(), we can move the code to bad_page() and simplify a bit.

The dump_page_badflags() function is renamed to __dump_page() and can still be
called separately from dump_page() for temporary debug prints where page_owner
info is not desired.

The only user-visible change is that page->mem_cgroup is printed before the bad
flags.

Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
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>
---
 include/linux/mmdebug.h |  3 +--
 mm/debug.c              | 10 +++-------
 mm/page_alloc.c         | 10 +++++++---
 3 files changed, 11 insertions(+), 12 deletions(-)

diff --git a/include/linux/mmdebug.h b/include/linux/mmdebug.h
index 2c8286cf162e..9b0dc2161f7a 100644
--- a/include/linux/mmdebug.h
+++ b/include/linux/mmdebug.h
@@ -14,8 +14,7 @@ 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);
+extern void __dump_page(struct page *page, const char *reason);
 void dump_vma(const struct vm_area_struct *vma);
 void dump_mm(const struct mm_struct *mm);
 
diff --git a/mm/debug.c b/mm/debug.c
index 7260644d8cc1..4c03b6d07c82 100644
--- a/mm/debug.c
+++ b/mm/debug.c
@@ -40,8 +40,7 @@ const struct trace_print_flags vmaflag_names[] = {
 	{0, NULL}
 };
 
-void dump_page_badflags(struct page *page, const char *reason,
-		unsigned long badflags)
+void __dump_page(struct page *page, const char *reason)
 {
 	pr_emerg("page:%p count:%d mapcount:%d mapping:%p index:%#lx",
 		  page, atomic_read(&page->_count), page_mapcount(page),
@@ -50,15 +49,12 @@ void dump_page_badflags(struct page *page, const char *reason,
 		pr_cont(" compound_mapcount: %d", compound_mapcount(page));
 	pr_cont("\n");
 	BUILD_BUG_ON(ARRAY_SIZE(pageflag_names) != __NR_PAGEFLAGS + 1);
+
 	pr_emerg("flags: %#lx(%pgp)\n", page->flags, &page->flags);
 
 	if (reason)
 		pr_alert("page dumped because: %s\n", reason);
 
-	badflags &= page->flags;
-	if (badflags)
-		pr_alert("bad because of flags: %#lx(%pgp)\n", badflags,
-								&badflags);
 #ifdef CONFIG_MEMCG
 	if (page->mem_cgroup)
 		pr_alert("page->mem_cgroup:%p\n", page->mem_cgroup);
@@ -67,7 +63,7 @@ void dump_page_badflags(struct page *page, const char *reason,
 
 void dump_page(struct page *page, const char *reason)
 {
-	dump_page_badflags(page, reason, 0);
+	__dump_page(page, reason);
 	dump_page_owner(page);
 }
 EXPORT_SYMBOL(dump_page);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 7718ee40726a..bac8842d4fcf 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -428,7 +428,7 @@ static void bad_page(struct page *page, const char *reason,
 			goto out;
 		}
 		if (nr_unshown) {
-			printk(KERN_ALERT
+			pr_alert(
 			      "BUG: Bad page state: %lu messages suppressed\n",
 				nr_unshown);
 			nr_unshown = 0;
@@ -438,9 +438,13 @@ static void bad_page(struct page *page, const char *reason,
 	if (nr_shown++ == 0)
 		resume = jiffies + 60 * HZ;
 
-	printk(KERN_ALERT "BUG: Bad page state in process %s  pfn:%05lx\n",
+	pr_alert("BUG: Bad page state in process %s  pfn:%05lx\n",
 		current->comm, page_to_pfn(page));
-	dump_page_badflags(page, reason, bad_flags);
+	__dump_page(page, reason);
+	bad_flags &= page->flags;
+	if (bad_flags)
+		pr_alert("bad because of flags: %#lx(%pgp)\n",
+						bad_flags, &bad_flags);
 	dump_page_owner(page);
 
 	print_modules();
-- 
2.6.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH v3 02/14] mm, tracing: make show_gfp_flags() up to date
  2015-12-18  9:03 ` [PATCH v3 02/14] mm, tracing: make show_gfp_flags() up to date Vlastimil Babka
@ 2016-01-07  9:29   ` Michal Hocko
  0 siblings, 0 replies; 25+ messages in thread
From: Michal Hocko @ 2016-01-07  9:29 UTC (permalink / raw)
  To: Vlastimil Babka
  Cc: Andrew Morton, linux-mm, linux-kernel, Steven Rostedt,
	Peter Zijlstra, Arnaldo Carvalho de Melo, Ingo Molnar,
	Rasmus Villemoes, Joonsoo Kim, Minchan Kim, Sasha Levin,
	Kirill A. Shutemov, Mel Gorman

On Fri 18-12-15 10:03:14, Vlastimil Babka wrote:
> The show_gfp_flags() macro provides human-friendly printing of gfp flags in
> tracepoints. However, it is somewhat out of date and missing several flags.
> This patches fills in the missing flags, and distinguishes properly between
> GFP_ATOMIC and __GFP_ATOMIC which were both translated to "GFP_ATOMIC".
> 
> Also add a note in gfp.h so hopefully future changes will be synced better.
> 
> 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>

Reviewed-by: Michal Hocko <mhocko@suse.com>

> ---
>  include/linux/gfp.h             | 5 +++++
>  include/trace/events/gfpflags.h | 9 +++++++--
>  2 files changed, 12 insertions(+), 2 deletions(-)
> 
> diff --git a/include/linux/gfp.h b/include/linux/gfp.h
> index 91f74e741aa2..6ffee7f93af7 100644
> --- a/include/linux/gfp.h
> +++ b/include/linux/gfp.h
> @@ -9,6 +9,11 @@
>  
>  struct vm_area_struct;
>  
> +/*
> + * In case of changes, please don't forget to update
> + * include/trace/events/gfpflags.h
> + */
> +
>  /* Plain integer GFP bitmasks. Do not use this directly. */
>  #define ___GFP_DMA		0x01u
>  #define ___GFP_HIGHMEM		0x02u
> diff --git a/include/trace/events/gfpflags.h b/include/trace/events/gfpflags.h
> index dde6bf092c8a..8395798d97b0 100644
> --- a/include/trace/events/gfpflags.h
> +++ b/include/trace/events/gfpflags.h
> @@ -19,9 +19,13 @@
>  	{(unsigned long)GFP_NOFS,		"GFP_NOFS"},		\
>  	{(unsigned long)GFP_ATOMIC,		"GFP_ATOMIC"},		\
>  	{(unsigned long)GFP_NOIO,		"GFP_NOIO"},		\
> +	{(unsigned long)GFP_NOWAIT,		"GFP_NOWAIT"},		\
> +	{(unsigned long)__GFP_DMA,		"GFP_DMA"},		\
> +	{(unsigned long)__GFP_DMA32,		"GFP_DMA32"},		\
>  	{(unsigned long)__GFP_HIGH,		"GFP_HIGH"},		\
> -	{(unsigned long)__GFP_ATOMIC,		"GFP_ATOMIC"},		\
> +	{(unsigned long)__GFP_ATOMIC,		"__GFP_ATOMIC"},	\
>  	{(unsigned long)__GFP_IO,		"GFP_IO"},		\
> +	{(unsigned long)__GFP_FS,		"GFP_FS"},		\
>  	{(unsigned long)__GFP_COLD,		"GFP_COLD"},		\
>  	{(unsigned long)__GFP_NOWARN,		"GFP_NOWARN"},		\
>  	{(unsigned long)__GFP_REPEAT,		"GFP_REPEAT"},		\
> @@ -36,8 +40,9 @@
>  	{(unsigned long)__GFP_RECLAIMABLE,	"GFP_RECLAIMABLE"},	\
>  	{(unsigned long)__GFP_MOVABLE,		"GFP_MOVABLE"},		\
>  	{(unsigned long)__GFP_NOTRACK,		"GFP_NOTRACK"},		\
> +	{(unsigned long)__GFP_WRITE,		"GFP_WRITE"},		\
>  	{(unsigned long)__GFP_DIRECT_RECLAIM,	"GFP_DIRECT_RECLAIM"},	\
>  	{(unsigned long)__GFP_KSWAPD_RECLAIM,	"GFP_KSWAPD_RECLAIM"},	\
>  	{(unsigned long)__GFP_OTHER_NODE,	"GFP_OTHER_NODE"}	\
> -	) : "GFP_NOWAIT"
> +	) : "none"
>  
> -- 
> 2.6.3

-- 
Michal Hocko
SUSE Labs

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v3 04/14] mm, tracing: unify mm flags handling in tracepoints and printk
  2015-12-18  9:03 ` [PATCH v3 04/14] mm, tracing: unify mm flags handling in tracepoints and printk Vlastimil Babka
@ 2016-01-07  9:46   ` Michal Hocko
  0 siblings, 0 replies; 25+ messages in thread
From: Michal Hocko @ 2016-01-07  9:46 UTC (permalink / raw)
  To: Vlastimil Babka
  Cc: Andrew Morton, linux-mm, linux-kernel, Steven Rostedt,
	Peter Zijlstra, Arnaldo Carvalho de Melo, Ingo Molnar,
	Rasmus Villemoes, Joonsoo Kim, Minchan Kim, Sasha Levin,
	Kirill A. Shutemov, Mel Gorman

On Fri 18-12-15 10:03:16, Vlastimil Babka wrote:
> In tracepoints, it's possible to print gfp flags in a human-friendly format
> through a macro show_gfp_flags(), which defines a translation array and passes
> is to __print_flags(). Since the following patch will introduce support for
> gfp flags printing in printk(), it would be nice to reuse the array. This is
> not straightforward, since __print_flags() can't simply reference an array
> defined in a .c file such as mm/debug.c - it has to be a macro to allow the
> macro magic to communicate the format to userspace tools such as trace-cmd.
> 
> The solution is to create a macro __def_gfpflag_names which is used both in
> show_gfp_flags(), and to define the gfpflag_names[] array in mm/debug.c.
> 
> On the other hand, mm/debug.c also defines translation tables for page
> flags and vma flags, and desire was expressed (but not implemented in this
> series) to use these also from tracepoints. Thus, this patch also renames the
> events/gfpflags.h file to events/mmflags.h and moves the table definitions
> there, using the same macro approach as for gfpflags. This allows translating
> all three kinds of mm-specific flags both in tracepoints and printk.
> 
> 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>

the IF_HAVE_PG_MLOCK trick was a news to me. I wasn't aware of the fact
that #define cannot contain #ifdef code.

Reviewed-by: Michal Hocko <mhocko@suse.com>

> ---
>  include/linux/gfp.h                |   2 +-
>  include/trace/events/btrfs.h       |   2 +-
>  include/trace/events/compaction.h  |   2 +-
>  include/trace/events/gfpflags.h    |  48 -----------
>  include/trace/events/huge_memory.h |   2 -
>  include/trace/events/kmem.h        |   2 +-
>  include/trace/events/mmflags.h     | 161 +++++++++++++++++++++++++++++++++++++
>  include/trace/events/vmscan.h      |   2 +-
>  mm/debug.c                         |  88 +++-----------------
>  tools/perf/builtin-kmem.c          |   2 +-
>  10 files changed, 178 insertions(+), 133 deletions(-)
>  delete mode 100644 include/trace/events/gfpflags.h
>  create mode 100644 include/trace/events/mmflags.h
> 
> diff --git a/include/linux/gfp.h b/include/linux/gfp.h
> index eed323f58547..f6a5e2ba7152 100644
> --- a/include/linux/gfp.h
> +++ b/include/linux/gfp.h
> @@ -11,7 +11,7 @@ struct vm_area_struct;
>  
>  /*
>   * In case of changes, please don't forget to update
> - * include/trace/events/gfpflags.h and tools/perf/builtin-kmem.c
> + * include/trace/events/mmflags.h and tools/perf/builtin-kmem.c
>   */
>  
>  /* Plain integer GFP bitmasks. Do not use this directly. */
> diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h
> index b4473dab39d6..27843f5eccde 100644
> --- a/include/trace/events/btrfs.h
> +++ b/include/trace/events/btrfs.h
> @@ -6,7 +6,7 @@
>  
>  #include <linux/writeback.h>
>  #include <linux/tracepoint.h>
> -#include <trace/events/gfpflags.h>
> +#include <trace/events/mmflags.h>
>  
>  struct btrfs_root;
>  struct btrfs_fs_info;
> diff --git a/include/trace/events/compaction.h b/include/trace/events/compaction.h
> index c92d1e1cbad9..111e5666e5eb 100644
> --- a/include/trace/events/compaction.h
> +++ b/include/trace/events/compaction.h
> @@ -7,7 +7,7 @@
>  #include <linux/types.h>
>  #include <linux/list.h>
>  #include <linux/tracepoint.h>
> -#include <trace/events/gfpflags.h>
> +#include <trace/events/mmflags.h>
>  
>  #define COMPACTION_STATUS					\
>  	EM( COMPACT_DEFERRED,		"deferred")		\
> diff --git a/include/trace/events/gfpflags.h b/include/trace/events/gfpflags.h
> deleted file mode 100644
> index 8395798d97b0..000000000000
> --- a/include/trace/events/gfpflags.h
> +++ /dev/null
> @@ -1,48 +0,0 @@
> -/*
> - * The order of these masks is important. Matching masks will be seen
> - * first and the left over flags will end up showing by themselves.
> - *
> - * For example, if we have GFP_KERNEL before GFP_USER we wil get:
> - *
> - *  GFP_KERNEL|GFP_HARDWALL
> - *
> - * Thus most bits set go first.
> - */
> -#define show_gfp_flags(flags)						\
> -	(flags) ? __print_flags(flags, "|",				\
> -	{(unsigned long)GFP_TRANSHUGE,		"GFP_TRANSHUGE"},	\
> -	{(unsigned long)GFP_HIGHUSER_MOVABLE,	"GFP_HIGHUSER_MOVABLE"}, \
> -	{(unsigned long)GFP_HIGHUSER,		"GFP_HIGHUSER"},	\
> -	{(unsigned long)GFP_USER,		"GFP_USER"},		\
> -	{(unsigned long)GFP_TEMPORARY,		"GFP_TEMPORARY"},	\
> -	{(unsigned long)GFP_KERNEL,		"GFP_KERNEL"},		\
> -	{(unsigned long)GFP_NOFS,		"GFP_NOFS"},		\
> -	{(unsigned long)GFP_ATOMIC,		"GFP_ATOMIC"},		\
> -	{(unsigned long)GFP_NOIO,		"GFP_NOIO"},		\
> -	{(unsigned long)GFP_NOWAIT,		"GFP_NOWAIT"},		\
> -	{(unsigned long)__GFP_DMA,		"GFP_DMA"},		\
> -	{(unsigned long)__GFP_DMA32,		"GFP_DMA32"},		\
> -	{(unsigned long)__GFP_HIGH,		"GFP_HIGH"},		\
> -	{(unsigned long)__GFP_ATOMIC,		"__GFP_ATOMIC"},	\
> -	{(unsigned long)__GFP_IO,		"GFP_IO"},		\
> -	{(unsigned long)__GFP_FS,		"GFP_FS"},		\
> -	{(unsigned long)__GFP_COLD,		"GFP_COLD"},		\
> -	{(unsigned long)__GFP_NOWARN,		"GFP_NOWARN"},		\
> -	{(unsigned long)__GFP_REPEAT,		"GFP_REPEAT"},		\
> -	{(unsigned long)__GFP_NOFAIL,		"GFP_NOFAIL"},		\
> -	{(unsigned long)__GFP_NORETRY,		"GFP_NORETRY"},		\
> -	{(unsigned long)__GFP_COMP,		"GFP_COMP"},		\
> -	{(unsigned long)__GFP_ZERO,		"GFP_ZERO"},		\
> -	{(unsigned long)__GFP_NOMEMALLOC,	"GFP_NOMEMALLOC"},	\
> -	{(unsigned long)__GFP_MEMALLOC,		"GFP_MEMALLOC"},	\
> -	{(unsigned long)__GFP_HARDWALL,		"GFP_HARDWALL"},	\
> -	{(unsigned long)__GFP_THISNODE,		"GFP_THISNODE"},	\
> -	{(unsigned long)__GFP_RECLAIMABLE,	"GFP_RECLAIMABLE"},	\
> -	{(unsigned long)__GFP_MOVABLE,		"GFP_MOVABLE"},		\
> -	{(unsigned long)__GFP_NOTRACK,		"GFP_NOTRACK"},		\
> -	{(unsigned long)__GFP_WRITE,		"GFP_WRITE"},		\
> -	{(unsigned long)__GFP_DIRECT_RECLAIM,	"GFP_DIRECT_RECLAIM"},	\
> -	{(unsigned long)__GFP_KSWAPD_RECLAIM,	"GFP_KSWAPD_RECLAIM"},	\
> -	{(unsigned long)__GFP_OTHER_NODE,	"GFP_OTHER_NODE"}	\
> -	) : "none"
> -
> diff --git a/include/trace/events/huge_memory.h b/include/trace/events/huge_memory.h
> index bfcf4a16aa94..8c62d1cac3b6 100644
> --- a/include/trace/events/huge_memory.h
> +++ b/include/trace/events/huge_memory.h
> @@ -6,8 +6,6 @@
>  
>  #include  <linux/tracepoint.h>
>  
> -#include <trace/events/gfpflags.h>
> -
>  #define SCAN_STATUS							\
>  	EM( SCAN_FAIL,			"failed")			\
>  	EM( SCAN_SUCCEED,		"succeeded")			\
> diff --git a/include/trace/events/kmem.h b/include/trace/events/kmem.h
> index f7554fd7fc62..ca7217389067 100644
> --- a/include/trace/events/kmem.h
> +++ b/include/trace/events/kmem.h
> @@ -6,7 +6,7 @@
>  
>  #include <linux/types.h>
>  #include <linux/tracepoint.h>
> -#include <trace/events/gfpflags.h>
> +#include <trace/events/mmflags.h>
>  
>  DECLARE_EVENT_CLASS(kmem_alloc,
>  
> diff --git a/include/trace/events/mmflags.h b/include/trace/events/mmflags.h
> new file mode 100644
> index 000000000000..1cabf464cd8f
> --- /dev/null
> +++ b/include/trace/events/mmflags.h
> @@ -0,0 +1,161 @@
> +/*
> + * The order of these masks is important. Matching masks will be seen
> + * first and the left over flags will end up showing by themselves.
> + *
> + * For example, if we have GFP_KERNEL before GFP_USER we wil get:
> + *
> + *  GFP_KERNEL|GFP_HARDWALL
> + *
> + * Thus most bits set go first.
> + */
> +
> +#define __def_gfpflag_names						\
> +	{(unsigned long)GFP_TRANSHUGE,		"GFP_TRANSHUGE"},	\
> +	{(unsigned long)GFP_HIGHUSER_MOVABLE,	"GFP_HIGHUSER_MOVABLE"},\
> +	{(unsigned long)GFP_HIGHUSER,		"GFP_HIGHUSER"},	\
> +	{(unsigned long)GFP_USER,		"GFP_USER"},		\
> +	{(unsigned long)GFP_TEMPORARY,		"GFP_TEMPORARY"},	\
> +	{(unsigned long)GFP_KERNEL,		"GFP_KERNEL"},		\
> +	{(unsigned long)GFP_NOFS,		"GFP_NOFS"},		\
> +	{(unsigned long)GFP_ATOMIC,		"GFP_ATOMIC"},		\
> +	{(unsigned long)GFP_NOIO,		"GFP_NOIO"},		\
> +	{(unsigned long)GFP_NOWAIT,		"GFP_NOWAIT"},		\
> +	{(unsigned long)__GFP_DMA,		"GFP_DMA"},		\
> +	{(unsigned long)__GFP_DMA32,		"GFP_DMA32"},		\
> +	{(unsigned long)__GFP_HIGH,		"GFP_HIGH"},		\
> +	{(unsigned long)__GFP_ATOMIC,		"__GFP_ATOMIC"},	\
> +	{(unsigned long)__GFP_IO,		"GFP_IO"},		\
> +	{(unsigned long)__GFP_FS,		"GFP_FS"},		\
> +	{(unsigned long)__GFP_COLD,		"GFP_COLD"},		\
> +	{(unsigned long)__GFP_NOWARN,		"GFP_NOWARN"},		\
> +	{(unsigned long)__GFP_REPEAT,		"GFP_REPEAT"},		\
> +	{(unsigned long)__GFP_NOFAIL,		"GFP_NOFAIL"},		\
> +	{(unsigned long)__GFP_NORETRY,		"GFP_NORETRY"},		\
> +	{(unsigned long)__GFP_COMP,		"GFP_COMP"},		\
> +	{(unsigned long)__GFP_ZERO,		"GFP_ZERO"},		\
> +	{(unsigned long)__GFP_NOMEMALLOC,	"GFP_NOMEMALLOC"},	\
> +	{(unsigned long)__GFP_MEMALLOC,		"GFP_MEMALLOC"},	\
> +	{(unsigned long)__GFP_HARDWALL,		"GFP_HARDWALL"},	\
> +	{(unsigned long)__GFP_THISNODE,		"GFP_THISNODE"},	\
> +	{(unsigned long)__GFP_RECLAIMABLE,	"GFP_RECLAIMABLE"},	\
> +	{(unsigned long)__GFP_MOVABLE,		"GFP_MOVABLE"},		\
> +	{(unsigned long)__GFP_NOTRACK,		"GFP_NOTRACK"},		\
> +	{(unsigned long)__GFP_WRITE,		"GFP_WRITE"},		\
> +	{(unsigned long)__GFP_DIRECT_RECLAIM,	"GFP_DIRECT_RECLAIM"},	\
> +	{(unsigned long)__GFP_KSWAPD_RECLAIM,	"GFP_KSWAPD_RECLAIM"},	\
> +	{(unsigned long)__GFP_OTHER_NODE,	"GFP_OTHER_NODE"}	\
> +
> +#define show_gfp_flags(flags)						\
> +	(flags) ? __print_flags(flags, "|",				\
> +	__def_gfpflag_names						\
> +	) : "none"
> +
> +#ifdef CONFIG_MMU
> +#define IF_HAVE_PG_MLOCK(flag,string) ,{1UL << flag, string}
> +#else
> +#define IF_HAVE_PG_MLOCK(flag,string)
> +#endif
> +
> +#ifdef CONFIG_ARCH_USES_PG_UNCACHED
> +#define IF_HAVE_PG_UNCACHED(flag,string) ,{1UL << flag, string}
> +#else
> +#define IF_HAVE_PG_UNCACHED(flag,string)
> +#endif
> +
> +#ifdef CONFIG_MEMORY_FAILURE
> +#define IF_HAVE_PG_HWPOISON(flag,string) ,{1UL << flag, string}
> +#else
> +#define IF_HAVE_PG_HWPOISON(flag,string)
> +#endif
> +
> +#if defined(CONFIG_IDLE_PAGE_TRACKING) && defined(CONFIG_64BIT)
> +#define IF_HAVE_PG_IDLE(flag,string) ,{1UL << flag, string}
> +#else
> +#define IF_HAVE_PG_IDLE(flag,string)
> +#endif
> +
> +#define __def_pageflag_names						\
> +	{1UL << PG_locked,		"locked"	},		\
> +	{1UL << PG_error,		"error"		},		\
> +	{1UL << PG_referenced,		"referenced"	},		\
> +	{1UL << PG_uptodate,		"uptodate"	},		\
> +	{1UL << PG_dirty,		"dirty"		},		\
> +	{1UL << PG_lru,			"lru"		},		\
> +	{1UL << PG_active,		"active"	},		\
> +	{1UL << PG_slab,		"slab"		},		\
> +	{1UL << PG_owner_priv_1,	"owner_priv_1"	},		\
> +	{1UL << PG_arch_1,		"arch_1"	},		\
> +	{1UL << PG_reserved,		"reserved"	},		\
> +	{1UL << PG_private,		"private"	},		\
> +	{1UL << PG_private_2,		"private_2"	},		\
> +	{1UL << PG_writeback,		"writeback"	},		\
> +	{1UL << PG_head,		"head"		},		\
> +	{1UL << PG_swapcache,		"swapcache"	},		\
> +	{1UL << PG_mappedtodisk,	"mappedtodisk"	},		\
> +	{1UL << PG_reclaim,		"reclaim"	},		\
> +	{1UL << PG_swapbacked,		"swapbacked"	},		\
> +	{1UL << PG_unevictable,		"unevictable"	}		\
> +IF_HAVE_PG_MLOCK(PG_mlocked,		"mlocked"	)		\
> +IF_HAVE_PG_UNCACHED(PG_uncached,	"uncached"	)		\
> +IF_HAVE_PG_HWPOISON(PG_hwpoison,	"hwpoison"	)		\
> +IF_HAVE_PG_IDLE(PG_young,		"young"		)		\
> +IF_HAVE_PG_IDLE(PG_idle,		"idle"		)
> +
> +#define show_page_flags(flags)						\
> +	(flags) ? __print_flags(flags, "|",				\
> +	__def_pageflag_names						\
> +	) : "none"
> +
> +#if defined(CONFIG_X86)
> +#define __VM_ARCH_SPECIFIC {VM_PAT,     "pat"           }
> +#elif defined(CONFIG_PPC)
> +#define __VM_ARCH_SPECIFIC {VM_SAO,     "sao"           }
> +#elif defined(CONFIG_PARISC) || defined(CONFIG_METAG) || defined(CONFIG_IA64)
> +#define __VM_ARCH_SPECIFIC {VM_GROWSUP,	"growsup"	}
> +#elif !defined(CONFIG_MMU)
> +#define __VM_ARCH_SPECIFIC {VM_MAPPED_COPY,"mappedcopy"	}
> +#else
> +#define __VM_ARCH_SPECIFIC {VM_ARCH_1,	"arch_1"	}
> +#endif
> +
> +#ifdef CONFIG_MEM_SOFT_DIRTY
> +#define IF_HAVE_VM_SOFTDIRTY(flag,name) {flag, name },
> +#else
> +#define IF_HAVE_VM_SOFTDIRTY(flag,name)
> +#endif
> +
> +#define __def_vmaflag_names						\
> +	{VM_READ,			"read"		},		\
> +	{VM_WRITE,			"write"		},		\
> +	{VM_EXEC,			"exec"		},		\
> +	{VM_SHARED,			"shared"	},		\
> +	{VM_MAYREAD,			"mayread"	},		\
> +	{VM_MAYWRITE,			"maywrite"	},		\
> +	{VM_MAYEXEC,			"mayexec"	},		\
> +	{VM_MAYSHARE,			"mayshare"	},		\
> +	{VM_GROWSDOWN,			"growsdown"	},		\
> +	{VM_PFNMAP,			"pfnmap"	},		\
> +	{VM_DENYWRITE,			"denywrite"	},		\
> +	{VM_LOCKONFAULT,		"lockonfault"	},		\
> +	{VM_LOCKED,			"locked"	},		\
> +	{VM_IO,				"io"		},		\
> +	{VM_SEQ_READ,			"seqread"	},		\
> +	{VM_RAND_READ,			"randread"	},		\
> +	{VM_DONTCOPY,			"dontcopy"	},		\
> +	{VM_DONTEXPAND,			"dontexpand"	},		\
> +	{VM_ACCOUNT,			"account"	},		\
> +	{VM_NORESERVE,			"noreserve"	},		\
> +	{VM_HUGETLB,			"hugetlb"	},		\
> +	__VM_ARCH_SPECIFIC				,		\
> +	{VM_DONTDUMP,			"dontdump"	},		\
> +IF_HAVE_VM_SOFTDIRTY(VM_SOFTDIRTY,	"softdirty"	)		\
> +	{VM_MIXEDMAP,			"mixedmap"	},		\
> +	{VM_HUGEPAGE,			"hugepage"	},		\
> +	{VM_NOHUGEPAGE,			"nohugepage"	},		\
> +	{VM_MERGEABLE,			"mergeable"	}		\
> +
> +#define show_vma_flags(flags)						\
> +	(flags) ? __print_flags(flags, "|",				\
> +	__def_vmaflag_names						\
> +	) : "none"
> +
> diff --git a/include/trace/events/vmscan.h b/include/trace/events/vmscan.h
> index 31763dd8db1c..0101ef37f1ee 100644
> --- a/include/trace/events/vmscan.h
> +++ b/include/trace/events/vmscan.h
> @@ -8,7 +8,7 @@
>  #include <linux/tracepoint.h>
>  #include <linux/mm.h>
>  #include <linux/memcontrol.h>
> -#include <trace/events/gfpflags.h>
> +#include <trace/events/mmflags.h>
>  
>  #define RECLAIM_WB_ANON		0x0001u
>  #define RECLAIM_WB_FILE		0x0002u
> diff --git a/mm/debug.c b/mm/debug.c
> index 836276586185..85f71e4ce59f 100644
> --- a/mm/debug.c
> +++ b/mm/debug.c
> @@ -9,41 +9,14 @@
>  #include <linux/mm.h>
>  #include <linux/trace_events.h>
>  #include <linux/memcontrol.h>
> +#include <trace/events/mmflags.h>
>  
>  static const struct trace_print_flags pageflag_names[] = {
> -	{1UL << PG_locked,		"locked"	},
> -	{1UL << PG_error,		"error"		},
> -	{1UL << PG_referenced,		"referenced"	},
> -	{1UL << PG_uptodate,		"uptodate"	},
> -	{1UL << PG_dirty,		"dirty"		},
> -	{1UL << PG_lru,			"lru"		},
> -	{1UL << PG_active,		"active"	},
> -	{1UL << PG_slab,		"slab"		},
> -	{1UL << PG_owner_priv_1,	"owner_priv_1"	},
> -	{1UL << PG_arch_1,		"arch_1"	},
> -	{1UL << PG_reserved,		"reserved"	},
> -	{1UL << PG_private,		"private"	},
> -	{1UL << PG_private_2,		"private_2"	},
> -	{1UL << PG_writeback,		"writeback"	},
> -	{1UL << PG_head,		"head"		},
> -	{1UL << PG_swapcache,		"swapcache"	},
> -	{1UL << PG_mappedtodisk,	"mappedtodisk"	},
> -	{1UL << PG_reclaim,		"reclaim"	},
> -	{1UL << PG_swapbacked,		"swapbacked"	},
> -	{1UL << PG_unevictable,		"unevictable"	},
> -#ifdef CONFIG_MMU
> -	{1UL << PG_mlocked,		"mlocked"	},
> -#endif
> -#ifdef CONFIG_ARCH_USES_PG_UNCACHED
> -	{1UL << PG_uncached,		"uncached"	},
> -#endif
> -#ifdef CONFIG_MEMORY_FAILURE
> -	{1UL << PG_hwpoison,		"hwpoison"	},
> -#endif
> -#if defined(CONFIG_IDLE_PAGE_TRACKING) && defined(CONFIG_64BIT)
> -	{1UL << PG_young,		"young"		},
> -	{1UL << PG_idle,		"idle"		},
> -#endif
> +	__def_pageflag_names
> +};
> +
> +static const struct trace_print_flags gfpflag_names[] = {
> +	__def_gfpflag_names
>  };
>  
>  static void dump_flags(unsigned long flags,
> @@ -108,47 +81,8 @@ EXPORT_SYMBOL(dump_page);
>  
>  #ifdef CONFIG_DEBUG_VM
>  
> -static const struct trace_print_flags vmaflags_names[] = {
> -	{VM_READ,			"read"		},
> -	{VM_WRITE,			"write"		},
> -	{VM_EXEC,			"exec"		},
> -	{VM_SHARED,			"shared"	},
> -	{VM_MAYREAD,			"mayread"	},
> -	{VM_MAYWRITE,			"maywrite"	},
> -	{VM_MAYEXEC,			"mayexec"	},
> -	{VM_MAYSHARE,			"mayshare"	},
> -	{VM_GROWSDOWN,			"growsdown"	},
> -	{VM_PFNMAP,			"pfnmap"	},
> -	{VM_DENYWRITE,			"denywrite"	},
> -	{VM_LOCKONFAULT,		"lockonfault"	},
> -	{VM_LOCKED,			"locked"	},
> -	{VM_IO,				"io"		},
> -	{VM_SEQ_READ,			"seqread"	},
> -	{VM_RAND_READ,			"randread"	},
> -	{VM_DONTCOPY,			"dontcopy"	},
> -	{VM_DONTEXPAND,			"dontexpand"	},
> -	{VM_ACCOUNT,			"account"	},
> -	{VM_NORESERVE,			"noreserve"	},
> -	{VM_HUGETLB,			"hugetlb"	},
> -#if defined(CONFIG_X86)
> -	{VM_PAT,			"pat"		},
> -#elif defined(CONFIG_PPC)
> -	{VM_SAO,			"sao"		},
> -#elif defined(CONFIG_PARISC) || defined(CONFIG_METAG) || defined(CONFIG_IA64)
> -	{VM_GROWSUP,			"growsup"	},
> -#elif !defined(CONFIG_MMU)
> -	{VM_MAPPED_COPY,		"mappedcopy"	},
> -#else
> -	{VM_ARCH_1,			"arch_1"	},
> -#endif
> -	{VM_DONTDUMP,			"dontdump"	},
> -#ifdef CONFIG_MEM_SOFT_DIRTY
> -	{VM_SOFTDIRTY,			"softdirty"	},
> -#endif
> -	{VM_MIXEDMAP,			"mixedmap"	},
> -	{VM_HUGEPAGE,			"hugepage"	},
> -	{VM_NOHUGEPAGE,			"nohugepage"	},
> -	{VM_MERGEABLE,			"mergeable"	},
> +static const struct trace_print_flags vmaflag_names[] = {
> +	__def_vmaflag_names
>  };
>  
>  void dump_vma(const struct vm_area_struct *vma)
> @@ -162,7 +96,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, vmaflags_names, ARRAY_SIZE(vmaflags_names));
> +	dump_flags(vma->vm_flags, vmaflag_names, ARRAY_SIZE(vmaflag_names));
>  }
>  EXPORT_SYMBOL(dump_vma);
>  
> @@ -233,8 +167,8 @@ void dump_mm(const struct mm_struct *mm)
>  		""		/* This is here to not have a comma! */
>  		);
>  
> -		dump_flags(mm->def_flags, vmaflags_names,
> -				ARRAY_SIZE(vmaflags_names));
> +		dump_flags(mm->def_flags, vmaflag_names,
> +				ARRAY_SIZE(vmaflag_names));
>  }
>  
>  #endif		/* CONFIG_DEBUG_VM */
> diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
> index acb0d011803a..d99083170315 100644
> --- a/tools/perf/builtin-kmem.c
> +++ b/tools/perf/builtin-kmem.c
> @@ -602,7 +602,7 @@ static int gfpcmp(const void *a, const void *b)
>  	return fa->flags - fb->flags;
>  }
>  
> -/* see include/trace/events/gfpflags.h */
> +/* see include/trace/events/mmflags.h */
>  static const struct {
>  	const char *original;
>  	const char *compact;
> -- 
> 2.6.3

-- 
Michal Hocko
SUSE Labs

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v3 05/14] mm, printk: introduce new format string for flags
  2015-12-18  9:03 ` [PATCH v3 05/14] mm, printk: introduce new format string for flags Vlastimil Babka
@ 2016-01-07  9:53   ` Michal Hocko
  0 siblings, 0 replies; 25+ messages in thread
From: Michal Hocko @ 2016-01-07  9:53 UTC (permalink / raw)
  To: Vlastimil Babka
  Cc: Andrew Morton, linux-mm, linux-kernel, Steven Rostedt,
	Peter Zijlstra, Arnaldo Carvalho de Melo, Ingo Molnar,
	Rasmus Villemoes, Joonsoo Kim, Minchan Kim, Sasha Levin,
	Kirill A. Shutemov, Mel Gorman

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

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v3 06/14] mm, debug: replace dump_flags() with the new printk formats
  2015-12-18  9:03 ` [PATCH v3 06/14] mm, debug: replace dump_flags() with the new printk formats Vlastimil Babka
@ 2016-01-07  9:57   ` Michal Hocko
  0 siblings, 0 replies; 25+ messages in thread
From: Michal Hocko @ 2016-01-07  9:57 UTC (permalink / raw)
  To: Vlastimil Babka
  Cc: Andrew Morton, linux-mm, linux-kernel, Steven Rostedt,
	Peter Zijlstra, Arnaldo Carvalho de Melo, Ingo Molnar,
	Rasmus Villemoes, Joonsoo Kim, Minchan Kim, Sasha Levin,
	Kirill A. Shutemov, Mel Gorman

On Fri 18-12-15 10:03:18, Vlastimil Babka wrote:
> With the new printk format strings for flags, we can get rid of dump_flags()
> in mm/debug.c.
> 
> This also fixes dump_vma() which used dump_flags() for printing vma flags.
> However dump_flags() did a page-flags specific filtering of bits higher than
> NR_PAGEFLAGS in order to remove the zone id part. For dump_vma() this resulted
> in removing several VM_* flags from the symbolic translation.
> 
> 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>

Nice simplification for sure!
Acked-by: Michal Hocko <mhocko@suse.com>

> ---
>  mm/debug.c | 60 ++++++++++++++----------------------------------------------
>  1 file changed, 14 insertions(+), 46 deletions(-)
> 
> diff --git a/mm/debug.c b/mm/debug.c
> index 79621a5ce46f..5ea57bc49ef6 100644
> --- a/mm/debug.c
> +++ b/mm/debug.c
> @@ -28,36 +28,6 @@ const struct trace_print_flags vmaflag_names[] = {
>  	{0, NULL}
>  };
>  
> -static void dump_flags(unsigned long flags,
> -			const struct trace_print_flags *names, int count)
> -{
> -	const char *delim = "";
> -	unsigned long mask;
> -	int i;
> -
> -	pr_emerg("flags: %#lx(", flags);
> -
> -	/* remove zone id */
> -	flags &= (1UL << NR_PAGEFLAGS) - 1;
> -
> -	for (i = 0; i < count && flags; i++) {
> -
> -		mask = names[i].mask;
> -		if ((flags & mask) != mask)
> -			continue;
> -
> -		flags &= ~mask;
> -		pr_cont("%s%s", delim, names[i].name);
> -		delim = "|";
> -	}
> -
> -	/* check for left over flags */
> -	if (flags)
> -		pr_cont("%s%#lx", delim, flags);
> -
> -	pr_cont(")\n");
> -}
> -
>  void dump_page_badflags(struct page *page, const char *reason,
>  		unsigned long badflags)
>  {
> @@ -68,15 +38,15 @@ void dump_page_badflags(struct page *page, const char *reason,
>  		pr_cont(" compound_mapcount: %d", compound_mapcount(page));
>  	pr_cont("\n");
>  	BUILD_BUG_ON(ARRAY_SIZE(pageflag_names) != __NR_PAGEFLAGS + 1);
> -	dump_flags(page->flags, pageflag_names,
> -					ARRAY_SIZE(pageflag_names) - 1);
> +	pr_emerg("flags: %#lx(%pgp)\n", page->flags, &page->flags);
> +
>  	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) - 1);
> -	}
> +
> +	badflags &= page->flags;
> +	if (badflags)
> +		pr_alert("bad because of flags: %#lx(%pgp)\n", badflags,
> +								&badflags);
>  #ifdef CONFIG_MEMCG
>  	if (page->mem_cgroup)
>  		pr_alert("page->mem_cgroup:%p\n", page->mem_cgroup);
> @@ -96,13 +66,14 @@ void dump_vma(const struct vm_area_struct *vma)
>  	pr_emerg("vma %p start %p end %p\n"
>  		"next %p prev %p mm %p\n"
>  		"prot %lx anon_vma %p vm_ops %p\n"
> -		"pgoff %lx file %p private_data %p\n",
> +		"pgoff %lx file %p private_data %p\n"
> +		"flags: %#lx(%pgv)\n",
>  		vma, (void *)vma->vm_start, (void *)vma->vm_end, vma->vm_next,
>  		vma->vm_prev, vma->vm_mm,
>  		(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) - 1);
> +		vma->vm_file, vma->vm_private_data,
> +		vma->vm_flags, &vma->vm_flags);
>  }
>  EXPORT_SYMBOL(dump_vma);
>  
> @@ -136,7 +107,7 @@ void dump_mm(const struct mm_struct *mm)
>  #if defined(CONFIG_NUMA_BALANCING) || defined(CONFIG_COMPACTION)
>  		"tlb_flush_pending %d\n"
>  #endif
> -		"%s",	/* This is here to hold the comma */
> +		"def_flags: %#lx(%pgv)\n",
>  
>  		mm, mm->mmap, mm->vmacache_seqnum, mm->task_size,
>  #ifdef CONFIG_MMU
> @@ -170,11 +141,8 @@ void dump_mm(const struct mm_struct *mm)
>  #if defined(CONFIG_NUMA_BALANCING) || defined(CONFIG_COMPACTION)
>  		mm->tlb_flush_pending,
>  #endif
> -		""		/* This is here to not have a comma! */
> -		);
> -
> -		dump_flags(mm->def_flags, vmaflag_names,
> -				ARRAY_SIZE(vmaflag_names) - 1);
> +		mm->def_flags, &mm->def_flags
> +	);
>  }
>  
>  #endif		/* CONFIG_DEBUG_VM */
> -- 
> 2.6.3

-- 
Michal Hocko
SUSE Labs

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v3 09/14] mm, page_owner: print migratetype of page and pageblock, symbolic flags
  2015-12-18  9:03 ` [PATCH v3 09/14] mm, page_owner: print migratetype of page and pageblock, symbolic flags Vlastimil Babka
@ 2016-01-07 10:06   ` Michal Hocko
  0 siblings, 0 replies; 25+ messages in thread
From: Michal Hocko @ 2016-01-07 10:06 UTC (permalink / raw)
  To: Vlastimil Babka
  Cc: Andrew Morton, linux-mm, linux-kernel, Joonsoo Kim, Minchan Kim,
	Sasha Levin, Kirill A. Shutemov, Mel Gorman

On Fri 18-12-15 10:03:21, Vlastimil Babka wrote:
> The information in /sys/kernel/debug/page_owner includes the migratetype of
> the pageblock the page belongs to. This is also checked against the page's
> migratetype (as declared by gfp_flags during its allocation), and the page is
> reported as Fallback if its migratetype differs from the pageblock's one.
> t
> This is somewhat misleading because in fact fallback allocation is not the only
> reason why these two can differ. It also doesn't direcly provide the page's
> migratetype, although it's possible to derive that from the gfp_flags.
> 
> It's arguably better to print both page and pageblock's migratetype and leave
> the interpretation to the consumer than to suggest fallback allocation as the
> only possible reason. While at it, we can print the migratetypes as string
> the same way as /proc/pagetypeinfo does, as some of the numeric values depend
> on kernel configuration. For that, this patch moves the migratetype_names
> array from #ifdef CONFIG_PROC_FS part of mm/vmstat.c to mm/page_alloc.c and
> exports it.
> 
> With the new format strings for flags, we can now also provide symbolic page
> and gfp flags in the /sys/kernel/debug/page_owner file. This replaces the
> positional printing of page flags as single letters, which might have looked
> nicer, but was limited to a subset of flags, and required the user to remember
> the letters.
> 
> Example page_owner entry after the patch:
> 
> Page allocated via order 0, mask 0x24213ca(GFP_HIGHUSER_MOVABLE|GFP_COLD|GFP_NOWARN|GFP_NORETRY)
> PFN 674308 type Movable Block 1317 type Movable Flags 0x1fffff80010068(uptodate|lru|active|mappedtodisk)
>  [<ffffffff81164e9a>] __alloc_pages_nodemask+0x15a/0xa30
>  [<ffffffff811ab938>] alloc_pages_current+0x88/0x120
>  [<ffffffff8115bc46>] __page_cache_alloc+0xe6/0x120
>  [<ffffffff81168b9b>] __do_page_cache_readahead+0xdb/0x200
>  [<ffffffff81168df5>] ondemand_readahead+0x135/0x260
>  [<ffffffff81168f8c>] page_cache_async_readahead+0x6c/0x70
>  [<ffffffff8115d5f8>] generic_file_read_iter+0x378/0x590
>  [<ffffffff811d12a7>] __vfs_read+0xa7/0xd0
> 
> Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
> 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>

Looks good to me
Acked-by: Michal Hocko <mhocko@suse.com>
> ---
>  include/linux/mmzone.h |  3 +++
>  mm/page_alloc.c        | 13 +++++++++++++
>  mm/page_owner.c        | 24 +++++++-----------------
>  mm/vmstat.c            | 13 -------------
>  4 files changed, 23 insertions(+), 30 deletions(-)
> 
> diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
> index 33bb1b19273e..68cc063bf0b7 100644
> --- a/include/linux/mmzone.h
> +++ b/include/linux/mmzone.h
> @@ -63,6 +63,9 @@ enum {
>  	MIGRATE_TYPES
>  };
>  
> +/* In mm/page_alloc.c; keep in sync also with show_migration_types() there */
> +extern char * const migratetype_names[MIGRATE_TYPES];
> +
>  #ifdef CONFIG_CMA
>  #  define is_migrate_cma(migratetype) unlikely((migratetype) == MIGRATE_CMA)
>  #else
> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> index 08e514721a57..67538b58e478 100644
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
> @@ -222,6 +222,19 @@ static char * const zone_names[MAX_NR_ZONES] = {
>  #endif
>  };
>  
> +char * const migratetype_names[MIGRATE_TYPES] = {
> +	"Unmovable",
> +	"Movable",
> +	"Reclaimable",
> +	"HighAtomic",
> +#ifdef CONFIG_CMA
> +	"CMA",
> +#endif
> +#ifdef CONFIG_MEMORY_ISOLATION
> +	"Isolate",
> +#endif
> +};
> +
>  compound_page_dtor * const compound_page_dtors[] = {
>  	NULL,
>  	free_compound_page,
> diff --git a/mm/page_owner.c b/mm/page_owner.c
> index 983c3a10fa07..5392195fca61 100644
> --- a/mm/page_owner.c
> +++ b/mm/page_owner.c
> @@ -100,8 +100,9 @@ print_page_owner(char __user *buf, size_t count, unsigned long pfn,
>  		return -ENOMEM;
>  
>  	ret = snprintf(kbuf, count,
> -			"Page allocated via order %u, mask 0x%x\n",
> -			page_ext->order, page_ext->gfp_mask);
> +			"Page allocated via order %u, mask %#x(%pgg)\n",
> +			page_ext->order, page_ext->gfp_mask,
> +			&page_ext->gfp_mask);
>  
>  	if (ret >= count)
>  		goto err;
> @@ -110,23 +111,12 @@ print_page_owner(char __user *buf, size_t count, unsigned long pfn,
>  	pageblock_mt = get_pfnblock_migratetype(page, pfn);
>  	page_mt  = gfpflags_to_migratetype(page_ext->gfp_mask);
>  	ret += snprintf(kbuf + ret, count - ret,
> -			"PFN %lu Block %lu type %d %s Flags %s%s%s%s%s%s%s%s%s%s%s%s\n",
> +			"PFN %lu type %s Block %lu type %s Flags %#lx(%pgp)\n",
>  			pfn,
> +			migratetype_names[page_mt],
>  			pfn >> pageblock_order,
> -			pageblock_mt,
> -			pageblock_mt != page_mt ? "Fallback" : "        ",
> -			PageLocked(page)	? "K" : " ",
> -			PageError(page)		? "E" : " ",
> -			PageReferenced(page)	? "R" : " ",
> -			PageUptodate(page)	? "U" : " ",
> -			PageDirty(page)		? "D" : " ",
> -			PageLRU(page)		? "L" : " ",
> -			PageActive(page)	? "A" : " ",
> -			PageSlab(page)		? "S" : " ",
> -			PageWriteback(page)	? "W" : " ",
> -			PageCompound(page)	? "C" : " ",
> -			PageSwapCache(page)	? "B" : " ",
> -			PageMappedToDisk(page)	? "M" : " ");
> +			migratetype_names[pageblock_mt],
> +			page->flags, &page->flags);
>  
>  	if (ret >= count)
>  		goto err;
> diff --git a/mm/vmstat.c b/mm/vmstat.c
> index dfe7315f2db6..475d154411f0 100644
> --- a/mm/vmstat.c
> +++ b/mm/vmstat.c
> @@ -924,19 +924,6 @@ static void walk_zones_in_node(struct seq_file *m, pg_data_t *pgdat,
>  #endif
>  
>  #ifdef CONFIG_PROC_FS
> -static char * const migratetype_names[MIGRATE_TYPES] = {
> -	"Unmovable",
> -	"Movable",
> -	"Reclaimable",
> -	"HighAtomic",
> -#ifdef CONFIG_CMA
> -	"CMA",
> -#endif
> -#ifdef CONFIG_MEMORY_ISOLATION
> -	"Isolate",
> -#endif
> -};
> -
>  static void frag_show_print(struct seq_file *m, pg_data_t *pgdat,
>  						struct zone *zone)
>  {
> -- 
> 2.6.3

-- 
Michal Hocko
SUSE Labs

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v3 10/14] mm, page_owner: convert page_owner_inited to static key
  2015-12-18  9:03 ` [PATCH v3 10/14] mm, page_owner: convert page_owner_inited to static key Vlastimil Babka
@ 2016-01-07 10:21   ` Michal Hocko
  0 siblings, 0 replies; 25+ messages in thread
From: Michal Hocko @ 2016-01-07 10:21 UTC (permalink / raw)
  To: Vlastimil Babka
  Cc: Andrew Morton, linux-mm, linux-kernel, Joonsoo Kim, Minchan Kim,
	Sasha Levin, Kirill A. Shutemov, Mel Gorman

On Fri 18-12-15 10:03:22, Vlastimil Babka wrote:
> CONFIG_PAGE_OWNER attempts to impose negligible runtime overhead when enabled
> during compilation, but not actually enabled during runtime by boot param
> page_owner=on. This overhead can be further reduced using the static key
> mechanism, which this patch does.
> 
> Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
> 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>

Acked-by: Michal Hocko <mhocko@suse.com>

> ---
>  Documentation/vm/page_owner.txt |  9 +++++----
>  include/linux/page_owner.h      | 22 ++++++++++------------
>  mm/page_owner.c                 |  9 +++++----
>  mm/vmstat.c                     |  2 +-
>  4 files changed, 21 insertions(+), 21 deletions(-)
> 
> diff --git a/Documentation/vm/page_owner.txt b/Documentation/vm/page_owner.txt
> index 8f3ce9b3aa11..ffff1439076a 100644
> --- a/Documentation/vm/page_owner.txt
> +++ b/Documentation/vm/page_owner.txt
> @@ -28,10 +28,11 @@ with page owner and page owner is disabled in runtime due to no enabling
>  boot option, runtime overhead is marginal. If disabled in runtime, it
>  doesn't require memory to store owner information, so there is no runtime
>  memory overhead. And, page owner inserts just two unlikely branches into
> -the page allocator hotpath and if it returns false then allocation is
> -done like as the kernel without page owner. These two unlikely branches
> -would not affect to allocation performance. Following is the kernel's
> -code size change due to this facility.
> +the page allocator hotpath and if not enabled, then allocation is done
> +like as the kernel without page owner. These two unlikely branches should
> +not affect to allocation performance, especially if the static keys jump
> +label patching functionality is available. Following is the kernel's code
> +size change due to this facility.
>  
>  - Without page owner
>     text    data     bss     dec     hex filename
> diff --git a/include/linux/page_owner.h b/include/linux/page_owner.h
> index cacaabea8a09..8e2eb153c7b9 100644
> --- a/include/linux/page_owner.h
> +++ b/include/linux/page_owner.h
> @@ -1,8 +1,10 @@
>  #ifndef __LINUX_PAGE_OWNER_H
>  #define __LINUX_PAGE_OWNER_H
>  
> +#include <linux/jump_label.h>
> +
>  #ifdef CONFIG_PAGE_OWNER
> -extern bool page_owner_inited;
> +extern struct static_key_false page_owner_inited;
>  extern struct page_ext_operations page_owner_ops;
>  
>  extern void __reset_page_owner(struct page *page, unsigned int order);
> @@ -12,27 +14,23 @@ extern gfp_t __get_page_owner_gfp(struct page *page);
>  
>  static inline void reset_page_owner(struct page *page, unsigned int order)
>  {
> -	if (likely(!page_owner_inited))
> -		return;
> -
> -	__reset_page_owner(page, order);
> +	if (static_branch_unlikely(&page_owner_inited))
> +		__reset_page_owner(page, order);
>  }
>  
>  static inline void set_page_owner(struct page *page,
>  			unsigned int order, gfp_t gfp_mask)
>  {
> -	if (likely(!page_owner_inited))
> -		return;
> -
> -	__set_page_owner(page, order, gfp_mask);
> +	if (static_branch_unlikely(&page_owner_inited))
> +		__set_page_owner(page, order, gfp_mask);
>  }
>  
>  static inline gfp_t get_page_owner_gfp(struct page *page)
>  {
> -	if (likely(!page_owner_inited))
> +	if (static_branch_unlikely(&page_owner_inited))
> +		return __get_page_owner_gfp(page);
> +	else
>  		return 0;
> -
> -	return __get_page_owner_gfp(page);
>  }
>  #else
>  static inline void reset_page_owner(struct page *page, unsigned int order)
> diff --git a/mm/page_owner.c b/mm/page_owner.c
> index 5392195fca61..c8ea1361146e 100644
> --- a/mm/page_owner.c
> +++ b/mm/page_owner.c
> @@ -5,10 +5,11 @@
>  #include <linux/bootmem.h>
>  #include <linux/stacktrace.h>
>  #include <linux/page_owner.h>
> +#include <linux/jump_label.h>
>  #include "internal.h"
>  
>  static bool page_owner_disabled = true;
> -bool page_owner_inited __read_mostly;
> +DEFINE_STATIC_KEY_FALSE(page_owner_inited);
>  
>  static void init_early_allocated_pages(void);
>  
> @@ -37,7 +38,7 @@ static void init_page_owner(void)
>  	if (page_owner_disabled)
>  		return;
>  
> -	page_owner_inited = true;
> +	static_branch_enable(&page_owner_inited);
>  	init_early_allocated_pages();
>  }
>  
> @@ -147,7 +148,7 @@ read_page_owner(struct file *file, char __user *buf, size_t count, loff_t *ppos)
>  	struct page *page;
>  	struct page_ext *page_ext;
>  
> -	if (!page_owner_inited)
> +	if (!static_branch_unlikely(&page_owner_inited))
>  		return -EINVAL;
>  
>  	page = NULL;
> @@ -295,7 +296,7 @@ static int __init pageowner_init(void)
>  {
>  	struct dentry *dentry;
>  
> -	if (!page_owner_inited) {
> +	if (!static_branch_unlikely(&page_owner_inited)) {
>  		pr_info("page_owner is disabled\n");
>  		return 0;
>  	}
> diff --git a/mm/vmstat.c b/mm/vmstat.c
> index 475d154411f0..649680698afe 100644
> --- a/mm/vmstat.c
> +++ b/mm/vmstat.c
> @@ -1120,7 +1120,7 @@ static void pagetypeinfo_showmixedcount(struct seq_file *m, pg_data_t *pgdat)
>  #ifdef CONFIG_PAGE_OWNER
>  	int mtype;
>  
> -	if (!page_owner_inited)
> +	if (!static_branch_unlikely(&page_owner_inited))
>  		return;
>  
>  	drain_all_pages(NULL);
> -- 
> 2.6.3

-- 
Michal Hocko
SUSE Labs

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v3 11/14] mm, page_owner: copy page owner info during migration
  2015-12-18  9:03 ` [PATCH v3 11/14] mm, page_owner: copy page owner info during migration Vlastimil Babka
@ 2016-01-07 10:44   ` Michal Hocko
  0 siblings, 0 replies; 25+ messages in thread
From: Michal Hocko @ 2016-01-07 10:44 UTC (permalink / raw)
  To: Vlastimil Babka
  Cc: Andrew Morton, linux-mm, linux-kernel, Joonsoo Kim, Minchan Kim,
	Sasha Levin, Kirill A. Shutemov, Mel Gorman, Hugh Dickins

On Fri 18-12-15 10:03:23, Vlastimil Babka wrote:
> The page_owner mechanism stores gfp_flags of an allocation and stack trace
> that lead to it. During page migration, the original information is
> practically replaced by the allocation of free page as the migration target.
> Arguably this is less useful and might lead to all the page_owner info for
> migratable pages gradually converge towards compaction or numa balancing
> migrations. It has also lead to inaccuracies such as one fixed by commit
> e2cfc91120fa ("mm/page_owner: set correct gfp_mask on page_owner").
> 
> This patch thus introduces copying the page_owner info during migration.
> However, since the fact that the page has been migrated from its original
> place might be useful for debugging, the next patch will introduce a way to
> track that information as well.
> 
> Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
> 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>
> Cc: Hugh Dickins <hughd@google.com>

Acked-by: Michal Hocko <mhocko@suse.com>

> ---
>  include/linux/page_owner.h | 10 +++++++++-
>  mm/migrate.c               |  3 +++
>  mm/page_owner.c            | 25 +++++++++++++++++++++++++
>  3 files changed, 37 insertions(+), 1 deletion(-)
> 
> diff --git a/include/linux/page_owner.h b/include/linux/page_owner.h
> index 8e2eb153c7b9..6440daab4ef8 100644
> --- a/include/linux/page_owner.h
> +++ b/include/linux/page_owner.h
> @@ -11,6 +11,7 @@ extern void __reset_page_owner(struct page *page, unsigned int order);
>  extern void __set_page_owner(struct page *page,
>  			unsigned int order, gfp_t gfp_mask);
>  extern gfp_t __get_page_owner_gfp(struct page *page);
> +extern void __copy_page_owner(struct page *oldpage, struct page *newpage);
>  
>  static inline void reset_page_owner(struct page *page, unsigned int order)
>  {
> @@ -32,6 +33,11 @@ static inline gfp_t get_page_owner_gfp(struct page *page)
>  	else
>  		return 0;
>  }
> +static inline void copy_page_owner(struct page *oldpage, struct page *newpage)
> +{
> +	if (static_branch_unlikely(&page_owner_inited))
> +		__copy_page_owner(oldpage, newpage);
> +}
>  #else
>  static inline void reset_page_owner(struct page *page, unsigned int order)
>  {
> @@ -44,6 +50,8 @@ static inline gfp_t get_page_owner_gfp(struct page *page)
>  {
>  	return 0;
>  }
> -
> +static inline void copy_page_owner(struct page *oldpage, struct page *newpage)
> +{
> +}
>  #endif /* CONFIG_PAGE_OWNER */
>  #endif /* __LINUX_PAGE_OWNER_H */
> diff --git a/mm/migrate.c b/mm/migrate.c
> index b1034f9c77e7..863a0f1fe23f 100644
> --- a/mm/migrate.c
> +++ b/mm/migrate.c
> @@ -38,6 +38,7 @@
>  #include <linux/balloon_compaction.h>
>  #include <linux/mmu_notifier.h>
>  #include <linux/page_idle.h>
> +#include <linux/page_owner.h>
>  
>  #include <asm/tlbflush.h>
>  
> @@ -578,6 +579,8 @@ void migrate_page_copy(struct page *newpage, struct page *page)
>  	 */
>  	if (PageWriteback(newpage))
>  		end_page_writeback(newpage);
> +
> +	copy_page_owner(page, newpage);
>  }
>  
>  /************************************************************
> diff --git a/mm/page_owner.c b/mm/page_owner.c
> index c8ea1361146e..a390d2665df2 100644
> --- a/mm/page_owner.c
> +++ b/mm/page_owner.c
> @@ -84,6 +84,31 @@ gfp_t __get_page_owner_gfp(struct page *page)
>  	return page_ext->gfp_mask;
>  }
>  
> +void __copy_page_owner(struct page *oldpage, struct page *newpage)
> +{
> +	struct page_ext *old_ext = lookup_page_ext(oldpage);
> +	struct page_ext *new_ext = lookup_page_ext(newpage);
> +	int i;
> +
> +	new_ext->order = old_ext->order;
> +	new_ext->gfp_mask = old_ext->gfp_mask;
> +	new_ext->nr_entries = old_ext->nr_entries;
> +
> +	for (i = 0; i < ARRAY_SIZE(new_ext->trace_entries); i++)
> +		new_ext->trace_entries[i] = old_ext->trace_entries[i];
> +
> +	/*
> +	 * We don't clear the bit on the oldpage as it's going to be freed
> +	 * after migration. Until then, the info can be useful in case of
> +	 * a bug, and the overal stats will be off a bit only temporarily.
> +	 * Also, migrate_misplaced_transhuge_page() can still fail the
> +	 * migration and then we want the oldpage to retain the info. But
> +	 * in that case we also don't need to explicitly clear the info from
> +	 * the new page, which will be freed.
> +	 */
> +	__set_bit(PAGE_EXT_OWNER, &new_ext->flags);
> +}
> +
>  static ssize_t
>  print_page_owner(char __user *buf, size_t count, unsigned long pfn,
>  		struct page *page, struct page_ext *page_ext)
> -- 
> 2.6.3

-- 
Michal Hocko
SUSE Labs

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v3 12/14] mm, page_owner: track and print last migrate reason
  2015-12-18  9:03 ` [PATCH v3 12/14] mm, page_owner: track and print last migrate reason Vlastimil Babka
@ 2016-01-07 10:54   ` Michal Hocko
  2016-01-07 13:17     ` Vlastimil Babka
  0 siblings, 1 reply; 25+ messages in thread
From: Michal Hocko @ 2016-01-07 10:54 UTC (permalink / raw)
  To: Vlastimil Babka
  Cc: Andrew Morton, linux-mm, linux-kernel, Joonsoo Kim, Minchan Kim,
	Sasha Levin, Kirill A. Shutemov, Mel Gorman, Hugh Dickins

On Fri 18-12-15 10:03:24, Vlastimil Babka wrote:
> During migration, page_owner info is now copied with the rest of the page, so
> the stacktrace leading to free page allocation during migration is overwritten.
> For debugging purposes, it might be however useful to know that the page has
> been migrated since its initial allocation. This might happen many times during
> the lifetime for different reasons and fully tracking this, especially with
> stacktraces would incur extra memory costs. As a compromise, store and print
> the migrate_reason of the last migration that occurred to the page. This is
> enough to distinguish compaction, numa balancing etc.

So you know that the page has been migrated because of compaction the
last time. You do not know anything about the previous migrations
though. How would you use that information during debugging? Wouldn't it
be sufficient to know that the page has been migrated (or count how many
times) instead? That would lead to less code and it might be sufficient
for practical use.

> Example page_owner entry after the patch:
> 
> Page allocated via order 0, mask 0x24213ca(GFP_HIGHUSER_MOVABLE|GFP_COLD|GFP_NOWARN|GFP_NORETRY)
> PFN 674308 type Movable Block 1317 type Movable Flags 0x1fffff80010068(uptodate|lru|active|mappedtodisk)
>  [<ffffffff81164e9a>] __alloc_pages_nodemask+0x15a/0xa30
>  [<ffffffff811ab938>] alloc_pages_current+0x88/0x120
>  [<ffffffff8115bc46>] __page_cache_alloc+0xe6/0x120
>  [<ffffffff81168b9b>] __do_page_cache_readahead+0xdb/0x200
>  [<ffffffff81168df5>] ondemand_readahead+0x135/0x260
>  [<ffffffff81168f8c>] page_cache_async_readahead+0x6c/0x70
>  [<ffffffff8115d5f8>] generic_file_read_iter+0x378/0x590
>  [<ffffffff811d12a7>] __vfs_read+0xa7/0xd0
> Page has been migrated, last migrate reason: compaction
> 
> Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
> 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>
> Cc: Hugh Dickins <hughd@google.com>
> ---
>  include/linux/migrate.h    |  6 +++++-
>  include/linux/page_ext.h   |  1 +
>  include/linux/page_owner.h |  9 +++++++++
>  mm/debug.c                 | 11 +++++++++++
>  mm/migrate.c               | 10 +++++++---
>  mm/page_owner.c            | 17 +++++++++++++++++
>  6 files changed, 50 insertions(+), 4 deletions(-)
[...]
-- 
Michal Hocko
SUSE Labs

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v3 14/14] mm, debug: move bad flags printing to bad_page()
  2015-12-18  9:03 ` [PATCH v3 14/14] mm, debug: move bad flags printing to bad_page() Vlastimil Babka
@ 2016-01-07 13:10   ` Michal Hocko
  0 siblings, 0 replies; 25+ messages in thread
From: Michal Hocko @ 2016-01-07 13:10 UTC (permalink / raw)
  To: Vlastimil Babka
  Cc: Andrew Morton, linux-mm, linux-kernel, Joonsoo Kim, Minchan Kim,
	Sasha Levin, Kirill A. Shutemov, Mel Gorman

On Fri 18-12-15 10:03:26, Vlastimil Babka wrote:
> Since bad_page() is the only user of the badflags parameter of
> dump_page_badflags(), we can move the code to bad_page() and simplify a bit.
> 
> The dump_page_badflags() function is renamed to __dump_page() and can still be
> called separately from dump_page() for temporary debug prints where page_owner
> info is not desired.
> 
> The only user-visible change is that page->mem_cgroup is printed before the bad
> flags.
> 
> Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
> 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>

Acked-by: Michal Hocko <mhocko@suse.com>

> ---
>  include/linux/mmdebug.h |  3 +--
>  mm/debug.c              | 10 +++-------
>  mm/page_alloc.c         | 10 +++++++---
>  3 files changed, 11 insertions(+), 12 deletions(-)
> 
> diff --git a/include/linux/mmdebug.h b/include/linux/mmdebug.h
> index 2c8286cf162e..9b0dc2161f7a 100644
> --- a/include/linux/mmdebug.h
> +++ b/include/linux/mmdebug.h
> @@ -14,8 +14,7 @@ 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);
> +extern void __dump_page(struct page *page, const char *reason);
>  void dump_vma(const struct vm_area_struct *vma);
>  void dump_mm(const struct mm_struct *mm);
>  
> diff --git a/mm/debug.c b/mm/debug.c
> index 7260644d8cc1..4c03b6d07c82 100644
> --- a/mm/debug.c
> +++ b/mm/debug.c
> @@ -40,8 +40,7 @@ const struct trace_print_flags vmaflag_names[] = {
>  	{0, NULL}
>  };
>  
> -void dump_page_badflags(struct page *page, const char *reason,
> -		unsigned long badflags)
> +void __dump_page(struct page *page, const char *reason)
>  {
>  	pr_emerg("page:%p count:%d mapcount:%d mapping:%p index:%#lx",
>  		  page, atomic_read(&page->_count), page_mapcount(page),
> @@ -50,15 +49,12 @@ void dump_page_badflags(struct page *page, const char *reason,
>  		pr_cont(" compound_mapcount: %d", compound_mapcount(page));
>  	pr_cont("\n");
>  	BUILD_BUG_ON(ARRAY_SIZE(pageflag_names) != __NR_PAGEFLAGS + 1);
> +
>  	pr_emerg("flags: %#lx(%pgp)\n", page->flags, &page->flags);
>  
>  	if (reason)
>  		pr_alert("page dumped because: %s\n", reason);
>  
> -	badflags &= page->flags;
> -	if (badflags)
> -		pr_alert("bad because of flags: %#lx(%pgp)\n", badflags,
> -								&badflags);
>  #ifdef CONFIG_MEMCG
>  	if (page->mem_cgroup)
>  		pr_alert("page->mem_cgroup:%p\n", page->mem_cgroup);
> @@ -67,7 +63,7 @@ void dump_page_badflags(struct page *page, const char *reason,
>  
>  void dump_page(struct page *page, const char *reason)
>  {
> -	dump_page_badflags(page, reason, 0);
> +	__dump_page(page, reason);
>  	dump_page_owner(page);
>  }
>  EXPORT_SYMBOL(dump_page);
> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> index 7718ee40726a..bac8842d4fcf 100644
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
> @@ -428,7 +428,7 @@ static void bad_page(struct page *page, const char *reason,
>  			goto out;
>  		}
>  		if (nr_unshown) {
> -			printk(KERN_ALERT
> +			pr_alert(
>  			      "BUG: Bad page state: %lu messages suppressed\n",
>  				nr_unshown);
>  			nr_unshown = 0;
> @@ -438,9 +438,13 @@ static void bad_page(struct page *page, const char *reason,
>  	if (nr_shown++ == 0)
>  		resume = jiffies + 60 * HZ;
>  
> -	printk(KERN_ALERT "BUG: Bad page state in process %s  pfn:%05lx\n",
> +	pr_alert("BUG: Bad page state in process %s  pfn:%05lx\n",
>  		current->comm, page_to_pfn(page));
> -	dump_page_badflags(page, reason, bad_flags);
> +	__dump_page(page, reason);
> +	bad_flags &= page->flags;
> +	if (bad_flags)
> +		pr_alert("bad because of flags: %#lx(%pgp)\n",
> +						bad_flags, &bad_flags);
>  	dump_page_owner(page);
>  
>  	print_modules();
> -- 
> 2.6.3

-- 
Michal Hocko
SUSE Labs

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v3 12/14] mm, page_owner: track and print last migrate reason
  2016-01-07 10:54   ` Michal Hocko
@ 2016-01-07 13:17     ` Vlastimil Babka
  0 siblings, 0 replies; 25+ messages in thread
From: Vlastimil Babka @ 2016-01-07 13:17 UTC (permalink / raw)
  To: Michal Hocko
  Cc: Andrew Morton, linux-mm, linux-kernel, Joonsoo Kim, Minchan Kim,
	Sasha Levin, Kirill A. Shutemov, Mel Gorman, Hugh Dickins

On 01/07/2016 11:54 AM, Michal Hocko wrote:
> On Fri 18-12-15 10:03:24, Vlastimil Babka wrote:
>> During migration, page_owner info is now copied with the rest of the page, so
>> the stacktrace leading to free page allocation during migration is overwritten.
>> For debugging purposes, it might be however useful to know that the page has
>> been migrated since its initial allocation. This might happen many times during
>> the lifetime for different reasons and fully tracking this, especially with
>> stacktraces would incur extra memory costs. As a compromise, store and print
>> the migrate_reason of the last migration that occurred to the page. This is
>> enough to distinguish compaction, numa balancing etc.
>
> So you know that the page has been migrated because of compaction the
> last time. You do not know anything about the previous migrations
> though. How would you use that information during debugging? Wouldn't it

The assumption is that if a migration does something bad, chances are it 
will manifest before another migration happens. I.e. the last migration 
is probably more related to the bug (e.g. catched by VM_BUG_ON_PAGE()) 
than the previous ones. Statistically if trinity sees more errors 
implying compaction than numa balancing, we should look for bugs in 
compaction, etc.

> be sufficient to know that the page has been migrated (or count how many
> times) instead? That would lead to less code and it might be sufficient
> for practical use.

Yeah it's hard to predict how useful/sufficient this patch would be. The 
fact that migration happened should be definitely noted. How many times 
is not that useful IMHO. Migrate reason seemed appropriate and useful 
enough and we already distinguish them for tracepoints.


^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2016-01-07 13:17 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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 ` [PATCH v3 01/14] tracepoints: move trace_print_flags definitions to tracepoint-defs.h Vlastimil Babka
2015-12-18  9:03 ` [PATCH v3 02/14] mm, tracing: make show_gfp_flags() up to date Vlastimil Babka
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 ` [PATCH v3 04/14] mm, tracing: unify mm flags handling in tracepoints and printk Vlastimil Babka
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
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
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 ` [PATCH v3 08/14] mm, oom: print symbolic gfp_flags in oom warning Vlastimil Babka
2015-12-18  9:03 ` [PATCH v3 09/14] mm, page_owner: print migratetype of page and pageblock, symbolic flags Vlastimil Babka
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
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
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
2016-01-07 10:54   ` Michal Hocko
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 ` [PATCH v3 14/14] mm, debug: move bad flags printing to bad_page() Vlastimil Babka
2016-01-07 13:10   ` Michal Hocko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).