* [PATCH 1/2] mm, printk: introduce new format string for flags
@ 2015-11-30 16:10 ` Vlastimil Babka
0 siblings, 0 replies; 115+ messages in thread
From: Vlastimil Babka @ 2015-11-30 16:10 UTC (permalink / raw)
To: linux-mm
Cc: linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko,
Vlastimil Babka, Rasmus Villemoes
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.
Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk>
---
I'm sending it on top of the page_owner series, as it's already in mmotm.
But to reduce churn (in case this approach is accepted), I can later
incorporate it and resend it whole.
Documentation/printk-formats.txt | 14 ++++
include/linux/mmdebug.h | 5 +-
lib/vsprintf.c | 31 ++++++++
mm/debug.c | 150 ++++++++++++++++++++++-----------------
mm/oom_kill.c | 5 +-
mm/page_alloc.c | 5 +-
mm/page_owner.c | 5 +-
7 files changed, 140 insertions(+), 75 deletions(-)
diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt
index b784c270105f..4b5156e74b09 100644
--- a/Documentation/printk-formats.txt
+++ b/Documentation/printk-formats.txt
@@ -292,6 +292,20 @@ Raw pointer value SHOULD be printed with %p. The kernel supports
Passed by reference.
+Flags bitfields such as page flags, gfp_flags:
+
+ %pgp 0x1fffff8000086c(referenced|uptodate|lru|active|private)
+ %pgg 0x24202c4(GFP_USER|GFP_DMA32|GFP_NOWARN)
+ %pgv 0x875(read|exec|mayread|maywrite|mayexec|denywrite)
+
+ For printing raw values of flags bitfields together with symbolic
+ strings that would construct the value. The type of flags is given by
+ the third character. Currently supported are [p]age flags, [g]fp_flags
+ and [v]ma_flags. The flag names and print order depends on the
+ particular type.
+
+ Passed by reference.
+
Network device features:
%pNF 0x000000000000c000
diff --git a/include/linux/mmdebug.h b/include/linux/mmdebug.h
index 3b77fab7ad28..e6518df259ca 100644
--- a/include/linux/mmdebug.h
+++ b/include/linux/mmdebug.h
@@ -2,6 +2,7 @@
#define LINUX_MM_DEBUG_H 1
#include <linux/stringify.h>
+#include <linux/types.h>
struct page;
struct vm_area_struct;
@@ -10,7 +11,9 @@ struct mm_struct;
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_gfpflag_names(unsigned long gfp_flags);
+extern char *format_page_flags(unsigned long flags, char *buf, char *end);
+extern char *format_vma_flags(unsigned long flags, char *buf, char *end);
+extern char *format_gfp_flags(gfp_t gfp_flags, char *buf, char*end);
void dump_vma(const struct vm_area_struct *vma);
void dump_mm(const struct mm_struct *mm);
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index f9cee8e1233c..41cd122bd307 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -31,6 +31,7 @@
#include <linux/dcache.h>
#include <linux/cred.h>
#include <net/addrconf.h>
+#include <linux/mmdebug.h>
#include <asm/page.h> /* for PAGE_SIZE */
#include <asm/sections.h> /* for dereference_function_descriptor() */
@@ -1361,6 +1362,29 @@ char *clock(char *buf, char *end, struct clk *clk, struct printf_spec spec,
}
}
+static noinline_for_stack
+char *flags_string(char *buf, char *end, void *flags_ptr,
+ struct printf_spec spec, const char *fmt)
+{
+ unsigned long flags;
+ gfp_t gfp_flags;
+
+ switch (fmt[1]) {
+ case 'p':
+ flags = *(unsigned long *)flags_ptr;
+ return format_page_flags(flags, buf, end);
+ case 'v':
+ flags = *(unsigned long *)flags_ptr;
+ return format_vma_flags(flags, buf, end);
+ case 'g':
+ gfp_flags = *(gfp_t *)flags_ptr;
+ return format_gfp_flags(gfp_flags, buf, end);
+ default:
+ WARN_ONCE(1, "Unsupported flags modifier: %c\n", fmt[1]);
+ return 0;
+ }
+}
+
int kptr_restrict __read_mostly;
/*
@@ -1448,6 +1472,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 **
*
@@ -1600,6 +1629,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, spec, fmt);
}
spec.flags |= SMALL;
if (spec.field_width == -1) {
diff --git a/mm/debug.c b/mm/debug.c
index 2fdf0999e6f9..a092111920e7 100644
--- a/mm/debug.c
+++ b/mm/debug.c
@@ -59,40 +59,109 @@ static const struct trace_print_flags pageflag_names[] = {
#endif
};
+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 gfpflag_names[] = {
__def_gfpflag_names
};
-static void dump_flag_names(unsigned long flags,
- const struct trace_print_flags *names, int count)
+static char *format_flag_names(unsigned long flags, unsigned long mask_out,
+ const struct trace_print_flags *names, int count,
+ char *buf, char *end)
{
const char *delim = "";
unsigned long mask;
int i;
- pr_cont("(");
+ buf += snprintf(buf, end - buf, "%#lx(", flags);
+
+ flags &= ~mask_out;
for (i = 0; i < count && flags; i++) {
+ if (buf >= end)
+ break;
mask = names[i].mask;
if ((flags & mask) != mask)
continue;
flags &= ~mask;
- pr_cont("%s%s", delim, names[i].name);
+ buf += snprintf(buf, end - buf, "%s%s", delim, names[i].name);
delim = "|";
}
/* check for left over flags */
- if (flags)
- pr_cont("%s%#lx", delim, flags);
+ if (flags && (buf < end))
+ buf += snprintf(buf, end - buf, "%s%#lx", delim, flags);
+
+ if (buf < end) {
+ *buf = ')';
+ buf++;
+ }
- pr_cont(")\n");
+ return buf;
}
-void dump_gfpflag_names(unsigned long gfp_flags)
+char *format_page_flags(unsigned long flags, char *buf, char *end)
{
- dump_flag_names(gfp_flags, gfpflag_names, ARRAY_SIZE(gfpflag_names));
+ /* remove zone id */
+ unsigned long mask = (1UL << NR_PAGEFLAGS) - 1;
+
+ return format_flag_names(flags, ~mask, pageflag_names,
+ ARRAY_SIZE(pageflag_names), buf, end);
+}
+
+char *format_vma_flags(unsigned long flags, char *buf, char *end)
+{
+ return format_flag_names(flags, 0, vmaflags_names,
+ ARRAY_SIZE(vmaflags_names), buf, end);
+}
+
+char *format_gfp_flags(gfp_t gfp_flags, char *buf, char *end)
+{
+ return format_flag_names(gfp_flags, 0, gfpflag_names,
+ ARRAY_SIZE(gfpflag_names), buf, end);
}
void dump_page_badflags(struct page *page, const char *reason,
@@ -108,18 +177,15 @@ void dump_page_badflags(struct page *page, const char *reason,
pr_cont("\n");
BUILD_BUG_ON(ARRAY_SIZE(pageflag_names) != __NR_PAGEFLAGS);
- pr_emerg("flags: %#lx", printflags);
+ pr_emerg("flags: %pgp\n", &printflags);
/* remove zone id */
printflags &= (1UL << NR_PAGEFLAGS) - 1;
- dump_flag_names(printflags, pageflag_names, ARRAY_SIZE(pageflag_names));
if (reason)
pr_alert("page dumped because: %s\n", reason);
if (page->flags & badflags) {
printflags = page->flags & badflags;
- pr_alert("bad because of flags: %#lx:", printflags);
- dump_flag_names(printflags, pageflag_names,
- ARRAY_SIZE(pageflag_names));
+ pr_alert("bad because of flags: %pgp\n", &printflags);
}
#ifdef CONFIG_MEMCG
if (page->mem_cgroup)
@@ -136,63 +202,19 @@ 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" },
-};
-
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: %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);
- pr_emerg("flags: %#lx", vma->vm_flags);
- dump_flag_names(vma->vm_flags, vmaflags_names,
- ARRAY_SIZE(vmaflags_names));
+ vma->vm_file, vma->vm_private_data,
+ &vma->vm_flags);
}
EXPORT_SYMBOL(dump_vma);
@@ -263,9 +285,7 @@ void dump_mm(const struct mm_struct *mm)
"" /* This is here to not have a comma! */
);
- pr_emerg("def_flags: %#lx", mm->def_flags);
- dump_flag_names(mm->def_flags, vmaflags_names,
- ARRAY_SIZE(vmaflags_names));
+ pr_emerg("def_flags: %pgv\n", &mm->def_flags);
}
#endif /* CONFIG_DEBUG_VM */
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 542d56c93209..63a68b62ee68 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -387,10 +387,9 @@ static void dump_header(struct oom_control *oc, struct task_struct *p,
struct mem_cgroup *memcg)
{
pr_warning("%s invoked oom-killer: order=%d, oom_score_adj=%hd, "
- "gfp_mask=0x%x",
+ "gfp_mask=%pgg\n",
current->comm, oc->order, current->signal->oom_score_adj,
- oc->gfp_mask);
- dump_gfpflag_names(oc->gfp_mask);
+ &oc->gfp_mask);
cpuset_print_current_mems_allowed();
dump_stack();
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 80349acd8c17..77d2c75f80e4 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -2711,9 +2711,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",
- current->comm, order, gfp_mask);
- dump_gfpflag_names(gfp_mask);
+ pr_warn("%s: page allocation failure: order:%u, mode:%pgg\n",
+ current->comm, order, &gfp_mask);
dump_stack();
if (!should_suppress_show_mem())
show_mem(filter);
diff --git a/mm/page_owner.c b/mm/page_owner.c
index f4acd2452c35..ff862b6d12da 100644
--- a/mm/page_owner.c
+++ b/mm/page_owner.c
@@ -208,9 +208,8 @@ void __dump_page_owner(struct page *page)
return;
}
- pr_alert("page allocated via order %u, migratetype %s, gfp_mask 0x%x",
- page_ext->order, migratetype_names[mt], gfp_mask);
- dump_gfpflag_names(gfp_mask);
+ pr_alert("page allocated via order %u, migratetype %s, gfp_mask %pgg\n",
+ page_ext->order, migratetype_names[mt], &gfp_mask);
print_stack_trace(&trace, 0);
if (page_ext->last_migrate_reason != -1)
--
2.6.3
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH 2/2] mm, page_owner: provide symbolic page flags and gfp_flags
2015-11-30 16:10 ` Vlastimil Babka
@ 2015-11-30 16:10 ` Vlastimil Babka
-1 siblings, 0 replies; 115+ messages in thread
From: Vlastimil Babka @ 2015-11-30 16:10 UTC (permalink / raw)
To: linux-mm
Cc: linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko,
Vlastimil Babka, Rasmus Villemoes
With the new format strings for flags, we can now 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 of the adjusted format:
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>
---
mm/page_owner.c | 19 ++++---------------
1 file changed, 4 insertions(+), 15 deletions(-)
diff --git a/mm/page_owner.c b/mm/page_owner.c
index ff862b6d12da..421765a53c68 100644
--- a/mm/page_owner.c
+++ b/mm/page_owner.c
@@ -135,8 +135,8 @@ 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 %pgg\n",
+ page_ext->order, &page_ext->gfp_mask);
if (ret >= count)
goto err;
@@ -145,23 +145,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 type %s Block %lu type %s Flags %s%s%s%s%s%s%s%s%s%s%s%s\n",
+ "PFN %lu type %s Block %lu type %s Flags %pgp\n",
pfn,
migratetype_names[page_mt],
pfn >> pageblock_order,
migratetype_names[pageblock_mt],
- 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" : " ");
+ &page->flags);
if (ret >= count)
goto err;
--
2.6.3
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH 2/2] mm, page_owner: provide symbolic page flags and gfp_flags
@ 2015-11-30 16:10 ` Vlastimil Babka
0 siblings, 0 replies; 115+ messages in thread
From: Vlastimil Babka @ 2015-11-30 16:10 UTC (permalink / raw)
To: linux-mm
Cc: linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko,
Vlastimil Babka, Rasmus Villemoes
With the new format strings for flags, we can now 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 of the adjusted format:
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>
---
mm/page_owner.c | 19 ++++---------------
1 file changed, 4 insertions(+), 15 deletions(-)
diff --git a/mm/page_owner.c b/mm/page_owner.c
index ff862b6d12da..421765a53c68 100644
--- a/mm/page_owner.c
+++ b/mm/page_owner.c
@@ -135,8 +135,8 @@ 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 %pgg\n",
+ page_ext->order, &page_ext->gfp_mask);
if (ret >= count)
goto err;
@@ -145,23 +145,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 type %s Block %lu type %s Flags %s%s%s%s%s%s%s%s%s%s%s%s\n",
+ "PFN %lu type %s Block %lu type %s Flags %pgp\n",
pfn,
migratetype_names[page_mt],
pfn >> pageblock_order,
migratetype_names[pageblock_mt],
- 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" : " ");
+ &page->flags);
if (ret >= count)
goto err;
--
2.6.3
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related [flat|nested] 115+ messages in thread
* Re: [PATCH 1/2] mm, printk: introduce new format string for flags
2015-11-30 16:10 ` Vlastimil Babka
@ 2015-12-02 11:01 ` Rasmus Villemoes
-1 siblings, 0 replies; 115+ messages in thread
From: Rasmus Villemoes @ 2015-12-02 11:01 UTC (permalink / raw)
To: Vlastimil Babka
Cc: linux-mm, linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko
On Mon, Nov 30 2015, Vlastimil Babka <vbabka@suse.cz> 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.
>
> Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
> Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk>
> ---
> I'm sending it on top of the page_owner series, as it's already in mmotm.
> But to reduce churn (in case this approach is accepted), I can later
> incorporate it and resend it whole.
>
> Documentation/printk-formats.txt | 14 ++++
> include/linux/mmdebug.h | 5 +-
> lib/vsprintf.c | 31 ++++++++
> mm/debug.c | 150 ++++++++++++++++++++++-----------------
> mm/oom_kill.c | 5 +-
> mm/page_alloc.c | 5 +-
> mm/page_owner.c | 5 +-
> 7 files changed, 140 insertions(+), 75 deletions(-)
I'd prefer to have the formatting code in vsprintf.c, so that we'd avoid
having to call vsnprintf recursively (and repeatedly - not that this is
going to be used in hot paths, but if the box is going down it might be
nice to get the debug info out a few thousand cycles earlier). That'll
also make it easier to avoid the bugs below.
> diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt
> index b784c270105f..4b5156e74b09 100644
> --- a/Documentation/printk-formats.txt
> +++ b/Documentation/printk-formats.txt
> @@ -292,6 +292,20 @@ Raw pointer value SHOULD be printed with %p. The kernel supports
>
> Passed by reference.
>
> +Flags bitfields such as page flags, gfp_flags:
> +
> + %pgp 0x1fffff8000086c(referenced|uptodate|lru|active|private)
> + %pgg 0x24202c4(GFP_USER|GFP_DMA32|GFP_NOWARN)
> + %pgv 0x875(read|exec|mayread|maywrite|mayexec|denywrite)
> +
I think it would be better (and more flexible) if %pg* only stood for
printing the | chain of strings. Let people pass the flags twice if they
also want the numeric value; then they're also able to choose 0-padding
and whatnot, can use other kinds of parentheses, etc., etc. So
pr_emerg("flags: 0x%08lu [%pgp]\n", printflags, &printflags)
> + For printing raw values of flags bitfields together with symbolic
> + strings that would construct the value. The type of flags is given by
> + the third character. Currently supported are [p]age flags, [g]fp_flags
> + and [v]ma_flags. The flag names and print order depends on the
> + particular type.
> +
> + Passed by reference.
> +
> Network device features:
>
> %pNF 0x000000000000c000
> diff --git a/include/linux/mmdebug.h b/include/linux/mmdebug.h
> index 3b77fab7ad28..e6518df259ca 100644
> --- a/include/linux/mmdebug.h
> +++ b/include/linux/mmdebug.h
> @@ -2,6 +2,7 @@
> #define LINUX_MM_DEBUG_H 1
>
> #include <linux/stringify.h>
> +#include <linux/types.h>
>
> struct page;
> struct vm_area_struct;
> @@ -10,7 +11,9 @@ struct mm_struct;
> 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_gfpflag_names(unsigned long gfp_flags);
> +extern char *format_page_flags(unsigned long flags, char *buf, char *end);
> +extern char *format_vma_flags(unsigned long flags, char *buf, char *end);
> +extern char *format_gfp_flags(gfp_t gfp_flags, char *buf, char*end);
> void dump_vma(const struct vm_area_struct *vma);
> void dump_mm(const struct mm_struct *mm);
>
> diff --git a/lib/vsprintf.c b/lib/vsprintf.c
> index f9cee8e1233c..41cd122bd307 100644
> --- a/lib/vsprintf.c
> +++ b/lib/vsprintf.c
> @@ -31,6 +31,7 @@
> #include <linux/dcache.h>
> #include <linux/cred.h>
> #include <net/addrconf.h>
> +#include <linux/mmdebug.h>
>
> #include <asm/page.h> /* for PAGE_SIZE */
> #include <asm/sections.h> /* for dereference_function_descriptor() */
> @@ -1361,6 +1362,29 @@ char *clock(char *buf, char *end, struct clk *clk, struct printf_spec spec,
> }
> }
>
> +static noinline_for_stack
> +char *flags_string(char *buf, char *end, void *flags_ptr,
> + struct printf_spec spec, const char *fmt)
> +{
> + unsigned long flags;
> + gfp_t gfp_flags;
> +
> + switch (fmt[1]) {
> + case 'p':
> + flags = *(unsigned long *)flags_ptr;
> + return format_page_flags(flags, buf, end);
> + case 'v':
> + flags = *(unsigned long *)flags_ptr;
> + return format_vma_flags(flags, buf, end);
> + case 'g':
> + gfp_flags = *(gfp_t *)flags_ptr;
> + return format_gfp_flags(gfp_flags, buf, end);
> + default:
> + WARN_ONCE(1, "Unsupported flags modifier: %c\n", fmt[1]);
> + return 0;
> + }
> +}
> +
That return 0 aka return NULL will lead to an oops when the next thing
is printed. Did you mean 'return buf;'?
> int kptr_restrict __read_mostly;
>
> /*
> @@ -1448,6 +1472,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 **
> *
> @@ -1600,6 +1629,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, spec, fmt);
> }
> spec.flags |= SMALL;
> if (spec.field_width == -1) {
> diff --git a/mm/debug.c b/mm/debug.c
> index 2fdf0999e6f9..a092111920e7 100644
> --- a/mm/debug.c
> +++ b/mm/debug.c
> @@ -59,40 +59,109 @@ static const struct trace_print_flags pageflag_names[] = {
> #endif
> };
>
> +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 gfpflag_names[] = {
> __def_gfpflag_names
> };
>
> -static void dump_flag_names(unsigned long flags,
> - const struct trace_print_flags *names, int count)
> +static char *format_flag_names(unsigned long flags, unsigned long mask_out,
> + const struct trace_print_flags *names, int count,
> + char *buf, char *end)
> {
> const char *delim = "";
> unsigned long mask;
> int i;
>
> - pr_cont("(");
> + buf += snprintf(buf, end - buf, "%#lx(", flags);
Sorry, you can't do it like this. The buf you've been passed from inside
vsnprintf may be beyond end, so end-buf is a negative number which will
(get converted to a huge positive size_t and) trigger a WARN_ONCE and
get you a return value of 0.
> + flags &= ~mask_out;
>
> for (i = 0; i < count && flags; i++) {
> + if (buf >= end)
> + break;
Even if you fix the above, this is also wrong. We have to return the
length of the string that would be generated if there was room enough,
so we cannot make an early return like this. As I said above, the
easiest way to do that is to do it inside vsprintf.c, where we have
e.g. string() available. So I'd do something like
char *format_flags(char *buf, char *end, unsigned long flags,
const struct trace_print_flags *names)
{
unsigned long mask;
const struct printf_spec strspec = {/* appropriate defaults*/}
const struct printf_spec numspec = {/* appropriate defaults*/}
for ( ; flags && names->mask; names++) {
mask = names->mask;
if ((flags & mask) != mask)
continue;
flags &= ~mask;
buf = string(buf, end, names->name, strspec);
if (flags) {
if (buf < end)
*buf = '|';
buf++;
}
}
if (flags)
buf = number(buf, end, flags, numspec);
return buf;
}
[where I've assumed that the trace_print_flags array is terminated with
an entry with 0 mask. Passing its length is also possible, but maybe a
little awkward if the arrays are defined in mm/ and contents depend on
.config.]
Then flags_string() would call this directly with an appropriate array
for names, and we avoid the individual tiny helper
functions. flags_string() can still do the mask_out thing for page
flags, especially when/if the numeric and string representations are not
done at the same time.
Rasmus
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH 1/2] mm, printk: introduce new format string for flags
@ 2015-12-02 11:01 ` Rasmus Villemoes
0 siblings, 0 replies; 115+ messages in thread
From: Rasmus Villemoes @ 2015-12-02 11:01 UTC (permalink / raw)
To: Vlastimil Babka
Cc: linux-mm, linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko
On Mon, Nov 30 2015, Vlastimil Babka <vbabka@suse.cz> 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.
>
> Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
> Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk>
> ---
> I'm sending it on top of the page_owner series, as it's already in mmotm.
> But to reduce churn (in case this approach is accepted), I can later
> incorporate it and resend it whole.
>
> Documentation/printk-formats.txt | 14 ++++
> include/linux/mmdebug.h | 5 +-
> lib/vsprintf.c | 31 ++++++++
> mm/debug.c | 150 ++++++++++++++++++++++-----------------
> mm/oom_kill.c | 5 +-
> mm/page_alloc.c | 5 +-
> mm/page_owner.c | 5 +-
> 7 files changed, 140 insertions(+), 75 deletions(-)
I'd prefer to have the formatting code in vsprintf.c, so that we'd avoid
having to call vsnprintf recursively (and repeatedly - not that this is
going to be used in hot paths, but if the box is going down it might be
nice to get the debug info out a few thousand cycles earlier). That'll
also make it easier to avoid the bugs below.
> diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt
> index b784c270105f..4b5156e74b09 100644
> --- a/Documentation/printk-formats.txt
> +++ b/Documentation/printk-formats.txt
> @@ -292,6 +292,20 @@ Raw pointer value SHOULD be printed with %p. The kernel supports
>
> Passed by reference.
>
> +Flags bitfields such as page flags, gfp_flags:
> +
> + %pgp 0x1fffff8000086c(referenced|uptodate|lru|active|private)
> + %pgg 0x24202c4(GFP_USER|GFP_DMA32|GFP_NOWARN)
> + %pgv 0x875(read|exec|mayread|maywrite|mayexec|denywrite)
> +
I think it would be better (and more flexible) if %pg* only stood for
printing the | chain of strings. Let people pass the flags twice if they
also want the numeric value; then they're also able to choose 0-padding
and whatnot, can use other kinds of parentheses, etc., etc. So
pr_emerg("flags: 0x%08lu [%pgp]\n", printflags, &printflags)
> + For printing raw values of flags bitfields together with symbolic
> + strings that would construct the value. The type of flags is given by
> + the third character. Currently supported are [p]age flags, [g]fp_flags
> + and [v]ma_flags. The flag names and print order depends on the
> + particular type.
> +
> + Passed by reference.
> +
> Network device features:
>
> %pNF 0x000000000000c000
> diff --git a/include/linux/mmdebug.h b/include/linux/mmdebug.h
> index 3b77fab7ad28..e6518df259ca 100644
> --- a/include/linux/mmdebug.h
> +++ b/include/linux/mmdebug.h
> @@ -2,6 +2,7 @@
> #define LINUX_MM_DEBUG_H 1
>
> #include <linux/stringify.h>
> +#include <linux/types.h>
>
> struct page;
> struct vm_area_struct;
> @@ -10,7 +11,9 @@ struct mm_struct;
> 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_gfpflag_names(unsigned long gfp_flags);
> +extern char *format_page_flags(unsigned long flags, char *buf, char *end);
> +extern char *format_vma_flags(unsigned long flags, char *buf, char *end);
> +extern char *format_gfp_flags(gfp_t gfp_flags, char *buf, char*end);
> void dump_vma(const struct vm_area_struct *vma);
> void dump_mm(const struct mm_struct *mm);
>
> diff --git a/lib/vsprintf.c b/lib/vsprintf.c
> index f9cee8e1233c..41cd122bd307 100644
> --- a/lib/vsprintf.c
> +++ b/lib/vsprintf.c
> @@ -31,6 +31,7 @@
> #include <linux/dcache.h>
> #include <linux/cred.h>
> #include <net/addrconf.h>
> +#include <linux/mmdebug.h>
>
> #include <asm/page.h> /* for PAGE_SIZE */
> #include <asm/sections.h> /* for dereference_function_descriptor() */
> @@ -1361,6 +1362,29 @@ char *clock(char *buf, char *end, struct clk *clk, struct printf_spec spec,
> }
> }
>
> +static noinline_for_stack
> +char *flags_string(char *buf, char *end, void *flags_ptr,
> + struct printf_spec spec, const char *fmt)
> +{
> + unsigned long flags;
> + gfp_t gfp_flags;
> +
> + switch (fmt[1]) {
> + case 'p':
> + flags = *(unsigned long *)flags_ptr;
> + return format_page_flags(flags, buf, end);
> + case 'v':
> + flags = *(unsigned long *)flags_ptr;
> + return format_vma_flags(flags, buf, end);
> + case 'g':
> + gfp_flags = *(gfp_t *)flags_ptr;
> + return format_gfp_flags(gfp_flags, buf, end);
> + default:
> + WARN_ONCE(1, "Unsupported flags modifier: %c\n", fmt[1]);
> + return 0;
> + }
> +}
> +
That return 0 aka return NULL will lead to an oops when the next thing
is printed. Did you mean 'return buf;'?
> int kptr_restrict __read_mostly;
>
> /*
> @@ -1448,6 +1472,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 **
> *
> @@ -1600,6 +1629,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, spec, fmt);
> }
> spec.flags |= SMALL;
> if (spec.field_width == -1) {
> diff --git a/mm/debug.c b/mm/debug.c
> index 2fdf0999e6f9..a092111920e7 100644
> --- a/mm/debug.c
> +++ b/mm/debug.c
> @@ -59,40 +59,109 @@ static const struct trace_print_flags pageflag_names[] = {
> #endif
> };
>
> +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 gfpflag_names[] = {
> __def_gfpflag_names
> };
>
> -static void dump_flag_names(unsigned long flags,
> - const struct trace_print_flags *names, int count)
> +static char *format_flag_names(unsigned long flags, unsigned long mask_out,
> + const struct trace_print_flags *names, int count,
> + char *buf, char *end)
> {
> const char *delim = "";
> unsigned long mask;
> int i;
>
> - pr_cont("(");
> + buf += snprintf(buf, end - buf, "%#lx(", flags);
Sorry, you can't do it like this. The buf you've been passed from inside
vsnprintf may be beyond end, so end-buf is a negative number which will
(get converted to a huge positive size_t and) trigger a WARN_ONCE and
get you a return value of 0.
> + flags &= ~mask_out;
>
> for (i = 0; i < count && flags; i++) {
> + if (buf >= end)
> + break;
Even if you fix the above, this is also wrong. We have to return the
length of the string that would be generated if there was room enough,
so we cannot make an early return like this. As I said above, the
easiest way to do that is to do it inside vsprintf.c, where we have
e.g. string() available. So I'd do something like
char *format_flags(char *buf, char *end, unsigned long flags,
const struct trace_print_flags *names)
{
unsigned long mask;
const struct printf_spec strspec = {/* appropriate defaults*/}
const struct printf_spec numspec = {/* appropriate defaults*/}
for ( ; flags && names->mask; names++) {
mask = names->mask;
if ((flags & mask) != mask)
continue;
flags &= ~mask;
buf = string(buf, end, names->name, strspec);
if (flags) {
if (buf < end)
*buf = '|';
buf++;
}
}
if (flags)
buf = number(buf, end, flags, numspec);
return buf;
}
[where I've assumed that the trace_print_flags array is terminated with
an entry with 0 mask. Passing its length is also possible, but maybe a
little awkward if the arrays are defined in mm/ and contents depend on
.config.]
Then flags_string() would call this directly with an appropriate array
for names, and we avoid the individual tiny helper
functions. flags_string() can still do the mask_out thing for page
flags, especially when/if the numeric and string representations are not
done at the same time.
Rasmus
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH 1/2] mm, printk: introduce new format string for flags
2015-12-02 11:01 ` Rasmus Villemoes
@ 2015-12-02 20:34 ` Vlastimil Babka
-1 siblings, 0 replies; 115+ messages in thread
From: Vlastimil Babka @ 2015-12-02 20:34 UTC (permalink / raw)
To: Rasmus Villemoes
Cc: linux-mm, linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko
On 12/02/2015 12:01 PM, Rasmus Villemoes wrote:
> On Mon, Nov 30 2015, Vlastimil Babka <vbabka@suse.cz> wrote:
>
> I'd prefer to have the formatting code in vsprintf.c, so that we'd avoid
> having to call vsnprintf recursively (and repeatedly - not that this is
> going to be used in hot paths, but if the box is going down it might be
> nice to get the debug info out a few thousand cycles earlier). That'll
> also make it easier to avoid the bugs below.
OK, I'll try.
>> diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt
>> index b784c270105f..4b5156e74b09 100644
>> --- a/Documentation/printk-formats.txt
>> +++ b/Documentation/printk-formats.txt
>> @@ -292,6 +292,20 @@ Raw pointer value SHOULD be printed with %p. The kernel supports
>>
>> Passed by reference.
>>
>> +Flags bitfields such as page flags, gfp_flags:
>> +
>> + %pgp 0x1fffff8000086c(referenced|uptodate|lru|active|private)
>> + %pgg 0x24202c4(GFP_USER|GFP_DMA32|GFP_NOWARN)
>> + %pgv 0x875(read|exec|mayread|maywrite|mayexec|denywrite)
>> +
>
> I think it would be better (and more flexible) if %pg* only stood for
> printing the | chain of strings. Let people pass the flags twice if they
> also want the numeric value; then they're also able to choose 0-padding
> and whatnot, can use other kinds of parentheses, etc., etc. So
>
> pr_emerg("flags: 0x%08lu [%pgp]\n", printflags, &printflags)
I had it initially like this, but then thought it was somewhat repetitive and
all current users did use the same format. But I agree it's more generic to do
it as you say so I'll change it.
>> @@ -1361,6 +1362,29 @@ char *clock(char *buf, char *end, struct clk *clk, struct printf_spec spec,
>> }
>> }
>>
>> +static noinline_for_stack
>> +char *flags_string(char *buf, char *end, void *flags_ptr,
>> + struct printf_spec spec, const char *fmt)
>> +{
>> + unsigned long flags;
>> + gfp_t gfp_flags;
>> +
>> + switch (fmt[1]) {
>> + case 'p':
>> + flags = *(unsigned long *)flags_ptr;
>> + return format_page_flags(flags, buf, end);
>> + case 'v':
>> + flags = *(unsigned long *)flags_ptr;
>> + return format_vma_flags(flags, buf, end);
>> + case 'g':
>> + gfp_flags = *(gfp_t *)flags_ptr;
>> + return format_gfp_flags(gfp_flags, buf, end);
>> + default:
>> + WARN_ONCE(1, "Unsupported flags modifier: %c\n", fmt[1]);
>> + return 0;
>> + }
>> +}
>> +
>
> That return 0 aka return NULL will lead to an oops when the next thing
> is printed. Did you mean 'return buf;'?
Uh, right.
>>
>> -static void dump_flag_names(unsigned long flags,
>> - const struct trace_print_flags *names, int count)
>> +static char *format_flag_names(unsigned long flags, unsigned long mask_out,
>> + const struct trace_print_flags *names, int count,
>> + char *buf, char *end)
>> {
>> const char *delim = "";
>> unsigned long mask;
>> int i;
>>
>> - pr_cont("(");
>> + buf += snprintf(buf, end - buf, "%#lx(", flags);
>
> Sorry, you can't do it like this. The buf you've been passed from inside
> vsnprintf may be beyond end
Ah, didn't realize that :/
> , so end-buf is a negative number which will
> (get converted to a huge positive size_t and) trigger a WARN_ONCE and
> get you a return value of 0.
>
>
>> + flags &= ~mask_out;
>>
>> for (i = 0; i < count && flags; i++) {
>> + if (buf >= end)
>> + break;
>
> Even if you fix the above, this is also wrong. We have to return the
> length of the string that would be generated if there was room enough,
> so we cannot make an early return like this. As I said above, the
> easiest way to do that is to do it inside vsprintf.c, where we have
> e.g. string() available. So I'd do something like
>
>
> char *format_flags(char *buf, char *end, unsigned long flags,
> const struct trace_print_flags *names)
> {
> unsigned long mask;
> const struct printf_spec strspec = {/* appropriate defaults*/}
> const struct printf_spec numspec = {/* appropriate defaults*/}
>
> for ( ; flags && names->mask; names++) {
> mask = names->mask;
> if ((flags & mask) != mask)
> continue;
> flags &= ~mask;
> buf = string(buf, end, names->name, strspec);
> if (flags) {
> if (buf < end)
> *buf = '|';
> buf++;
> }
> }
> if (flags)
> buf = number(buf, end, flags, numspec);
> return buf;
> }
Thanks a lot for your review and suggestions!
> [where I've assumed that the trace_print_flags array is terminated with
> an entry with 0 mask. Passing its length is also possible, but maybe a
> little awkward if the arrays are defined in mm/ and contents depend on
> .config.]
> Then flags_string() would call this directly with an appropriate array
> for names, and we avoid the individual tiny helper
> functions. flags_string() can still do the mask_out thing for page
> flags, especially when/if the numeric and string representations are not
> done at the same time.
>
> Rasmus
Zero-terminated array is a good idea to get rid of the ARRAY_SIZE with helpers
needing to live in the same .c file etc.
But if I were to keep the array definitions in mm/debug.c with declarations
(which don't know the size yet) in e.g. <linux/mmdebug.h> (which lib/vsnprintf.c
would include so that format_flags() can reference them, is there a more elegant
way than the one below?
--- a/include/linux/mmdebug.h
+++ b/include/linux/mmdebug.h
@@ -7,6 +7,9 @@
struct page;
struct vm_area_struct;
struct mm_struct;
+struct trace_print_flags; // can't include trace_events.h here
+
+extern const struct trace_print_flags *pageflag_names;
extern void dump_page(struct page *page, const char *reason);
extern void dump_page_badflags(struct page *page, const char *reason,
diff --git a/mm/debug.c b/mm/debug.c
index a092111920e7..1cbc60544b87 100644
--- a/mm/debug.c
+++ b/mm/debug.c
@@ -23,7 +23,7 @@ char *migrate_reason_names[MR_TYPES] = {
"cma",
};
-static const struct trace_print_flags pageflag_names[] = {
+const struct trace_print_flags __pageflag_names[] = {
{1UL << PG_locked, "locked" },
{1UL << PG_error, "error" },
{1UL << PG_referenced, "referenced" },
@@ -59,6 +59,8 @@ static const struct trace_print_flags pageflag_names[] = {
#endif
};
+const struct trace_print_flags *pageflag_names = &__pageflag_names[0];
^ permalink raw reply related [flat|nested] 115+ messages in thread
* Re: [PATCH 1/2] mm, printk: introduce new format string for flags
@ 2015-12-02 20:34 ` Vlastimil Babka
0 siblings, 0 replies; 115+ messages in thread
From: Vlastimil Babka @ 2015-12-02 20:34 UTC (permalink / raw)
To: Rasmus Villemoes
Cc: linux-mm, linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko
On 12/02/2015 12:01 PM, Rasmus Villemoes wrote:
> On Mon, Nov 30 2015, Vlastimil Babka <vbabka@suse.cz> wrote:
>
> I'd prefer to have the formatting code in vsprintf.c, so that we'd avoid
> having to call vsnprintf recursively (and repeatedly - not that this is
> going to be used in hot paths, but if the box is going down it might be
> nice to get the debug info out a few thousand cycles earlier). That'll
> also make it easier to avoid the bugs below.
OK, I'll try.
>> diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt
>> index b784c270105f..4b5156e74b09 100644
>> --- a/Documentation/printk-formats.txt
>> +++ b/Documentation/printk-formats.txt
>> @@ -292,6 +292,20 @@ Raw pointer value SHOULD be printed with %p. The kernel supports
>>
>> Passed by reference.
>>
>> +Flags bitfields such as page flags, gfp_flags:
>> +
>> + %pgp 0x1fffff8000086c(referenced|uptodate|lru|active|private)
>> + %pgg 0x24202c4(GFP_USER|GFP_DMA32|GFP_NOWARN)
>> + %pgv 0x875(read|exec|mayread|maywrite|mayexec|denywrite)
>> +
>
> I think it would be better (and more flexible) if %pg* only stood for
> printing the | chain of strings. Let people pass the flags twice if they
> also want the numeric value; then they're also able to choose 0-padding
> and whatnot, can use other kinds of parentheses, etc., etc. So
>
> pr_emerg("flags: 0x%08lu [%pgp]\n", printflags, &printflags)
I had it initially like this, but then thought it was somewhat repetitive and
all current users did use the same format. But I agree it's more generic to do
it as you say so I'll change it.
>> @@ -1361,6 +1362,29 @@ char *clock(char *buf, char *end, struct clk *clk, struct printf_spec spec,
>> }
>> }
>>
>> +static noinline_for_stack
>> +char *flags_string(char *buf, char *end, void *flags_ptr,
>> + struct printf_spec spec, const char *fmt)
>> +{
>> + unsigned long flags;
>> + gfp_t gfp_flags;
>> +
>> + switch (fmt[1]) {
>> + case 'p':
>> + flags = *(unsigned long *)flags_ptr;
>> + return format_page_flags(flags, buf, end);
>> + case 'v':
>> + flags = *(unsigned long *)flags_ptr;
>> + return format_vma_flags(flags, buf, end);
>> + case 'g':
>> + gfp_flags = *(gfp_t *)flags_ptr;
>> + return format_gfp_flags(gfp_flags, buf, end);
>> + default:
>> + WARN_ONCE(1, "Unsupported flags modifier: %c\n", fmt[1]);
>> + return 0;
>> + }
>> +}
>> +
>
> That return 0 aka return NULL will lead to an oops when the next thing
> is printed. Did you mean 'return buf;'?
Uh, right.
>>
>> -static void dump_flag_names(unsigned long flags,
>> - const struct trace_print_flags *names, int count)
>> +static char *format_flag_names(unsigned long flags, unsigned long mask_out,
>> + const struct trace_print_flags *names, int count,
>> + char *buf, char *end)
>> {
>> const char *delim = "";
>> unsigned long mask;
>> int i;
>>
>> - pr_cont("(");
>> + buf += snprintf(buf, end - buf, "%#lx(", flags);
>
> Sorry, you can't do it like this. The buf you've been passed from inside
> vsnprintf may be beyond end
Ah, didn't realize that :/
> , so end-buf is a negative number which will
> (get converted to a huge positive size_t and) trigger a WARN_ONCE and
> get you a return value of 0.
>
>
>> + flags &= ~mask_out;
>>
>> for (i = 0; i < count && flags; i++) {
>> + if (buf >= end)
>> + break;
>
> Even if you fix the above, this is also wrong. We have to return the
> length of the string that would be generated if there was room enough,
> so we cannot make an early return like this. As I said above, the
> easiest way to do that is to do it inside vsprintf.c, where we have
> e.g. string() available. So I'd do something like
>
>
> char *format_flags(char *buf, char *end, unsigned long flags,
> const struct trace_print_flags *names)
> {
> unsigned long mask;
> const struct printf_spec strspec = {/* appropriate defaults*/}
> const struct printf_spec numspec = {/* appropriate defaults*/}
>
> for ( ; flags && names->mask; names++) {
> mask = names->mask;
> if ((flags & mask) != mask)
> continue;
> flags &= ~mask;
> buf = string(buf, end, names->name, strspec);
> if (flags) {
> if (buf < end)
> *buf = '|';
> buf++;
> }
> }
> if (flags)
> buf = number(buf, end, flags, numspec);
> return buf;
> }
Thanks a lot for your review and suggestions!
> [where I've assumed that the trace_print_flags array is terminated with
> an entry with 0 mask. Passing its length is also possible, but maybe a
> little awkward if the arrays are defined in mm/ and contents depend on
> .config.]
> Then flags_string() would call this directly with an appropriate array
> for names, and we avoid the individual tiny helper
> functions. flags_string() can still do the mask_out thing for page
> flags, especially when/if the numeric and string representations are not
> done at the same time.
>
> Rasmus
Zero-terminated array is a good idea to get rid of the ARRAY_SIZE with helpers
needing to live in the same .c file etc.
But if I were to keep the array definitions in mm/debug.c with declarations
(which don't know the size yet) in e.g. <linux/mmdebug.h> (which lib/vsnprintf.c
would include so that format_flags() can reference them, is there a more elegant
way than the one below?
--- a/include/linux/mmdebug.h
+++ b/include/linux/mmdebug.h
@@ -7,6 +7,9 @@
struct page;
struct vm_area_struct;
struct mm_struct;
+struct trace_print_flags; // can't include trace_events.h here
+
+extern const struct trace_print_flags *pageflag_names;
extern void dump_page(struct page *page, const char *reason);
extern void dump_page_badflags(struct page *page, const char *reason,
diff --git a/mm/debug.c b/mm/debug.c
index a092111920e7..1cbc60544b87 100644
--- a/mm/debug.c
+++ b/mm/debug.c
@@ -23,7 +23,7 @@ char *migrate_reason_names[MR_TYPES] = {
"cma",
};
-static const struct trace_print_flags pageflag_names[] = {
+const struct trace_print_flags __pageflag_names[] = {
{1UL << PG_locked, "locked" },
{1UL << PG_error, "error" },
{1UL << PG_referenced, "referenced" },
@@ -59,6 +59,8 @@ static const struct trace_print_flags pageflag_names[] = {
#endif
};
+const struct trace_print_flags *pageflag_names = &__pageflag_names[0];
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related [flat|nested] 115+ messages in thread
* Re: [PATCH 1/2] mm, printk: introduce new format string for flags
2015-12-02 20:34 ` Vlastimil Babka
@ 2015-12-03 12:37 ` Rasmus Villemoes
-1 siblings, 0 replies; 115+ messages in thread
From: Rasmus Villemoes @ 2015-12-03 12:37 UTC (permalink / raw)
To: Vlastimil Babka
Cc: linux-mm, linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko
On Wed, Dec 02 2015, Vlastimil Babka <vbabka@suse.cz> wrote:
>> [where I've assumed that the trace_print_flags array is terminated with
>> an entry with 0 mask. Passing its length is also possible, but maybe a
>> little awkward if the arrays are defined in mm/ and contents depend on
>> .config.]
...
>
>> Rasmus
>
> Zero-terminated array is a good idea to get rid of the ARRAY_SIZE with helpers
> needing to live in the same .c file etc.
>
> But if I were to keep the array definitions in mm/debug.c with declarations
> (which don't know the size yet) in e.g. <linux/mmdebug.h> (which lib/vsnprintf.c
> would include so that format_flags() can reference them, is there a more elegant
> way than the one below?
>
> --- a/include/linux/mmdebug.h
> +++ b/include/linux/mmdebug.h
> @@ -7,6 +7,9 @@
> struct page;
> struct vm_area_struct;
> struct mm_struct;
> +struct trace_print_flags; // can't include trace_events.h here
> +
> +extern const struct trace_print_flags *pageflag_names;
>
> extern void dump_page(struct page *page, const char *reason);
> extern void dump_page_badflags(struct page *page, const char *reason,
> diff --git a/mm/debug.c b/mm/debug.c
> index a092111920e7..1cbc60544b87 100644
> --- a/mm/debug.c
> +++ b/mm/debug.c
> @@ -23,7 +23,7 @@ char *migrate_reason_names[MR_TYPES] = {
> "cma",
> };
>
> -static const struct trace_print_flags pageflag_names[] = {
> +const struct trace_print_flags __pageflag_names[] = {
> {1UL << PG_locked, "locked" },
> {1UL << PG_error, "error" },
> {1UL << PG_referenced, "referenced" },
> @@ -59,6 +59,8 @@ static const struct trace_print_flags pageflag_names[] = {
> #endif
> };
>
> +const struct trace_print_flags *pageflag_names = &__pageflag_names[0];
Ugh. I think it would be better if either the definition of struct
trace_print_flags is moved somewhere where everybody can see it or to
make our own identical type definition. For now I'd go with the latter,
also since this doesn't really have anything to do with the tracing
subsystem. Then just declare the array in the header
extern const struct print_flags pageflag_names[];
(If you do the extra indirection thing, __pageflag_names could still be
static, and it would be best to declare the pointer itself const as
well, but I'd rather we don't go that way.)
Rasmus
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH 1/2] mm, printk: introduce new format string for flags
@ 2015-12-03 12:37 ` Rasmus Villemoes
0 siblings, 0 replies; 115+ messages in thread
From: Rasmus Villemoes @ 2015-12-03 12:37 UTC (permalink / raw)
To: Vlastimil Babka
Cc: linux-mm, linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko
On Wed, Dec 02 2015, Vlastimil Babka <vbabka@suse.cz> wrote:
>> [where I've assumed that the trace_print_flags array is terminated with
>> an entry with 0 mask. Passing its length is also possible, but maybe a
>> little awkward if the arrays are defined in mm/ and contents depend on
>> .config.]
...
>
>> Rasmus
>
> Zero-terminated array is a good idea to get rid of the ARRAY_SIZE with helpers
> needing to live in the same .c file etc.
>
> But if I were to keep the array definitions in mm/debug.c with declarations
> (which don't know the size yet) in e.g. <linux/mmdebug.h> (which lib/vsnprintf.c
> would include so that format_flags() can reference them, is there a more elegant
> way than the one below?
>
> --- a/include/linux/mmdebug.h
> +++ b/include/linux/mmdebug.h
> @@ -7,6 +7,9 @@
> struct page;
> struct vm_area_struct;
> struct mm_struct;
> +struct trace_print_flags; // can't include trace_events.h here
> +
> +extern const struct trace_print_flags *pageflag_names;
>
> extern void dump_page(struct page *page, const char *reason);
> extern void dump_page_badflags(struct page *page, const char *reason,
> diff --git a/mm/debug.c b/mm/debug.c
> index a092111920e7..1cbc60544b87 100644
> --- a/mm/debug.c
> +++ b/mm/debug.c
> @@ -23,7 +23,7 @@ char *migrate_reason_names[MR_TYPES] = {
> "cma",
> };
>
> -static const struct trace_print_flags pageflag_names[] = {
> +const struct trace_print_flags __pageflag_names[] = {
> {1UL << PG_locked, "locked" },
> {1UL << PG_error, "error" },
> {1UL << PG_referenced, "referenced" },
> @@ -59,6 +59,8 @@ static const struct trace_print_flags pageflag_names[] = {
> #endif
> };
>
> +const struct trace_print_flags *pageflag_names = &__pageflag_names[0];
Ugh. I think it would be better if either the definition of struct
trace_print_flags is moved somewhere where everybody can see it or to
make our own identical type definition. For now I'd go with the latter,
also since this doesn't really have anything to do with the tracing
subsystem. Then just declare the array in the header
extern const struct print_flags pageflag_names[];
(If you do the extra indirection thing, __pageflag_names could still be
static, and it would be best to declare the pointer itself const as
well, but I'd rather we don't go that way.)
Rasmus
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH 1/2] mm, printk: introduce new format string for flags
2015-12-03 12:37 ` Rasmus Villemoes
@ 2015-12-03 13:46 ` Vlastimil Babka
-1 siblings, 0 replies; 115+ messages in thread
From: Vlastimil Babka @ 2015-12-03 13:46 UTC (permalink / raw)
To: Rasmus Villemoes
Cc: linux-mm, linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko
On 12/03/2015 01:37 PM, Rasmus Villemoes wrote:
> On Wed, Dec 02 2015, Vlastimil Babka <vbabka@suse.cz> wrote:
>> --- a/include/linux/mmdebug.h
>> +++ b/include/linux/mmdebug.h
>> @@ -7,6 +7,9 @@
>> struct page;
>> struct vm_area_struct;
>> struct mm_struct;
>> +struct trace_print_flags; // can't include trace_events.h here
>> +
>> +extern const struct trace_print_flags *pageflag_names;
>>
>> extern void dump_page(struct page *page, const char *reason);
>> extern void dump_page_badflags(struct page *page, const char *reason,
>> diff --git a/mm/debug.c b/mm/debug.c
>> index a092111920e7..1cbc60544b87 100644
>> --- a/mm/debug.c
>> +++ b/mm/debug.c
>> @@ -23,7 +23,7 @@ char *migrate_reason_names[MR_TYPES] = {
>> "cma",
>> };
>>
>> -static const struct trace_print_flags pageflag_names[] = {
>> +const struct trace_print_flags __pageflag_names[] = {
>> {1UL << PG_locked, "locked" },
>> {1UL << PG_error, "error" },
>> {1UL << PG_referenced, "referenced" },
>> @@ -59,6 +59,8 @@ static const struct trace_print_flags pageflag_names[] = {
>> #endif
>> };
>>
>> +const struct trace_print_flags *pageflag_names = &__pageflag_names[0];
>
> Ugh. I think it would be better if either the definition of struct
> trace_print_flags is moved somewhere where everybody can see it or to
> make our own identical type definition. For now I'd go with the latter,
> also since this doesn't really have anything to do with the tracing
> subsystem. Then just declare the array in the header
>
> extern const struct print_flags pageflag_names[];
Ugh so yesterday I copy/pasted the definition and still got an error, which I
probably didn't read closely enough. I assumed that if it needs the full
definition of "struct trace_print_flags" here to know the size, it would also
need to know the lenght of the array as well.
But now it works. Well, copy/pasting the definition fails as long as both
headers are included and it's redefining the struct (even though it's the same
thing). But looks like I can move it from trace_events.h to tracepoint.h and it
won't blow off (knock knock).
I suck at C.
> (If you do the extra indirection thing, __pageflag_names could still be
> static, and it would be best to declare the pointer itself const as
> well, but I'd rather we don't go that way.)
>
> Rasmus
>
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH 1/2] mm, printk: introduce new format string for flags
@ 2015-12-03 13:46 ` Vlastimil Babka
0 siblings, 0 replies; 115+ messages in thread
From: Vlastimil Babka @ 2015-12-03 13:46 UTC (permalink / raw)
To: Rasmus Villemoes
Cc: linux-mm, linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko
On 12/03/2015 01:37 PM, Rasmus Villemoes wrote:
> On Wed, Dec 02 2015, Vlastimil Babka <vbabka@suse.cz> wrote:
>> --- a/include/linux/mmdebug.h
>> +++ b/include/linux/mmdebug.h
>> @@ -7,6 +7,9 @@
>> struct page;
>> struct vm_area_struct;
>> struct mm_struct;
>> +struct trace_print_flags; // can't include trace_events.h here
>> +
>> +extern const struct trace_print_flags *pageflag_names;
>>
>> extern void dump_page(struct page *page, const char *reason);
>> extern void dump_page_badflags(struct page *page, const char *reason,
>> diff --git a/mm/debug.c b/mm/debug.c
>> index a092111920e7..1cbc60544b87 100644
>> --- a/mm/debug.c
>> +++ b/mm/debug.c
>> @@ -23,7 +23,7 @@ char *migrate_reason_names[MR_TYPES] = {
>> "cma",
>> };
>>
>> -static const struct trace_print_flags pageflag_names[] = {
>> +const struct trace_print_flags __pageflag_names[] = {
>> {1UL << PG_locked, "locked" },
>> {1UL << PG_error, "error" },
>> {1UL << PG_referenced, "referenced" },
>> @@ -59,6 +59,8 @@ static const struct trace_print_flags pageflag_names[] = {
>> #endif
>> };
>>
>> +const struct trace_print_flags *pageflag_names = &__pageflag_names[0];
>
> Ugh. I think it would be better if either the definition of struct
> trace_print_flags is moved somewhere where everybody can see it or to
> make our own identical type definition. For now I'd go with the latter,
> also since this doesn't really have anything to do with the tracing
> subsystem. Then just declare the array in the header
>
> extern const struct print_flags pageflag_names[];
Ugh so yesterday I copy/pasted the definition and still got an error, which I
probably didn't read closely enough. I assumed that if it needs the full
definition of "struct trace_print_flags" here to know the size, it would also
need to know the lenght of the array as well.
But now it works. Well, copy/pasting the definition fails as long as both
headers are included and it's redefining the struct (even though it's the same
thing). But looks like I can move it from trace_events.h to tracepoint.h and it
won't blow off (knock knock).
I suck at C.
> (If you do the extra indirection thing, __pageflag_names could still be
> static, and it would be best to declare the pointer itself const as
> well, but I'd rather we don't go that way.)
>
> Rasmus
>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 115+ messages in thread
* [PATCH v2 1/3] mm, printk: introduce new format string for flags
2015-12-02 11:01 ` Rasmus Villemoes
@ 2015-12-04 15:16 ` Vlastimil Babka
-1 siblings, 0 replies; 115+ messages in thread
From: Vlastimil Babka @ 2015-12-04 15:16 UTC (permalink / raw)
To: linux-mm
Cc: linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko,
Vlastimil Babka, Rasmus Villemoes
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: 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>
---
Should hopefully apply to mmots (release mmotm doesn't have the 3 -fix patches yet?)
Documentation/printk-formats.txt | 14 ++++
include/linux/mmdebug.h | 7 +-
include/linux/trace_events.h | 10 ---
include/linux/tracepoint.h | 10 +++
lib/vsprintf.c | 75 ++++++++++++++++++++++
mm/debug.c | 135 ++++++++++++++-------------------------
mm/oom_kill.c | 5 +-
mm/page_alloc.c | 5 +-
mm/page_owner.c | 6 +-
9 files changed, 160 insertions(+), 107 deletions(-)
diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt
index b784c270105f..8b6ab00fcfc9 100644
--- a/Documentation/printk-formats.txt
+++ b/Documentation/printk-formats.txt
@@ -292,6 +292,20 @@ 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, [g]fp_flags and
+ [v]ma_flags. The flag names and print order depends on the particular
+ type.
+
+ Passed by reference.
+
Network device features:
%pNF 0x000000000000c000
diff --git a/include/linux/mmdebug.h b/include/linux/mmdebug.h
index 3b77fab7ad28..2c8286cf162e 100644
--- a/include/linux/mmdebug.h
+++ b/include/linux/mmdebug.h
@@ -2,15 +2,20 @@
#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);
-extern void dump_gfpflag_names(unsigned long gfp_flags);
void dump_vma(const struct vm_area_struct *vma);
void dump_mm(const struct mm_struct *mm);
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.h b/include/linux/tracepoint.h
index 7834a8a8bf1e..a5d0ab46724d 100644
--- a/include/linux/tracepoint.h
+++ b/include/linux/tracepoint.h
@@ -43,6 +43,16 @@ struct trace_enum_map {
unsigned long enum_value;
};
+struct trace_print_flags {
+ unsigned long mask;
+ const char *name;
+};
+
+struct trace_print_flags_u64 {
+ unsigned long long mask;
+ const char *name;
+};
+
#define TRACEPOINT_DEFAULT_PRIO 10
extern int
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index f9cee8e1233c..9a0697b14ea3 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -31,6 +31,7 @@
#include <linux/dcache.h>
#include <linux/cred.h>
#include <net/addrconf.h>
+#include <linux/mmdebug.h>
#include <asm/page.h> /* for PAGE_SIZE */
#include <asm/sections.h> /* for dereference_function_descriptor() */
@@ -1361,6 +1362,73 @@ 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->mask || 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,
+ struct printf_spec spec, 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;
/*
@@ -1448,6 +1516,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 **
*
@@ -1600,6 +1673,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, spec, fmt);
}
spec.flags |= SMALL;
if (spec.field_width == -1) {
diff --git a/mm/debug.c b/mm/debug.c
index 9416524839d8..c42bb4c13c2d 100644
--- a/mm/debug.c
+++ b/mm/debug.c
@@ -23,7 +23,7 @@ char *migrate_reason_names[MR_TYPES] = {
"cma",
};
-static const struct trace_print_flags pageflag_names[] = {
+const struct trace_print_flags pageflag_names[] = {
{1UL << PG_locked, "locked" },
{1UL << PG_error, "error" },
{1UL << PG_referenced, "referenced" },
@@ -57,86 +57,10 @@ static const struct trace_print_flags pageflag_names[] = {
{1UL << PG_young, "young" },
{1UL << PG_idle, "idle" },
#endif
+ {0, NULL },
};
-static const struct trace_print_flags gfpflag_names[] = {
- __def_gfpflag_names
-};
-
-static void dump_flag_names(unsigned long flags,
- const struct trace_print_flags *names, int count)
-{
- const char *delim = "";
- unsigned long mask;
- int i;
-
- pr_cont("(");
-
- 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_gfpflag_names(unsigned long gfp_flags)
-{
- dump_flag_names(gfp_flags, gfpflag_names, ARRAY_SIZE(gfpflag_names));
-}
-
-void dump_page_badflags(struct page *page, const char *reason,
- unsigned long badflags)
-{
- unsigned long printflags = page->flags;
-
- pr_emerg("page:%p count:%d mapcount:%d mapping:%p index:%#lx",
- page, atomic_read(&page->_count), page_mapcount(page),
- page->mapping, page->index);
- if (PageCompound(page))
- pr_cont(" compound_mapcount: %d", compound_mapcount(page));
- pr_cont("\n");
- BUILD_BUG_ON(ARRAY_SIZE(pageflag_names) != __NR_PAGEFLAGS);
-
- pr_emerg("flags: %#lx", printflags);
- /* remove zone id */
- printflags &= (1UL << NR_PAGEFLAGS) - 1;
- dump_flag_names(printflags, pageflag_names, ARRAY_SIZE(pageflag_names));
-
- if (reason)
- pr_alert("page dumped because: %s\n", reason);
- if (page->flags & badflags) {
- printflags = page->flags & badflags;
- pr_alert("bad because of flags: %#lx:", printflags);
- dump_flag_names(printflags, pageflag_names,
- ARRAY_SIZE(pageflag_names));
- }
-#ifdef CONFIG_MEMCG
- if (page->mem_cgroup)
- pr_alert("page->mem_cgroup:%p\n", page->mem_cgroup);
-#endif
-}
-
-void dump_page(struct page *page, const char *reason)
-{
- dump_page_badflags(page, reason, 0);
- dump_page_owner(page);
-}
-EXPORT_SYMBOL(dump_page);
-
-#ifdef CONFIG_DEBUG_VM
-
-static const struct trace_print_flags vmaflags_names[] = {
+const struct trace_print_flags vmaflag_names[] = {
{VM_READ, "read" },
{VM_WRITE, "write" },
{VM_EXEC, "exec" },
@@ -177,22 +101,61 @@ static const struct trace_print_flags vmaflags_names[] = {
{VM_HUGEPAGE, "hugepage" },
{VM_NOHUGEPAGE, "nohugepage" },
{VM_MERGEABLE, "mergeable" },
+ {0, NULL },
+};
+
+const struct trace_print_flags gfpflag_names[] = {
+ __def_gfpflag_names,
+ {0, NULL},
};
+void dump_page_badflags(struct page *page, const char *reason,
+ unsigned long badflags)
+{
+ unsigned long printflags = page->flags;
+
+ pr_emerg("page:%p count:%d mapcount:%d mapping:%p index:%#lx\n",
+ page, atomic_read(&page->_count), page_mapcount(page),
+ page->mapping, page->index);
+ BUILD_BUG_ON(ARRAY_SIZE(pageflag_names) != __NR_PAGEFLAGS + 1);
+
+ pr_emerg("flags: %#lx(%pgp)\n", printflags, &printflags);
+
+ if (reason)
+ pr_alert("page dumped because: %s\n", reason);
+ if (page->flags & badflags) {
+ printflags = page->flags & badflags;
+ pr_alert("bad because of flags: %#lx(%pgp)\n", printflags,
+ &printflags);
+ }
+#ifdef CONFIG_MEMCG
+ if (page->mem_cgroup)
+ pr_alert("page->mem_cgroup:%p\n", page->mem_cgroup);
+#endif
+}
+
+void dump_page(struct page *page, const char *reason)
+{
+ dump_page_badflags(page, reason, 0);
+ dump_page_owner(page);
+}
+EXPORT_SYMBOL(dump_page);
+
+#ifdef CONFIG_DEBUG_VM
+
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);
- pr_emerg("flags: %#lx", vma->vm_flags);
- dump_flag_names(vma->vm_flags, vmaflags_names,
- ARRAY_SIZE(vmaflags_names));
+ vma->vm_file, vma->vm_private_data,
+ vma->vm_flags, &vma->vm_flags);
}
EXPORT_SYMBOL(dump_vma);
@@ -263,9 +226,7 @@ void dump_mm(const struct mm_struct *mm)
"" /* This is here to not have a comma! */
);
- pr_emerg("def_flags: %#lx", mm->def_flags);
- dump_flag_names(mm->def_flags, vmaflags_names,
- ARRAY_SIZE(vmaflags_names));
+ pr_emerg("def_flags: %#lx(%pgv)\n", mm->def_flags, &mm->def_flags);
}
#endif /* CONFIG_DEBUG_VM */
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 542d56c93209..07bba5a46b47 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -387,10 +387,9 @@ static void dump_header(struct oom_control *oc, struct task_struct *p,
struct mem_cgroup *memcg)
{
pr_warning("%s invoked oom-killer: order=%d, oom_score_adj=%hd, "
- "gfp_mask=0x%x",
+ "gfp_mask=%#x(%pgg)\n",
current->comm, oc->order, current->signal->oom_score_adj,
- oc->gfp_mask);
- dump_gfpflag_names(oc->gfp_mask);
+ oc->gfp_mask, &oc->gfp_mask);
cpuset_print_current_mems_allowed();
dump_stack();
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index d6d7c97c0b28..bd94c7465dea 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -2711,9 +2711,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",
- current->comm, order, gfp_mask);
- dump_gfpflag_names(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);
diff --git a/mm/page_owner.c b/mm/page_owner.c
index f4acd2452c35..313251f36d86 100644
--- a/mm/page_owner.c
+++ b/mm/page_owner.c
@@ -208,9 +208,9 @@ void __dump_page_owner(struct page *page)
return;
}
- pr_alert("page allocated via order %u, migratetype %s, gfp_mask 0x%x",
- page_ext->order, migratetype_names[mt], gfp_mask);
- dump_gfpflag_names(gfp_mask);
+ 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)
--
2.6.3
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v2 1/3] mm, printk: introduce new format string for flags
@ 2015-12-04 15:16 ` Vlastimil Babka
0 siblings, 0 replies; 115+ messages in thread
From: Vlastimil Babka @ 2015-12-04 15:16 UTC (permalink / raw)
To: linux-mm
Cc: linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko,
Vlastimil Babka, Rasmus Villemoes
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: 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>
---
Should hopefully apply to mmots (release mmotm doesn't have the 3 -fix patches yet?)
Documentation/printk-formats.txt | 14 ++++
include/linux/mmdebug.h | 7 +-
include/linux/trace_events.h | 10 ---
include/linux/tracepoint.h | 10 +++
lib/vsprintf.c | 75 ++++++++++++++++++++++
mm/debug.c | 135 ++++++++++++++-------------------------
mm/oom_kill.c | 5 +-
mm/page_alloc.c | 5 +-
mm/page_owner.c | 6 +-
9 files changed, 160 insertions(+), 107 deletions(-)
diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt
index b784c270105f..8b6ab00fcfc9 100644
--- a/Documentation/printk-formats.txt
+++ b/Documentation/printk-formats.txt
@@ -292,6 +292,20 @@ 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, [g]fp_flags and
+ [v]ma_flags. The flag names and print order depends on the particular
+ type.
+
+ Passed by reference.
+
Network device features:
%pNF 0x000000000000c000
diff --git a/include/linux/mmdebug.h b/include/linux/mmdebug.h
index 3b77fab7ad28..2c8286cf162e 100644
--- a/include/linux/mmdebug.h
+++ b/include/linux/mmdebug.h
@@ -2,15 +2,20 @@
#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);
-extern void dump_gfpflag_names(unsigned long gfp_flags);
void dump_vma(const struct vm_area_struct *vma);
void dump_mm(const struct mm_struct *mm);
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.h b/include/linux/tracepoint.h
index 7834a8a8bf1e..a5d0ab46724d 100644
--- a/include/linux/tracepoint.h
+++ b/include/linux/tracepoint.h
@@ -43,6 +43,16 @@ struct trace_enum_map {
unsigned long enum_value;
};
+struct trace_print_flags {
+ unsigned long mask;
+ const char *name;
+};
+
+struct trace_print_flags_u64 {
+ unsigned long long mask;
+ const char *name;
+};
+
#define TRACEPOINT_DEFAULT_PRIO 10
extern int
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index f9cee8e1233c..9a0697b14ea3 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -31,6 +31,7 @@
#include <linux/dcache.h>
#include <linux/cred.h>
#include <net/addrconf.h>
+#include <linux/mmdebug.h>
#include <asm/page.h> /* for PAGE_SIZE */
#include <asm/sections.h> /* for dereference_function_descriptor() */
@@ -1361,6 +1362,73 @@ 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->mask || 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,
+ struct printf_spec spec, 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;
/*
@@ -1448,6 +1516,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 **
*
@@ -1600,6 +1673,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, spec, fmt);
}
spec.flags |= SMALL;
if (spec.field_width == -1) {
diff --git a/mm/debug.c b/mm/debug.c
index 9416524839d8..c42bb4c13c2d 100644
--- a/mm/debug.c
+++ b/mm/debug.c
@@ -23,7 +23,7 @@ char *migrate_reason_names[MR_TYPES] = {
"cma",
};
-static const struct trace_print_flags pageflag_names[] = {
+const struct trace_print_flags pageflag_names[] = {
{1UL << PG_locked, "locked" },
{1UL << PG_error, "error" },
{1UL << PG_referenced, "referenced" },
@@ -57,86 +57,10 @@ static const struct trace_print_flags pageflag_names[] = {
{1UL << PG_young, "young" },
{1UL << PG_idle, "idle" },
#endif
+ {0, NULL },
};
-static const struct trace_print_flags gfpflag_names[] = {
- __def_gfpflag_names
-};
-
-static void dump_flag_names(unsigned long flags,
- const struct trace_print_flags *names, int count)
-{
- const char *delim = "";
- unsigned long mask;
- int i;
-
- pr_cont("(");
-
- 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_gfpflag_names(unsigned long gfp_flags)
-{
- dump_flag_names(gfp_flags, gfpflag_names, ARRAY_SIZE(gfpflag_names));
-}
-
-void dump_page_badflags(struct page *page, const char *reason,
- unsigned long badflags)
-{
- unsigned long printflags = page->flags;
-
- pr_emerg("page:%p count:%d mapcount:%d mapping:%p index:%#lx",
- page, atomic_read(&page->_count), page_mapcount(page),
- page->mapping, page->index);
- if (PageCompound(page))
- pr_cont(" compound_mapcount: %d", compound_mapcount(page));
- pr_cont("\n");
- BUILD_BUG_ON(ARRAY_SIZE(pageflag_names) != __NR_PAGEFLAGS);
-
- pr_emerg("flags: %#lx", printflags);
- /* remove zone id */
- printflags &= (1UL << NR_PAGEFLAGS) - 1;
- dump_flag_names(printflags, pageflag_names, ARRAY_SIZE(pageflag_names));
-
- if (reason)
- pr_alert("page dumped because: %s\n", reason);
- if (page->flags & badflags) {
- printflags = page->flags & badflags;
- pr_alert("bad because of flags: %#lx:", printflags);
- dump_flag_names(printflags, pageflag_names,
- ARRAY_SIZE(pageflag_names));
- }
-#ifdef CONFIG_MEMCG
- if (page->mem_cgroup)
- pr_alert("page->mem_cgroup:%p\n", page->mem_cgroup);
-#endif
-}
-
-void dump_page(struct page *page, const char *reason)
-{
- dump_page_badflags(page, reason, 0);
- dump_page_owner(page);
-}
-EXPORT_SYMBOL(dump_page);
-
-#ifdef CONFIG_DEBUG_VM
-
-static const struct trace_print_flags vmaflags_names[] = {
+const struct trace_print_flags vmaflag_names[] = {
{VM_READ, "read" },
{VM_WRITE, "write" },
{VM_EXEC, "exec" },
@@ -177,22 +101,61 @@ static const struct trace_print_flags vmaflags_names[] = {
{VM_HUGEPAGE, "hugepage" },
{VM_NOHUGEPAGE, "nohugepage" },
{VM_MERGEABLE, "mergeable" },
+ {0, NULL },
+};
+
+const struct trace_print_flags gfpflag_names[] = {
+ __def_gfpflag_names,
+ {0, NULL},
};
+void dump_page_badflags(struct page *page, const char *reason,
+ unsigned long badflags)
+{
+ unsigned long printflags = page->flags;
+
+ pr_emerg("page:%p count:%d mapcount:%d mapping:%p index:%#lx\n",
+ page, atomic_read(&page->_count), page_mapcount(page),
+ page->mapping, page->index);
+ BUILD_BUG_ON(ARRAY_SIZE(pageflag_names) != __NR_PAGEFLAGS + 1);
+
+ pr_emerg("flags: %#lx(%pgp)\n", printflags, &printflags);
+
+ if (reason)
+ pr_alert("page dumped because: %s\n", reason);
+ if (page->flags & badflags) {
+ printflags = page->flags & badflags;
+ pr_alert("bad because of flags: %#lx(%pgp)\n", printflags,
+ &printflags);
+ }
+#ifdef CONFIG_MEMCG
+ if (page->mem_cgroup)
+ pr_alert("page->mem_cgroup:%p\n", page->mem_cgroup);
+#endif
+}
+
+void dump_page(struct page *page, const char *reason)
+{
+ dump_page_badflags(page, reason, 0);
+ dump_page_owner(page);
+}
+EXPORT_SYMBOL(dump_page);
+
+#ifdef CONFIG_DEBUG_VM
+
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);
- pr_emerg("flags: %#lx", vma->vm_flags);
- dump_flag_names(vma->vm_flags, vmaflags_names,
- ARRAY_SIZE(vmaflags_names));
+ vma->vm_file, vma->vm_private_data,
+ vma->vm_flags, &vma->vm_flags);
}
EXPORT_SYMBOL(dump_vma);
@@ -263,9 +226,7 @@ void dump_mm(const struct mm_struct *mm)
"" /* This is here to not have a comma! */
);
- pr_emerg("def_flags: %#lx", mm->def_flags);
- dump_flag_names(mm->def_flags, vmaflags_names,
- ARRAY_SIZE(vmaflags_names));
+ pr_emerg("def_flags: %#lx(%pgv)\n", mm->def_flags, &mm->def_flags);
}
#endif /* CONFIG_DEBUG_VM */
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 542d56c93209..07bba5a46b47 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -387,10 +387,9 @@ static void dump_header(struct oom_control *oc, struct task_struct *p,
struct mem_cgroup *memcg)
{
pr_warning("%s invoked oom-killer: order=%d, oom_score_adj=%hd, "
- "gfp_mask=0x%x",
+ "gfp_mask=%#x(%pgg)\n",
current->comm, oc->order, current->signal->oom_score_adj,
- oc->gfp_mask);
- dump_gfpflag_names(oc->gfp_mask);
+ oc->gfp_mask, &oc->gfp_mask);
cpuset_print_current_mems_allowed();
dump_stack();
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index d6d7c97c0b28..bd94c7465dea 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -2711,9 +2711,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",
- current->comm, order, gfp_mask);
- dump_gfpflag_names(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);
diff --git a/mm/page_owner.c b/mm/page_owner.c
index f4acd2452c35..313251f36d86 100644
--- a/mm/page_owner.c
+++ b/mm/page_owner.c
@@ -208,9 +208,9 @@ void __dump_page_owner(struct page *page)
return;
}
- pr_alert("page allocated via order %u, migratetype %s, gfp_mask 0x%x",
- page_ext->order, migratetype_names[mt], gfp_mask);
- dump_gfpflag_names(gfp_mask);
+ 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)
--
2.6.3
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v2 2/3] mm, page_owner: provide symbolic page flags and gfp_flags
2015-12-04 15:16 ` Vlastimil Babka
@ 2015-12-04 15:16 ` Vlastimil Babka
-1 siblings, 0 replies; 115+ messages in thread
From: Vlastimil Babka @ 2015-12-04 15:16 UTC (permalink / raw)
To: linux-mm
Cc: linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko,
Vlastimil Babka, Rasmus Villemoes
With the new format strings for flags, we can now 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 of the adjusted format:
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: 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/page_owner.c | 20 +++++---------------
1 file changed, 5 insertions(+), 15 deletions(-)
diff --git a/mm/page_owner.c b/mm/page_owner.c
index 313251f36d86..011377548b4f 100644
--- a/mm/page_owner.c
+++ b/mm/page_owner.c
@@ -135,8 +135,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;
@@ -145,23 +146,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 type %s Block %lu type %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,
migratetype_names[pageblock_mt],
- 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" : " ");
+ page->flags, &page->flags);
if (ret >= count)
goto err;
--
2.6.3
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v2 2/3] mm, page_owner: provide symbolic page flags and gfp_flags
@ 2015-12-04 15:16 ` Vlastimil Babka
0 siblings, 0 replies; 115+ messages in thread
From: Vlastimil Babka @ 2015-12-04 15:16 UTC (permalink / raw)
To: linux-mm
Cc: linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko,
Vlastimil Babka, Rasmus Villemoes
With the new format strings for flags, we can now 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 of the adjusted format:
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: 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/page_owner.c | 20 +++++---------------
1 file changed, 5 insertions(+), 15 deletions(-)
diff --git a/mm/page_owner.c b/mm/page_owner.c
index 313251f36d86..011377548b4f 100644
--- a/mm/page_owner.c
+++ b/mm/page_owner.c
@@ -135,8 +135,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;
@@ -145,23 +146,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 type %s Block %lu type %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,
migratetype_names[pageblock_mt],
- 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" : " ");
+ page->flags, &page->flags);
if (ret >= count)
goto err;
--
2.6.3
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related [flat|nested] 115+ messages in thread
* [PATCH v2 3/3] mm, debug: move bad flags printing to bad_page()
2015-12-04 15:16 ` Vlastimil Babka
@ 2015-12-04 15:16 ` Vlastimil Babka
-1 siblings, 0 replies; 115+ messages in thread
From: Vlastimil Babka @ 2015-12-04 15:16 UTC (permalink / raw)
To: linux-mm
Cc: linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko,
Vlastimil Babka, Rasmus Villemoes
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 | 14 +++-----------
mm/page_alloc.c | 10 +++++++---
3 files changed, 11 insertions(+), 16 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 c42bb4c13c2d..d36aa66e9779 100644
--- a/mm/debug.c
+++ b/mm/debug.c
@@ -109,25 +109,17 @@ const struct trace_print_flags gfpflag_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)
{
- unsigned long printflags = page->flags;
-
pr_emerg("page:%p count:%d mapcount:%d mapping:%p index:%#lx\n",
page, atomic_read(&page->_count), page_mapcount(page),
page->mapping, page->index);
BUILD_BUG_ON(ARRAY_SIZE(pageflag_names) != __NR_PAGEFLAGS + 1);
- pr_emerg("flags: %#lx(%pgp)\n", printflags, &printflags);
+ pr_emerg("flags: %#lx(%pgp)\n", page->flags, &page->flags);
if (reason)
pr_alert("page dumped because: %s\n", reason);
- if (page->flags & badflags) {
- printflags = page->flags & badflags;
- pr_alert("bad because of flags: %#lx(%pgp)\n", printflags,
- &printflags);
- }
#ifdef CONFIG_MEMCG
if (page->mem_cgroup)
pr_alert("page->mem_cgroup:%p\n", page->mem_cgroup);
@@ -136,7 +128,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 bd94c7465dea..2388496a7c6c 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -435,7 +435,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;
@@ -445,9 +445,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] 115+ messages in thread
* [PATCH v2 3/3] mm, debug: move bad flags printing to bad_page()
@ 2015-12-04 15:16 ` Vlastimil Babka
0 siblings, 0 replies; 115+ messages in thread
From: Vlastimil Babka @ 2015-12-04 15:16 UTC (permalink / raw)
To: linux-mm
Cc: linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko,
Vlastimil Babka, Rasmus Villemoes
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 | 14 +++-----------
mm/page_alloc.c | 10 +++++++---
3 files changed, 11 insertions(+), 16 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 c42bb4c13c2d..d36aa66e9779 100644
--- a/mm/debug.c
+++ b/mm/debug.c
@@ -109,25 +109,17 @@ const struct trace_print_flags gfpflag_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)
{
- unsigned long printflags = page->flags;
-
pr_emerg("page:%p count:%d mapcount:%d mapping:%p index:%#lx\n",
page, atomic_read(&page->_count), page_mapcount(page),
page->mapping, page->index);
BUILD_BUG_ON(ARRAY_SIZE(pageflag_names) != __NR_PAGEFLAGS + 1);
- pr_emerg("flags: %#lx(%pgp)\n", printflags, &printflags);
+ pr_emerg("flags: %#lx(%pgp)\n", page->flags, &page->flags);
if (reason)
pr_alert("page dumped because: %s\n", reason);
- if (page->flags & badflags) {
- printflags = page->flags & badflags;
- pr_alert("bad because of flags: %#lx(%pgp)\n", printflags,
- &printflags);
- }
#ifdef CONFIG_MEMCG
if (page->mem_cgroup)
pr_alert("page->mem_cgroup:%p\n", page->mem_cgroup);
@@ -136,7 +128,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 bd94c7465dea..2388496a7c6c 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -435,7 +435,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;
@@ -445,9 +445,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
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related [flat|nested] 115+ messages in thread
* Re: [PATCH v2 1/3] mm, printk: introduce new format string for flags
2015-12-04 15:16 ` Vlastimil Babka
@ 2015-12-05 20:00 ` Rasmus Villemoes
-1 siblings, 0 replies; 115+ messages in thread
From: Rasmus Villemoes @ 2015-12-05 20:00 UTC (permalink / raw)
To: Vlastimil Babka
Cc: linux-mm, linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko
On Fri, Dec 04 2015, Vlastimil Babka <vbabka@suse.cz> 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).
Hm, with that $subject, I'd expect the patch to touch little beyond
lib/vsprintf.c and Documentation/printk-formats.txt (plus whatever might
be needed to make the name arrays accessible).
> Existing users of dump_flag_names() are converted and simplified.
If you do a respin, please do that part in a separate patch. That would
make it a lot easier to review.
> diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt
> index b784c270105f..8b6ab00fcfc9 100644
> --- a/Documentation/printk-formats.txt
> +++ b/Documentation/printk-formats.txt
> @@ -292,6 +292,20 @@ 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, [g]fp_flags and
> + [v]ma_flags. The flag names and print order depends on the particular
> + type.
> +
> + Passed by reference.
> +
It should probably be emphasized that %pgp and %pgv expect (unsigned
long*), while %pgg expect (gfp_t*), just as you do in vsprintf.c.
> Network device features:
>
> %pNF 0x000000000000c000
> diff --git a/include/linux/mmdebug.h b/include/linux/mmdebug.h
> index 3b77fab7ad28..2c8286cf162e 100644
> --- a/include/linux/mmdebug.h
> +++ b/include/linux/mmdebug.h
> @@ -2,15 +2,20 @@
> #define LINUX_MM_DEBUG_H 1
>
> #include <linux/stringify.h>
> +#include <linux/types.h>
> +#include <linux/tracepoint.h>
>
How much header bloat does it cause by making all users of mmdebug.h
also include tracepoint.h? Couldn't we put the struct definition in
types.h instead?
> 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);
> -extern void dump_gfpflag_names(unsigned long gfp_flags);
> void dump_vma(const struct vm_area_struct *vma);
> void dump_mm(const struct mm_struct *mm);
>
>
> extern int
> diff --git a/lib/vsprintf.c b/lib/vsprintf.c
> index f9cee8e1233c..9a0697b14ea3 100644
> --- a/lib/vsprintf.c
> +++ b/lib/vsprintf.c
> @@ -31,6 +31,7 @@
> #include <linux/dcache.h>
> #include <linux/cred.h>
> #include <net/addrconf.h>
> +#include <linux/mmdebug.h>
>
> #include <asm/page.h> /* for PAGE_SIZE */
> #include <asm/sections.h> /* for dereference_function_descriptor() */
> @@ -1361,6 +1362,73 @@ 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->mask || names->name); names++) {
Why test both ->mask and ->name? I could imagine some constant being
#defined to 0 due to some CONFIG_* (and stuff that tested "flag & THAT"
would then get compiled away), so maybe ->mask is insufficient. But
->name will always be non-NULL for all but the sentinel entry, right?
> + mask = names->mask;
> + if ((flags & mask) != mask)
> + continue;
And if we have some constant which is 0, this will then actually cause
us to print the corresponding string. Do we want that? If not we should
have a "if (!mask) continue;". And how helpful are these strings really
if their meaning might be .config dependent?
> + buf = string(buf, end, names->name, strspec);
So string() is robust against a NULL string (printing the string
"(null)"), but that seems silly to rely on. So I'd strongly lean towards
making the loop condition just test ->name.
> + 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,
> + struct printf_spec spec, const char *fmt)
Even if the user passed a field width (which is extremely unlikely), we
wouldn't honour it, so there's no reason to pass on the spec. But maybe
gcc realizes that.
> +{
> + 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);
> +}
> +
OK.
> int kptr_restrict __read_mostly;
>
> /*
> @@ -1448,6 +1516,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 **
> *
> @@ -1600,6 +1673,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, spec, fmt);
> }
OK.
I looked briefly at the conversions in mm/ and they seemed fine, but
others are more qualified to comment on that part.
Oh, and while I remember, citing from the end of printk-format.txt:
If you add other %p extensions, please extend lib/test_printf.c with
one or more test cases, if at all feasible.
Maybe I shouldn't have put that note at the end :)
Rasmus
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH v2 1/3] mm, printk: introduce new format string for flags
@ 2015-12-05 20:00 ` Rasmus Villemoes
0 siblings, 0 replies; 115+ messages in thread
From: Rasmus Villemoes @ 2015-12-05 20:00 UTC (permalink / raw)
To: Vlastimil Babka
Cc: linux-mm, linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko
On Fri, Dec 04 2015, Vlastimil Babka <vbabka@suse.cz> 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).
Hm, with that $subject, I'd expect the patch to touch little beyond
lib/vsprintf.c and Documentation/printk-formats.txt (plus whatever might
be needed to make the name arrays accessible).
> Existing users of dump_flag_names() are converted and simplified.
If you do a respin, please do that part in a separate patch. That would
make it a lot easier to review.
> diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt
> index b784c270105f..8b6ab00fcfc9 100644
> --- a/Documentation/printk-formats.txt
> +++ b/Documentation/printk-formats.txt
> @@ -292,6 +292,20 @@ 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, [g]fp_flags and
> + [v]ma_flags. The flag names and print order depends on the particular
> + type.
> +
> + Passed by reference.
> +
It should probably be emphasized that %pgp and %pgv expect (unsigned
long*), while %pgg expect (gfp_t*), just as you do in vsprintf.c.
> Network device features:
>
> %pNF 0x000000000000c000
> diff --git a/include/linux/mmdebug.h b/include/linux/mmdebug.h
> index 3b77fab7ad28..2c8286cf162e 100644
> --- a/include/linux/mmdebug.h
> +++ b/include/linux/mmdebug.h
> @@ -2,15 +2,20 @@
> #define LINUX_MM_DEBUG_H 1
>
> #include <linux/stringify.h>
> +#include <linux/types.h>
> +#include <linux/tracepoint.h>
>
How much header bloat does it cause by making all users of mmdebug.h
also include tracepoint.h? Couldn't we put the struct definition in
types.h instead?
> 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);
> -extern void dump_gfpflag_names(unsigned long gfp_flags);
> void dump_vma(const struct vm_area_struct *vma);
> void dump_mm(const struct mm_struct *mm);
>
>
> extern int
> diff --git a/lib/vsprintf.c b/lib/vsprintf.c
> index f9cee8e1233c..9a0697b14ea3 100644
> --- a/lib/vsprintf.c
> +++ b/lib/vsprintf.c
> @@ -31,6 +31,7 @@
> #include <linux/dcache.h>
> #include <linux/cred.h>
> #include <net/addrconf.h>
> +#include <linux/mmdebug.h>
>
> #include <asm/page.h> /* for PAGE_SIZE */
> #include <asm/sections.h> /* for dereference_function_descriptor() */
> @@ -1361,6 +1362,73 @@ 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->mask || names->name); names++) {
Why test both ->mask and ->name? I could imagine some constant being
#defined to 0 due to some CONFIG_* (and stuff that tested "flag & THAT"
would then get compiled away), so maybe ->mask is insufficient. But
->name will always be non-NULL for all but the sentinel entry, right?
> + mask = names->mask;
> + if ((flags & mask) != mask)
> + continue;
And if we have some constant which is 0, this will then actually cause
us to print the corresponding string. Do we want that? If not we should
have a "if (!mask) continue;". And how helpful are these strings really
if their meaning might be .config dependent?
> + buf = string(buf, end, names->name, strspec);
So string() is robust against a NULL string (printing the string
"(null)"), but that seems silly to rely on. So I'd strongly lean towards
making the loop condition just test ->name.
> + 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,
> + struct printf_spec spec, const char *fmt)
Even if the user passed a field width (which is extremely unlikely), we
wouldn't honour it, so there's no reason to pass on the spec. But maybe
gcc realizes that.
> +{
> + 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);
> +}
> +
OK.
> int kptr_restrict __read_mostly;
>
> /*
> @@ -1448,6 +1516,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 **
> *
> @@ -1600,6 +1673,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, spec, fmt);
> }
OK.
I looked briefly at the conversions in mm/ and they seemed fine, but
others are more qualified to comment on that part.
Oh, and while I remember, citing from the end of printk-format.txt:
If you add other %p extensions, please extend lib/test_printf.c with
one or more test cases, if at all feasible.
Maybe I shouldn't have put that note at the end :)
Rasmus
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH v2 1/3] mm, printk: introduce new format string for flags
2015-12-04 15:16 ` Vlastimil Babka
@ 2015-12-09 11:29 ` Arnd Bergmann
-1 siblings, 0 replies; 115+ messages in thread
From: Arnd Bergmann @ 2015-12-09 11:29 UTC (permalink / raw)
To: Vlastimil Babka
Cc: linux-mm, linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko,
Rasmus Villemoes
On Friday 04 December 2015 16:16:33 Vlastimil Babka wrote:
> --- a/include/linux/mmdebug.h
> +++ b/include/linux/mmdebug.h
> @@ -2,15 +2,20 @@
> #define LINUX_MM_DEBUG_H 1
>
> #include <linux/stringify.h>
> +#include <linux/types.h>
> +#include <linux/tracepoint.h>
8<-----
Subject: mm: fix generated/bounds.h
The inclusion of linux/tracepoint.h is causing build errors for me in ARM
randconfig:
In file included from /git/arm-soc/include/linux/ktime.h:25:0,
from /git/arm-soc/include/linux/rcupdate.h:47,
from /git/arm-soc/include/linux/tracepoint.h:19,
from /git/arm-soc/include/linux/mmdebug.h:6,
from /git/arm-soc/include/linux/page-flags.h:10,
from /git/arm-soc/kernel/bounds.c:9:
/git/arm-soc/include/linux/jiffies.h:10:33: fatal error: generated/timeconst.h: No such file or directory
compilation terminated.
To work around this, we can stop including linux/mmdebug.h from linux/page_flags.h
while generating bounds.h, as we do for mm_types.h already.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Fixes: 8c0d593d0f8f ("mm, printk: introduce new format string for flags")
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index 19724e6ebd26..4efad0578a28 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -7,8 +7,8 @@
#include <linux/types.h>
#include <linux/bug.h>
-#include <linux/mmdebug.h>
#ifndef __GENERATING_BOUNDS_H
+#include <linux/mmdebug.h>
#include <linux/mm_types.h>
#include <generated/bounds.h>
#endif /* !__GENERATING_BOUNDS_H */
^ permalink raw reply related [flat|nested] 115+ messages in thread
* Re: [PATCH v2 1/3] mm, printk: introduce new format string for flags
@ 2015-12-09 11:29 ` Arnd Bergmann
0 siblings, 0 replies; 115+ messages in thread
From: Arnd Bergmann @ 2015-12-09 11:29 UTC (permalink / raw)
To: Vlastimil Babka
Cc: linux-mm, linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko,
Rasmus Villemoes
On Friday 04 December 2015 16:16:33 Vlastimil Babka wrote:
> --- a/include/linux/mmdebug.h
> +++ b/include/linux/mmdebug.h
> @@ -2,15 +2,20 @@
> #define LINUX_MM_DEBUG_H 1
>
> #include <linux/stringify.h>
> +#include <linux/types.h>
> +#include <linux/tracepoint.h>
8<-----
Subject: mm: fix generated/bounds.h
The inclusion of linux/tracepoint.h is causing build errors for me in ARM
randconfig:
In file included from /git/arm-soc/include/linux/ktime.h:25:0,
from /git/arm-soc/include/linux/rcupdate.h:47,
from /git/arm-soc/include/linux/tracepoint.h:19,
from /git/arm-soc/include/linux/mmdebug.h:6,
from /git/arm-soc/include/linux/page-flags.h:10,
from /git/arm-soc/kernel/bounds.c:9:
/git/arm-soc/include/linux/jiffies.h:10:33: fatal error: generated/timeconst.h: No such file or directory
compilation terminated.
To work around this, we can stop including linux/mmdebug.h from linux/page_flags.h
while generating bounds.h, as we do for mm_types.h already.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Fixes: 8c0d593d0f8f ("mm, printk: introduce new format string for flags")
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index 19724e6ebd26..4efad0578a28 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -7,8 +7,8 @@
#include <linux/types.h>
#include <linux/bug.h>
-#include <linux/mmdebug.h>
#ifndef __GENERATING_BOUNDS_H
+#include <linux/mmdebug.h>
#include <linux/mm_types.h>
#include <generated/bounds.h>
#endif /* !__GENERATING_BOUNDS_H */
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related [flat|nested] 115+ messages in thread
* Re: [PATCH v2 1/3] mm, printk: introduce new format string for flags
2015-12-09 11:29 ` Arnd Bergmann
@ 2015-12-09 20:48 ` Vlastimil Babka
-1 siblings, 0 replies; 115+ messages in thread
From: Vlastimil Babka @ 2015-12-09 20:48 UTC (permalink / raw)
To: Arnd Bergmann
Cc: linux-mm, linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko,
Rasmus Villemoes, Andi Kleen
On 12/09/2015 12:29 PM, Arnd Bergmann wrote:
> On Friday 04 December 2015 16:16:33 Vlastimil Babka wrote:
>> --- a/include/linux/mmdebug.h
>> +++ b/include/linux/mmdebug.h
>> @@ -2,15 +2,20 @@
>> #define LINUX_MM_DEBUG_H 1
>>
>> #include <linux/stringify.h>
>> +#include <linux/types.h>
>> +#include <linux/tracepoint.h>
>
> 8<-----
> Subject: mm: fix generated/bounds.h
>
> The inclusion of linux/tracepoint.h is causing build errors for me in ARM
> randconfig:
>
> In file included from /git/arm-soc/include/linux/ktime.h:25:0,
> from /git/arm-soc/include/linux/rcupdate.h:47,
> from /git/arm-soc/include/linux/tracepoint.h:19,
> from /git/arm-soc/include/linux/mmdebug.h:6,
> from /git/arm-soc/include/linux/page-flags.h:10,
> from /git/arm-soc/kernel/bounds.c:9:
> /git/arm-soc/include/linux/jiffies.h:10:33: fatal error: generated/timeconst.h: No such file or directory
> compilation terminated.
>
> To work around this, we can stop including linux/mmdebug.h from linux/page_flags.h
> while generating bounds.h, as we do for mm_types.h already.
>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Thanks and sorry. Andrew can you please include it in mmotm as -fix for now?
I plan to respin the whole of this later with some patch splitting and
reordering to reduce churn and follow Rasmus' advice.
Also I've just learned that there's a new lightweight tracepoint-defs.h in -tip
thanks to Andi, which would be a better place for struct trace_print_flags than
tracepoint.h is, so I'll look into using it for the respin, which should make
this temporary -fix redundant.
> Fixes: 8c0d593d0f8f ("mm, printk: introduce new format string for flags")
Note that the linux-next commit id is volatile here (regenerated from quilt series).
>
> diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
> index 19724e6ebd26..4efad0578a28 100644
> --- a/include/linux/page-flags.h
> +++ b/include/linux/page-flags.h
> @@ -7,8 +7,8 @@
>
> #include <linux/types.h>
> #include <linux/bug.h>
> -#include <linux/mmdebug.h>
> #ifndef __GENERATING_BOUNDS_H
> +#include <linux/mmdebug.h>
> #include <linux/mm_types.h>
> #include <generated/bounds.h>
> #endif /* !__GENERATING_BOUNDS_H */
>
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH v2 1/3] mm, printk: introduce new format string for flags
@ 2015-12-09 20:48 ` Vlastimil Babka
0 siblings, 0 replies; 115+ messages in thread
From: Vlastimil Babka @ 2015-12-09 20:48 UTC (permalink / raw)
To: Arnd Bergmann
Cc: linux-mm, linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko,
Rasmus Villemoes, Andi Kleen
On 12/09/2015 12:29 PM, Arnd Bergmann wrote:
> On Friday 04 December 2015 16:16:33 Vlastimil Babka wrote:
>> --- a/include/linux/mmdebug.h
>> +++ b/include/linux/mmdebug.h
>> @@ -2,15 +2,20 @@
>> #define LINUX_MM_DEBUG_H 1
>>
>> #include <linux/stringify.h>
>> +#include <linux/types.h>
>> +#include <linux/tracepoint.h>
>
> 8<-----
> Subject: mm: fix generated/bounds.h
>
> The inclusion of linux/tracepoint.h is causing build errors for me in ARM
> randconfig:
>
> In file included from /git/arm-soc/include/linux/ktime.h:25:0,
> from /git/arm-soc/include/linux/rcupdate.h:47,
> from /git/arm-soc/include/linux/tracepoint.h:19,
> from /git/arm-soc/include/linux/mmdebug.h:6,
> from /git/arm-soc/include/linux/page-flags.h:10,
> from /git/arm-soc/kernel/bounds.c:9:
> /git/arm-soc/include/linux/jiffies.h:10:33: fatal error: generated/timeconst.h: No such file or directory
> compilation terminated.
>
> To work around this, we can stop including linux/mmdebug.h from linux/page_flags.h
> while generating bounds.h, as we do for mm_types.h already.
>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Thanks and sorry. Andrew can you please include it in mmotm as -fix for now?
I plan to respin the whole of this later with some patch splitting and
reordering to reduce churn and follow Rasmus' advice.
Also I've just learned that there's a new lightweight tracepoint-defs.h in -tip
thanks to Andi, which would be a better place for struct trace_print_flags than
tracepoint.h is, so I'll look into using it for the respin, which should make
this temporary -fix redundant.
> Fixes: 8c0d593d0f8f ("mm, printk: introduce new format string for flags")
Note that the linux-next commit id is volatile here (regenerated from quilt series).
>
> diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
> index 19724e6ebd26..4efad0578a28 100644
> --- a/include/linux/page-flags.h
> +++ b/include/linux/page-flags.h
> @@ -7,8 +7,8 @@
>
> #include <linux/types.h>
> #include <linux/bug.h>
> -#include <linux/mmdebug.h>
> #ifndef __GENERATING_BOUNDS_H
> +#include <linux/mmdebug.h>
> #include <linux/mm_types.h>
> #include <generated/bounds.h>
> #endif /* !__GENERATING_BOUNDS_H */
>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH v2 1/3] mm, printk: introduce new format string for flags
2015-12-09 11:29 ` Arnd Bergmann
(?)
@ 2015-12-10 12:26 ` James Hogan
-1 siblings, 0 replies; 115+ messages in thread
From: James Hogan @ 2015-12-10 12:26 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Vlastimil Babka, linux-mm, LKML, Andrew Morton, Joonsoo Kim,
Minchan Kim, Sasha Levin, Kirill A. Shutemov, Mel Gorman,
Michal Hocko, Rasmus Villemoes, metag
On 9 December 2015 at 11:29, Arnd Bergmann <arnd@arndb.de> wrote:
> On Friday 04 December 2015 16:16:33 Vlastimil Babka wrote:
>> --- a/include/linux/mmdebug.h
>> +++ b/include/linux/mmdebug.h
>> @@ -2,15 +2,20 @@
>> #define LINUX_MM_DEBUG_H 1
>>
>> #include <linux/stringify.h>
>> +#include <linux/types.h>
>> +#include <linux/tracepoint.h>
>
> 8<-----
> Subject: mm: fix generated/bounds.h
>
> The inclusion of linux/tracepoint.h is causing build errors for me in ARM
> randconfig:
>
> In file included from /git/arm-soc/include/linux/ktime.h:25:0,
> from /git/arm-soc/include/linux/rcupdate.h:47,
> from /git/arm-soc/include/linux/tracepoint.h:19,
> from /git/arm-soc/include/linux/mmdebug.h:6,
> from /git/arm-soc/include/linux/page-flags.h:10,
> from /git/arm-soc/kernel/bounds.c:9:
> /git/arm-soc/include/linux/jiffies.h:10:33: fatal error: generated/timeconst.h: No such file or directory
> compilation terminated.
>
> To work around this, we can stop including linux/mmdebug.h from linux/page_flags.h
> while generating bounds.h, as we do for mm_types.h already.
>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> Fixes: 8c0d593d0f8f ("mm, printk: introduce new format string for flags")
>
> diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
> index 19724e6ebd26..4efad0578a28 100644
> --- a/include/linux/page-flags.h
> +++ b/include/linux/page-flags.h
> @@ -7,8 +7,8 @@
>
> #include <linux/types.h>
> #include <linux/bug.h>
> -#include <linux/mmdebug.h>
> #ifndef __GENERATING_BOUNDS_H
> +#include <linux/mmdebug.h>
> #include <linux/mm_types.h>
> #include <generated/bounds.h>
> #endif /* !__GENERATING_BOUNDS_H */
Same build issue observed for metag too.
Tested-by: James Hogan <james.hogan@imgtec.com>
Cheers
James
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH v2 1/3] mm, printk: introduce new format string for flags
@ 2015-12-10 12:26 ` James Hogan
0 siblings, 0 replies; 115+ messages in thread
From: James Hogan @ 2015-12-10 12:26 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Vlastimil Babka, linux-mm, LKML, Andrew Morton, Joonsoo Kim,
Minchan Kim, Sasha Levin, Kirill A. Shutemov, Mel Gorman,
Michal Hocko, Rasmus Villemoes, metag
On 9 December 2015 at 11:29, Arnd Bergmann <arnd-r2nGTMty4D4@public.gmane.org> wrote:
> On Friday 04 December 2015 16:16:33 Vlastimil Babka wrote:
>> --- a/include/linux/mmdebug.h
>> +++ b/include/linux/mmdebug.h
>> @@ -2,15 +2,20 @@
>> #define LINUX_MM_DEBUG_H 1
>>
>> #include <linux/stringify.h>
>> +#include <linux/types.h>
>> +#include <linux/tracepoint.h>
>
> 8<-----
> Subject: mm: fix generated/bounds.h
>
> The inclusion of linux/tracepoint.h is causing build errors for me in ARM
> randconfig:
>
> In file included from /git/arm-soc/include/linux/ktime.h:25:0,
> from /git/arm-soc/include/linux/rcupdate.h:47,
> from /git/arm-soc/include/linux/tracepoint.h:19,
> from /git/arm-soc/include/linux/mmdebug.h:6,
> from /git/arm-soc/include/linux/page-flags.h:10,
> from /git/arm-soc/kernel/bounds.c:9:
> /git/arm-soc/include/linux/jiffies.h:10:33: fatal error: generated/timeconst.h: No such file or directory
> compilation terminated.
>
> To work around this, we can stop including linux/mmdebug.h from linux/page_flags.h
> while generating bounds.h, as we do for mm_types.h already.
>
> Signed-off-by: Arnd Bergmann <arnd-r2nGTMty4D4@public.gmane.org>
> Fixes: 8c0d593d0f8f ("mm, printk: introduce new format string for flags")
>
> diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
> index 19724e6ebd26..4efad0578a28 100644
> --- a/include/linux/page-flags.h
> +++ b/include/linux/page-flags.h
> @@ -7,8 +7,8 @@
>
> #include <linux/types.h>
> #include <linux/bug.h>
> -#include <linux/mmdebug.h>
> #ifndef __GENERATING_BOUNDS_H
> +#include <linux/mmdebug.h>
> #include <linux/mm_types.h>
> #include <generated/bounds.h>
> #endif /* !__GENERATING_BOUNDS_H */
Same build issue observed for metag too.
Tested-by: James Hogan <james.hogan-1AXoQHu6uovQT0dZR+AlfA@public.gmane.org>
Cheers
James
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH v2 1/3] mm, printk: introduce new format string for flags
@ 2015-12-10 12:26 ` James Hogan
0 siblings, 0 replies; 115+ messages in thread
From: James Hogan @ 2015-12-10 12:26 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Vlastimil Babka, linux-mm, LKML, Andrew Morton, Joonsoo Kim,
Minchan Kim, Sasha Levin, Kirill A. Shutemov, Mel Gorman,
Michal Hocko, Rasmus Villemoes, metag
On 9 December 2015 at 11:29, Arnd Bergmann <arnd@arndb.de> wrote:
> On Friday 04 December 2015 16:16:33 Vlastimil Babka wrote:
>> --- a/include/linux/mmdebug.h
>> +++ b/include/linux/mmdebug.h
>> @@ -2,15 +2,20 @@
>> #define LINUX_MM_DEBUG_H 1
>>
>> #include <linux/stringify.h>
>> +#include <linux/types.h>
>> +#include <linux/tracepoint.h>
>
> 8<-----
> Subject: mm: fix generated/bounds.h
>
> The inclusion of linux/tracepoint.h is causing build errors for me in ARM
> randconfig:
>
> In file included from /git/arm-soc/include/linux/ktime.h:25:0,
> from /git/arm-soc/include/linux/rcupdate.h:47,
> from /git/arm-soc/include/linux/tracepoint.h:19,
> from /git/arm-soc/include/linux/mmdebug.h:6,
> from /git/arm-soc/include/linux/page-flags.h:10,
> from /git/arm-soc/kernel/bounds.c:9:
> /git/arm-soc/include/linux/jiffies.h:10:33: fatal error: generated/timeconst.h: No such file or directory
> compilation terminated.
>
> To work around this, we can stop including linux/mmdebug.h from linux/page_flags.h
> while generating bounds.h, as we do for mm_types.h already.
>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> Fixes: 8c0d593d0f8f ("mm, printk: introduce new format string for flags")
>
> diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
> index 19724e6ebd26..4efad0578a28 100644
> --- a/include/linux/page-flags.h
> +++ b/include/linux/page-flags.h
> @@ -7,8 +7,8 @@
>
> #include <linux/types.h>
> #include <linux/bug.h>
> -#include <linux/mmdebug.h>
> #ifndef __GENERATING_BOUNDS_H
> +#include <linux/mmdebug.h>
> #include <linux/mm_types.h>
> #include <generated/bounds.h>
> #endif /* !__GENERATING_BOUNDS_H */
Same build issue observed for metag too.
Tested-by: James Hogan <james.hogan@imgtec.com>
Cheers
James
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH v2 1/3] mm, printk: introduce new format string for flags
2015-12-04 15:16 ` Vlastimil Babka
@ 2015-12-10 2:59 ` Joonsoo Kim
-1 siblings, 0 replies; 115+ messages in thread
From: Joonsoo Kim @ 2015-12-10 2:59 UTC (permalink / raw)
To: Vlastimil Babka
Cc: linux-mm, linux-kernel, Andrew Morton, Minchan Kim, Sasha Levin,
Kirill A. Shutemov, Mel Gorman, Michal Hocko, Rasmus Villemoes,
Steven Rostedt
Ccing, Steven to ask trace-cmd problem.
On Fri, Dec 04, 2015 at 04:16:33PM +0100, 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.
I'd like to use %pgp in tracepoint output. It works well when I do
'cat /sys/kernel/debug/tracing/trace' but not works well when I do
'./trace-cmd report'. It prints following error log.
[page_ref:page_ref_unfreeze] bad op token &
[page_ref:page_ref_set] bad op token &
[page_ref:page_ref_mod_unless] bad op token &
[page_ref:page_ref_mod_and_test] bad op token &
[page_ref:page_ref_mod_and_return] bad op token &
[page_ref:page_ref_mod] bad op token &
[page_ref:page_ref_freeze] bad op token &
Following is the format I used.
TP_printk("pfn=0x%lx flags=%pgp count=%d mapcount=%d mapping=%p mt=%d val=%d ret=%d",
__entry->pfn, &__entry->flags, __entry->count,
__entry->mapcount, __entry->mapping, __entry->mt,
__entry->val, __entry->ret)
Could it be solved by 'trace-cmd' itself?
Or it's better to pass flags by value?
Or should I use something like show_gfp_flags()?
Thanks.
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH v2 1/3] mm, printk: introduce new format string for flags
@ 2015-12-10 2:59 ` Joonsoo Kim
0 siblings, 0 replies; 115+ messages in thread
From: Joonsoo Kim @ 2015-12-10 2:59 UTC (permalink / raw)
To: Vlastimil Babka
Cc: linux-mm, linux-kernel, Andrew Morton, Minchan Kim, Sasha Levin,
Kirill A. Shutemov, Mel Gorman, Michal Hocko, Rasmus Villemoes,
Steven Rostedt
Ccing, Steven to ask trace-cmd problem.
On Fri, Dec 04, 2015 at 04:16:33PM +0100, 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.
I'd like to use %pgp in tracepoint output. It works well when I do
'cat /sys/kernel/debug/tracing/trace' but not works well when I do
'./trace-cmd report'. It prints following error log.
[page_ref:page_ref_unfreeze] bad op token &
[page_ref:page_ref_set] bad op token &
[page_ref:page_ref_mod_unless] bad op token &
[page_ref:page_ref_mod_and_test] bad op token &
[page_ref:page_ref_mod_and_return] bad op token &
[page_ref:page_ref_mod] bad op token &
[page_ref:page_ref_freeze] bad op token &
Following is the format I used.
TP_printk("pfn=0x%lx flags=%pgp count=%d mapcount=%d mapping=%p mt=%d val=%d ret=%d",
__entry->pfn, &__entry->flags, __entry->count,
__entry->mapcount, __entry->mapping, __entry->mt,
__entry->val, __entry->ret)
Could it be solved by 'trace-cmd' itself?
Or it's better to pass flags by value?
Or should I use something like show_gfp_flags()?
Thanks.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH v2 1/3] mm, printk: introduce new format string for flags
2015-12-10 2:59 ` Joonsoo Kim
@ 2015-12-10 4:04 ` Steven Rostedt
-1 siblings, 0 replies; 115+ messages in thread
From: Steven Rostedt @ 2015-12-10 4:04 UTC (permalink / raw)
To: Joonsoo Kim
Cc: Vlastimil Babka, linux-mm, linux-kernel, Andrew Morton,
Minchan Kim, Sasha Levin, Kirill A. Shutemov, Mel Gorman,
Michal Hocko, Rasmus Villemoes
On Thu, Dec 10, 2015 at 11:59:44AM +0900, Joonsoo Kim wrote:
> Ccing, Steven to ask trace-cmd problem.
Thanks, I should have been Cc'd for the rest as well.
>
> On Fri, Dec 04, 2015 at 04:16:33PM +0100, 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.
>
> I'd like to use %pgp in tracepoint output. It works well when I do
> 'cat /sys/kernel/debug/tracing/trace' but not works well when I do
> './trace-cmd report'. It prints following error log.
>
> [page_ref:page_ref_unfreeze] bad op token &
> [page_ref:page_ref_set] bad op token &
> [page_ref:page_ref_mod_unless] bad op token &
> [page_ref:page_ref_mod_and_test] bad op token &
> [page_ref:page_ref_mod_and_return] bad op token &
> [page_ref:page_ref_mod] bad op token &
> [page_ref:page_ref_freeze] bad op token &
>
> Following is the format I used.
>
> TP_printk("pfn=0x%lx flags=%pgp count=%d mapcount=%d mapping=%p mt=%d val=%d ret=%d",
> __entry->pfn, &__entry->flags, __entry->count,
> __entry->mapcount, __entry->mapping, __entry->mt,
> __entry->val, __entry->ret)
>
> Could it be solved by 'trace-cmd' itself?
> Or it's better to pass flags by value?
> Or should I use something like show_gfp_flags()?
Yes this can be solved in perf and trace-cmd via the parse-events.c file. And
as soon as that happens, whatever method we decide upon becomes a userspace
ABI. So don't think you can change it later.
-- Steve
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH v2 1/3] mm, printk: introduce new format string for flags
@ 2015-12-10 4:04 ` Steven Rostedt
0 siblings, 0 replies; 115+ messages in thread
From: Steven Rostedt @ 2015-12-10 4:04 UTC (permalink / raw)
To: Joonsoo Kim
Cc: Vlastimil Babka, linux-mm, linux-kernel, Andrew Morton,
Minchan Kim, Sasha Levin, Kirill A. Shutemov, Mel Gorman,
Michal Hocko, Rasmus Villemoes
On Thu, Dec 10, 2015 at 11:59:44AM +0900, Joonsoo Kim wrote:
> Ccing, Steven to ask trace-cmd problem.
Thanks, I should have been Cc'd for the rest as well.
>
> On Fri, Dec 04, 2015 at 04:16:33PM +0100, 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.
>
> I'd like to use %pgp in tracepoint output. It works well when I do
> 'cat /sys/kernel/debug/tracing/trace' but not works well when I do
> './trace-cmd report'. It prints following error log.
>
> [page_ref:page_ref_unfreeze] bad op token &
> [page_ref:page_ref_set] bad op token &
> [page_ref:page_ref_mod_unless] bad op token &
> [page_ref:page_ref_mod_and_test] bad op token &
> [page_ref:page_ref_mod_and_return] bad op token &
> [page_ref:page_ref_mod] bad op token &
> [page_ref:page_ref_freeze] bad op token &
>
> Following is the format I used.
>
> TP_printk("pfn=0x%lx flags=%pgp count=%d mapcount=%d mapping=%p mt=%d val=%d ret=%d",
> __entry->pfn, &__entry->flags, __entry->count,
> __entry->mapcount, __entry->mapping, __entry->mt,
> __entry->val, __entry->ret)
>
> Could it be solved by 'trace-cmd' itself?
> Or it's better to pass flags by value?
> Or should I use something like show_gfp_flags()?
Yes this can be solved in perf and trace-cmd via the parse-events.c file. And
as soon as that happens, whatever method we decide upon becomes a userspace
ABI. So don't think you can change it later.
-- Steve
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH v2 1/3] mm, printk: introduce new format string for flags
2015-12-10 4:04 ` Steven Rostedt
@ 2015-12-10 4:12 ` Joonsoo Kim
-1 siblings, 0 replies; 115+ messages in thread
From: Joonsoo Kim @ 2015-12-10 4:12 UTC (permalink / raw)
To: Steven Rostedt
Cc: Vlastimil Babka, linux-mm, linux-kernel, Andrew Morton,
Minchan Kim, Sasha Levin, Kirill A. Shutemov, Mel Gorman,
Michal Hocko, Rasmus Villemoes
On Wed, Dec 09, 2015 at 11:04:56PM -0500, Steven Rostedt wrote:
> On Thu, Dec 10, 2015 at 11:59:44AM +0900, Joonsoo Kim wrote:
> > Ccing, Steven to ask trace-cmd problem.
>
> Thanks, I should have been Cc'd for the rest as well.
>
> >
> > On Fri, Dec 04, 2015 at 04:16:33PM +0100, 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.
> >
> > I'd like to use %pgp in tracepoint output. It works well when I do
> > 'cat /sys/kernel/debug/tracing/trace' but not works well when I do
> > './trace-cmd report'. It prints following error log.
> >
> > [page_ref:page_ref_unfreeze] bad op token &
> > [page_ref:page_ref_set] bad op token &
> > [page_ref:page_ref_mod_unless] bad op token &
> > [page_ref:page_ref_mod_and_test] bad op token &
> > [page_ref:page_ref_mod_and_return] bad op token &
> > [page_ref:page_ref_mod] bad op token &
> > [page_ref:page_ref_freeze] bad op token &
> >
> > Following is the format I used.
> >
> > TP_printk("pfn=0x%lx flags=%pgp count=%d mapcount=%d mapping=%p mt=%d val=%d ret=%d",
> > __entry->pfn, &__entry->flags, __entry->count,
> > __entry->mapcount, __entry->mapping, __entry->mt,
> > __entry->val, __entry->ret)
> >
> > Could it be solved by 'trace-cmd' itself?
> > Or it's better to pass flags by value?
> > Or should I use something like show_gfp_flags()?
>
> Yes this can be solved in perf and trace-cmd via the parse-events.c file. And
> as soon as that happens, whatever method we decide upon becomes a userspace
> ABI. So don't think you can change it later.
Okay. Because it can be solved by perf and trace-cmd via the
parse-events.c, I have no preference whether it is passed by value or
not.
Thanks.
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH v2 1/3] mm, printk: introduce new format string for flags
@ 2015-12-10 4:12 ` Joonsoo Kim
0 siblings, 0 replies; 115+ messages in thread
From: Joonsoo Kim @ 2015-12-10 4:12 UTC (permalink / raw)
To: Steven Rostedt
Cc: Vlastimil Babka, linux-mm, linux-kernel, Andrew Morton,
Minchan Kim, Sasha Levin, Kirill A. Shutemov, Mel Gorman,
Michal Hocko, Rasmus Villemoes
On Wed, Dec 09, 2015 at 11:04:56PM -0500, Steven Rostedt wrote:
> On Thu, Dec 10, 2015 at 11:59:44AM +0900, Joonsoo Kim wrote:
> > Ccing, Steven to ask trace-cmd problem.
>
> Thanks, I should have been Cc'd for the rest as well.
>
> >
> > On Fri, Dec 04, 2015 at 04:16:33PM +0100, 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.
> >
> > I'd like to use %pgp in tracepoint output. It works well when I do
> > 'cat /sys/kernel/debug/tracing/trace' but not works well when I do
> > './trace-cmd report'. It prints following error log.
> >
> > [page_ref:page_ref_unfreeze] bad op token &
> > [page_ref:page_ref_set] bad op token &
> > [page_ref:page_ref_mod_unless] bad op token &
> > [page_ref:page_ref_mod_and_test] bad op token &
> > [page_ref:page_ref_mod_and_return] bad op token &
> > [page_ref:page_ref_mod] bad op token &
> > [page_ref:page_ref_freeze] bad op token &
> >
> > Following is the format I used.
> >
> > TP_printk("pfn=0x%lx flags=%pgp count=%d mapcount=%d mapping=%p mt=%d val=%d ret=%d",
> > __entry->pfn, &__entry->flags, __entry->count,
> > __entry->mapcount, __entry->mapping, __entry->mt,
> > __entry->val, __entry->ret)
> >
> > Could it be solved by 'trace-cmd' itself?
> > Or it's better to pass flags by value?
> > Or should I use something like show_gfp_flags()?
>
> Yes this can be solved in perf and trace-cmd via the parse-events.c file. And
> as soon as that happens, whatever method we decide upon becomes a userspace
> ABI. So don't think you can change it later.
Okay. Because it can be solved by perf and trace-cmd via the
parse-events.c, I have no preference whether it is passed by value or
not.
Thanks.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH v2 1/3] mm, printk: introduce new format string for flags
2015-12-10 4:04 ` Steven Rostedt
@ 2015-12-10 8:41 ` Rasmus Villemoes
-1 siblings, 0 replies; 115+ messages in thread
From: Rasmus Villemoes @ 2015-12-10 8:41 UTC (permalink / raw)
To: Steven Rostedt
Cc: Joonsoo Kim, Vlastimil Babka, linux-mm, linux-kernel,
Andrew Morton, Minchan Kim, Sasha Levin, Kirill A. Shutemov,
Mel Gorman, Michal Hocko
On Thu, Dec 10 2015, Steven Rostedt <rostedt@goodmis.org> wrote:
> On Thu, Dec 10, 2015 at 11:59:44AM +0900, Joonsoo Kim wrote:
>>
>> [page_ref:page_ref_unfreeze] bad op token &
>> [page_ref:page_ref_set] bad op token &
>> [page_ref:page_ref_mod_unless] bad op token &
>> [page_ref:page_ref_mod_and_test] bad op token &
>> [page_ref:page_ref_mod_and_return] bad op token &
>> [page_ref:page_ref_mod] bad op token &
>> [page_ref:page_ref_freeze] bad op token &
>>
>> Following is the format I used.
>>
>> TP_printk("pfn=0x%lx flags=%pgp count=%d mapcount=%d mapping=%p mt=%d val=%d ret=%d",
>> __entry->pfn, &__entry->flags, __entry->count,
>> __entry->mapcount, __entry->mapping, __entry->mt,
>> __entry->val, __entry->ret)
>>
>> Could it be solved by 'trace-cmd' itself?
>> Or it's better to pass flags by value?
>> Or should I use something like show_gfp_flags()?
>
> Yes this can be solved in perf and trace-cmd via the parse-events.c file. And
> as soon as that happens, whatever method we decide upon becomes a userspace
> ABI. So don't think you can change it later.
So somewhat off-topic, but this reminds me of a question I've been
meaning to ask: What makes it safe to stash the pointer values in
vbin_printf and only dereference them later in bstr_printf? For plain
pointer printing (%p) it's of course not a problem, but quite a few of
the %p extensions do dereference the pointer in one way or another (at
least %p[dD], %p[mM], %p[iI], %ph, %pE, %pC, %pNF, %pU, %pa and probably
soon %pg).
Rasmus
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH v2 1/3] mm, printk: introduce new format string for flags
@ 2015-12-10 8:41 ` Rasmus Villemoes
0 siblings, 0 replies; 115+ messages in thread
From: Rasmus Villemoes @ 2015-12-10 8:41 UTC (permalink / raw)
To: Steven Rostedt
Cc: Joonsoo Kim, Vlastimil Babka, linux-mm, linux-kernel,
Andrew Morton, Minchan Kim, Sasha Levin, Kirill A. Shutemov,
Mel Gorman, Michal Hocko
On Thu, Dec 10 2015, Steven Rostedt <rostedt@goodmis.org> wrote:
> On Thu, Dec 10, 2015 at 11:59:44AM +0900, Joonsoo Kim wrote:
>>
>> [page_ref:page_ref_unfreeze] bad op token &
>> [page_ref:page_ref_set] bad op token &
>> [page_ref:page_ref_mod_unless] bad op token &
>> [page_ref:page_ref_mod_and_test] bad op token &
>> [page_ref:page_ref_mod_and_return] bad op token &
>> [page_ref:page_ref_mod] bad op token &
>> [page_ref:page_ref_freeze] bad op token &
>>
>> Following is the format I used.
>>
>> TP_printk("pfn=0x%lx flags=%pgp count=%d mapcount=%d mapping=%p mt=%d val=%d ret=%d",
>> __entry->pfn, &__entry->flags, __entry->count,
>> __entry->mapcount, __entry->mapping, __entry->mt,
>> __entry->val, __entry->ret)
>>
>> Could it be solved by 'trace-cmd' itself?
>> Or it's better to pass flags by value?
>> Or should I use something like show_gfp_flags()?
>
> Yes this can be solved in perf and trace-cmd via the parse-events.c file. And
> as soon as that happens, whatever method we decide upon becomes a userspace
> ABI. So don't think you can change it later.
So somewhat off-topic, but this reminds me of a question I've been
meaning to ask: What makes it safe to stash the pointer values in
vbin_printf and only dereference them later in bstr_printf? For plain
pointer printing (%p) it's of course not a problem, but quite a few of
the %p extensions do dereference the pointer in one way or another (at
least %p[dD], %p[mM], %p[iI], %ph, %pE, %pC, %pNF, %pU, %pa and probably
soon %pg).
Rasmus
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH v2 1/3] mm, printk: introduce new format string for flags
2015-12-10 4:04 ` Steven Rostedt
@ 2015-12-10 10:03 ` Vlastimil Babka
-1 siblings, 0 replies; 115+ messages in thread
From: Vlastimil Babka @ 2015-12-10 10:03 UTC (permalink / raw)
To: Steven Rostedt, Joonsoo Kim
Cc: linux-mm, linux-kernel, Andrew Morton, Minchan Kim, Sasha Levin,
Kirill A. Shutemov, Mel Gorman, Michal Hocko, Rasmus Villemoes
On 12/10/2015 05:04 AM, Steven Rostedt wrote:
> On Thu, Dec 10, 2015 at 11:59:44AM +0900, Joonsoo Kim wrote:
>> Ccing, Steven to ask trace-cmd problem.
>>
>> I'd like to use %pgp in tracepoint output. It works well when I do
>> 'cat /sys/kernel/debug/tracing/trace' but not works well when I do
>> './trace-cmd report'. It prints following error log.
>>
>> [page_ref:page_ref_unfreeze] bad op token &
>> [page_ref:page_ref_set] bad op token &
>> [page_ref:page_ref_mod_unless] bad op token &
>> [page_ref:page_ref_mod_and_test] bad op token &
>> [page_ref:page_ref_mod_and_return] bad op token &
>> [page_ref:page_ref_mod] bad op token &
>> [page_ref:page_ref_freeze] bad op token &
>>
>> Following is the format I used.
>>
>> TP_printk("pfn=0x%lx flags=%pgp count=%d mapcount=%d mapping=%p mt=%d val=%d ret=%d",
>> __entry->pfn, &__entry->flags, __entry->count,
>> __entry->mapcount, __entry->mapping, __entry->mt,
>> __entry->val, __entry->ret)
>>
>> Could it be solved by 'trace-cmd' itself?
You mean that trace-cmd/parse-events.c would interpret the raw value of
flags by itself? That would mean the flags became fixed ABI, not a good
idea...
>> Or it's better to pass flags by value?
If it's value (as opposed to a pointer in %pgp), that doesn't change
much wrt. having to intepret them?
>> Or should I use something like show_gfp_flags()?
Sounds like least pain to me, at least for now. We just need to have the
translation tables available as #define with __print_flags() in some
trace/events header, like the existing trace/events/gfpflags.h for gfp
flags. These tables can still be reused within mm/debug.c or printk code
without copy/paste, like I did in "[PATCH v2 6/9] mm, debug: introduce
dump_gfpflag_names() for symbolic printing of gfp_flags" [1]. Maybe it's
not the most elegant solution, but works without changing parse-events.c
using the existing format export.
So if you agree, I can do this in the next spin.
[1] https://lkml.org/lkml/2015/11/24/354
> Yes this can be solved in perf and trace-cmd via the parse-events.c file. And
> as soon as that happens, whatever method we decide upon becomes a userspace
> ABI. So don't think you can change it later.
>
> -- Steve
>
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH v2 1/3] mm, printk: introduce new format string for flags
@ 2015-12-10 10:03 ` Vlastimil Babka
0 siblings, 0 replies; 115+ messages in thread
From: Vlastimil Babka @ 2015-12-10 10:03 UTC (permalink / raw)
To: Steven Rostedt, Joonsoo Kim
Cc: linux-mm, linux-kernel, Andrew Morton, Minchan Kim, Sasha Levin,
Kirill A. Shutemov, Mel Gorman, Michal Hocko, Rasmus Villemoes
On 12/10/2015 05:04 AM, Steven Rostedt wrote:
> On Thu, Dec 10, 2015 at 11:59:44AM +0900, Joonsoo Kim wrote:
>> Ccing, Steven to ask trace-cmd problem.
>>
>> I'd like to use %pgp in tracepoint output. It works well when I do
>> 'cat /sys/kernel/debug/tracing/trace' but not works well when I do
>> './trace-cmd report'. It prints following error log.
>>
>> [page_ref:page_ref_unfreeze] bad op token &
>> [page_ref:page_ref_set] bad op token &
>> [page_ref:page_ref_mod_unless] bad op token &
>> [page_ref:page_ref_mod_and_test] bad op token &
>> [page_ref:page_ref_mod_and_return] bad op token &
>> [page_ref:page_ref_mod] bad op token &
>> [page_ref:page_ref_freeze] bad op token &
>>
>> Following is the format I used.
>>
>> TP_printk("pfn=0x%lx flags=%pgp count=%d mapcount=%d mapping=%p mt=%d val=%d ret=%d",
>> __entry->pfn, &__entry->flags, __entry->count,
>> __entry->mapcount, __entry->mapping, __entry->mt,
>> __entry->val, __entry->ret)
>>
>> Could it be solved by 'trace-cmd' itself?
You mean that trace-cmd/parse-events.c would interpret the raw value of
flags by itself? That would mean the flags became fixed ABI, not a good
idea...
>> Or it's better to pass flags by value?
If it's value (as opposed to a pointer in %pgp), that doesn't change
much wrt. having to intepret them?
>> Or should I use something like show_gfp_flags()?
Sounds like least pain to me, at least for now. We just need to have the
translation tables available as #define with __print_flags() in some
trace/events header, like the existing trace/events/gfpflags.h for gfp
flags. These tables can still be reused within mm/debug.c or printk code
without copy/paste, like I did in "[PATCH v2 6/9] mm, debug: introduce
dump_gfpflag_names() for symbolic printing of gfp_flags" [1]. Maybe it's
not the most elegant solution, but works without changing parse-events.c
using the existing format export.
So if you agree, I can do this in the next spin.
[1] https://lkml.org/lkml/2015/11/24/354
> Yes this can be solved in perf and trace-cmd via the parse-events.c file. And
> as soon as that happens, whatever method we decide upon becomes a userspace
> ABI. So don't think you can change it later.
>
> -- Steve
>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH v2 1/3] mm, printk: introduce new format string for flags
2015-12-10 10:03 ` Vlastimil Babka
@ 2015-12-14 3:03 ` Joonsoo Kim
-1 siblings, 0 replies; 115+ messages in thread
From: Joonsoo Kim @ 2015-12-14 3:03 UTC (permalink / raw)
To: Vlastimil Babka
Cc: Steven Rostedt, linux-mm, linux-kernel, Andrew Morton,
Minchan Kim, Sasha Levin, Kirill A. Shutemov, Mel Gorman,
Michal Hocko, Rasmus Villemoes
On Thu, Dec 10, 2015 at 11:03:34AM +0100, Vlastimil Babka wrote:
> On 12/10/2015 05:04 AM, Steven Rostedt wrote:
> >On Thu, Dec 10, 2015 at 11:59:44AM +0900, Joonsoo Kim wrote:
> >>Ccing, Steven to ask trace-cmd problem.
> >>
> >>I'd like to use %pgp in tracepoint output. It works well when I do
> >>'cat /sys/kernel/debug/tracing/trace' but not works well when I do
> >>'./trace-cmd report'. It prints following error log.
> >>
> >> [page_ref:page_ref_unfreeze] bad op token &
> >> [page_ref:page_ref_set] bad op token &
> >> [page_ref:page_ref_mod_unless] bad op token &
> >> [page_ref:page_ref_mod_and_test] bad op token &
> >> [page_ref:page_ref_mod_and_return] bad op token &
> >> [page_ref:page_ref_mod] bad op token &
> >> [page_ref:page_ref_freeze] bad op token &
> >>
> >>Following is the format I used.
> >>
> >>TP_printk("pfn=0x%lx flags=%pgp count=%d mapcount=%d mapping=%p mt=%d val=%d ret=%d",
> >> __entry->pfn, &__entry->flags, __entry->count,
> >> __entry->mapcount, __entry->mapping, __entry->mt,
> >> __entry->val, __entry->ret)
> >>
> >>Could it be solved by 'trace-cmd' itself?
>
> You mean that trace-cmd/parse-events.c would interpret the raw value
> of flags by itself? That would mean the flags became fixed ABI, not
> a good idea...
>
> >>Or it's better to pass flags by value?
>
> If it's value (as opposed to a pointer in %pgp), that doesn't change
> much wrt. having to intepret them?
>
> >>Or should I use something like show_gfp_flags()?
>
> Sounds like least pain to me, at least for now. We just need to have
> the translation tables available as #define with __print_flags() in
> some trace/events header, like the existing trace/events/gfpflags.h
> for gfp flags. These tables can still be reused within mm/debug.c or
> printk code without copy/paste, like I did in "[PATCH v2 6/9] mm,
> debug: introduce dump_gfpflag_names() for symbolic printing of
> gfp_flags" [1]. Maybe it's not the most elegant solution, but works
> without changing parse-events.c using the existing format export.
>
> So if you agree, I can do this in the next spin.
>
Okay. I'm okay with this approach.
Thanks.
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH v2 1/3] mm, printk: introduce new format string for flags
@ 2015-12-14 3:03 ` Joonsoo Kim
0 siblings, 0 replies; 115+ messages in thread
From: Joonsoo Kim @ 2015-12-14 3:03 UTC (permalink / raw)
To: Vlastimil Babka
Cc: Steven Rostedt, linux-mm, linux-kernel, Andrew Morton,
Minchan Kim, Sasha Levin, Kirill A. Shutemov, Mel Gorman,
Michal Hocko, Rasmus Villemoes
On Thu, Dec 10, 2015 at 11:03:34AM +0100, Vlastimil Babka wrote:
> On 12/10/2015 05:04 AM, Steven Rostedt wrote:
> >On Thu, Dec 10, 2015 at 11:59:44AM +0900, Joonsoo Kim wrote:
> >>Ccing, Steven to ask trace-cmd problem.
> >>
> >>I'd like to use %pgp in tracepoint output. It works well when I do
> >>'cat /sys/kernel/debug/tracing/trace' but not works well when I do
> >>'./trace-cmd report'. It prints following error log.
> >>
> >> [page_ref:page_ref_unfreeze] bad op token &
> >> [page_ref:page_ref_set] bad op token &
> >> [page_ref:page_ref_mod_unless] bad op token &
> >> [page_ref:page_ref_mod_and_test] bad op token &
> >> [page_ref:page_ref_mod_and_return] bad op token &
> >> [page_ref:page_ref_mod] bad op token &
> >> [page_ref:page_ref_freeze] bad op token &
> >>
> >>Following is the format I used.
> >>
> >>TP_printk("pfn=0x%lx flags=%pgp count=%d mapcount=%d mapping=%p mt=%d val=%d ret=%d",
> >> __entry->pfn, &__entry->flags, __entry->count,
> >> __entry->mapcount, __entry->mapping, __entry->mt,
> >> __entry->val, __entry->ret)
> >>
> >>Could it be solved by 'trace-cmd' itself?
>
> You mean that trace-cmd/parse-events.c would interpret the raw value
> of flags by itself? That would mean the flags became fixed ABI, not
> a good idea...
>
> >>Or it's better to pass flags by value?
>
> If it's value (as opposed to a pointer in %pgp), that doesn't change
> much wrt. having to intepret them?
>
> >>Or should I use something like show_gfp_flags()?
>
> Sounds like least pain to me, at least for now. We just need to have
> the translation tables available as #define with __print_flags() in
> some trace/events header, like the existing trace/events/gfpflags.h
> for gfp flags. These tables can still be reused within mm/debug.c or
> printk code without copy/paste, like I did in "[PATCH v2 6/9] mm,
> debug: introduce dump_gfpflag_names() for symbolic printing of
> gfp_flags" [1]. Maybe it's not the most elegant solution, but works
> without changing parse-events.c using the existing format export.
>
> So if you agree, I can do this in the next spin.
>
Okay. I'm okay with this approach.
Thanks.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH v2 1/3] mm, printk: introduce new format string for flags
2015-12-04 15:16 ` Vlastimil Babka
@ 2015-12-10 3:51 ` Steven Rostedt
-1 siblings, 0 replies; 115+ messages in thread
From: Steven Rostedt @ 2015-12-10 3:51 UTC (permalink / raw)
To: Vlastimil Babka
Cc: linux-mm, linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko,
Rasmus Villemoes, Ingo Molnar
I should have been Cc'd on this as I'm the maintainer of a few of the files
here that is being modified.
On Fri, Dec 04, 2015 at 04:16:33PM +0100, 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: 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>
> ---
> Should hopefully apply to mmots (release mmotm doesn't have the 3 -fix patches yet?)
>
> Documentation/printk-formats.txt | 14 ++++
> include/linux/mmdebug.h | 7 +-
> include/linux/trace_events.h | 10 ---
> include/linux/tracepoint.h | 10 +++
> lib/vsprintf.c | 75 ++++++++++++++++++++++
> mm/debug.c | 135 ++++++++++++++-------------------------
> mm/oom_kill.c | 5 +-
> mm/page_alloc.c | 5 +-
> mm/page_owner.c | 6 +-
> 9 files changed, 160 insertions(+), 107 deletions(-)
>
> diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt
> index b784c270105f..8b6ab00fcfc9 100644
> --- a/Documentation/printk-formats.txt
> +++ b/Documentation/printk-formats.txt
> @@ -292,6 +292,20 @@ 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, [g]fp_flags and
> + [v]ma_flags. The flag names and print order depends on the particular
> + type.
> +
> + Passed by reference.
> +
> Network device features:
>
> %pNF 0x000000000000c000
> diff --git a/include/linux/mmdebug.h b/include/linux/mmdebug.h
> index 3b77fab7ad28..2c8286cf162e 100644
> --- a/include/linux/mmdebug.h
> +++ b/include/linux/mmdebug.h
> @@ -2,15 +2,20 @@
> #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);
> -extern void dump_gfpflag_names(unsigned long gfp_flags);
> void dump_vma(const struct vm_area_struct *vma);
> void dump_mm(const struct mm_struct *mm);
>
> 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;
> -};
> -
Ingo took some patches from Andi Kleen that creates a tracepoint-defs.h file
If anything, these should be moved there. That code is currently in tip.
-- Steve
> 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.h b/include/linux/tracepoint.h
> index 7834a8a8bf1e..a5d0ab46724d 100644
> --- a/include/linux/tracepoint.h
> +++ b/include/linux/tracepoint.h
> @@ -43,6 +43,16 @@ struct trace_enum_map {
> unsigned long enum_value;
> };
>
> +struct trace_print_flags {
> + unsigned long mask;
> + const char *name;
> +};
> +
> +struct trace_print_flags_u64 {
> + unsigned long long mask;
> + const char *name;
> +};
> +
> #define TRACEPOINT_DEFAULT_PRIO 10
>
> extern int
> diff --git a/lib/vsprintf.c b/lib/vsprintf.c
> index f9cee8e1233c..9a0697b14ea3 100644
> --- a/lib/vsprintf.c
> +++ b/lib/vsprintf.c
> @@ -31,6 +31,7 @@
> #include <linux/dcache.h>
> #include <linux/cred.h>
> #include <net/addrconf.h>
> +#include <linux/mmdebug.h>
>
> #include <asm/page.h> /* for PAGE_SIZE */
> #include <asm/sections.h> /* for dereference_function_descriptor() */
> @@ -1361,6 +1362,73 @@ 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->mask || 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,
> + struct printf_spec spec, 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;
>
> /*
> @@ -1448,6 +1516,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 **
> *
> @@ -1600,6 +1673,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, spec, fmt);
> }
> spec.flags |= SMALL;
> if (spec.field_width == -1) {
> diff --git a/mm/debug.c b/mm/debug.c
> index 9416524839d8..c42bb4c13c2d 100644
> --- a/mm/debug.c
> +++ b/mm/debug.c
> @@ -23,7 +23,7 @@ char *migrate_reason_names[MR_TYPES] = {
> "cma",
> };
>
> -static const struct trace_print_flags pageflag_names[] = {
> +const struct trace_print_flags pageflag_names[] = {
> {1UL << PG_locked, "locked" },
> {1UL << PG_error, "error" },
> {1UL << PG_referenced, "referenced" },
> @@ -57,86 +57,10 @@ static const struct trace_print_flags pageflag_names[] = {
> {1UL << PG_young, "young" },
> {1UL << PG_idle, "idle" },
> #endif
> + {0, NULL },
> };
>
> -static const struct trace_print_flags gfpflag_names[] = {
> - __def_gfpflag_names
> -};
> -
> -static void dump_flag_names(unsigned long flags,
> - const struct trace_print_flags *names, int count)
> -{
> - const char *delim = "";
> - unsigned long mask;
> - int i;
> -
> - pr_cont("(");
> -
> - 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_gfpflag_names(unsigned long gfp_flags)
> -{
> - dump_flag_names(gfp_flags, gfpflag_names, ARRAY_SIZE(gfpflag_names));
> -}
> -
> -void dump_page_badflags(struct page *page, const char *reason,
> - unsigned long badflags)
> -{
> - unsigned long printflags = page->flags;
> -
> - pr_emerg("page:%p count:%d mapcount:%d mapping:%p index:%#lx",
> - page, atomic_read(&page->_count), page_mapcount(page),
> - page->mapping, page->index);
> - if (PageCompound(page))
> - pr_cont(" compound_mapcount: %d", compound_mapcount(page));
> - pr_cont("\n");
> - BUILD_BUG_ON(ARRAY_SIZE(pageflag_names) != __NR_PAGEFLAGS);
> -
> - pr_emerg("flags: %#lx", printflags);
> - /* remove zone id */
> - printflags &= (1UL << NR_PAGEFLAGS) - 1;
> - dump_flag_names(printflags, pageflag_names, ARRAY_SIZE(pageflag_names));
> -
> - if (reason)
> - pr_alert("page dumped because: %s\n", reason);
> - if (page->flags & badflags) {
> - printflags = page->flags & badflags;
> - pr_alert("bad because of flags: %#lx:", printflags);
> - dump_flag_names(printflags, pageflag_names,
> - ARRAY_SIZE(pageflag_names));
> - }
> -#ifdef CONFIG_MEMCG
> - if (page->mem_cgroup)
> - pr_alert("page->mem_cgroup:%p\n", page->mem_cgroup);
> -#endif
> -}
> -
> -void dump_page(struct page *page, const char *reason)
> -{
> - dump_page_badflags(page, reason, 0);
> - dump_page_owner(page);
> -}
> -EXPORT_SYMBOL(dump_page);
> -
> -#ifdef CONFIG_DEBUG_VM
> -
> -static const struct trace_print_flags vmaflags_names[] = {
> +const struct trace_print_flags vmaflag_names[] = {
> {VM_READ, "read" },
> {VM_WRITE, "write" },
> {VM_EXEC, "exec" },
> @@ -177,22 +101,61 @@ static const struct trace_print_flags vmaflags_names[] = {
> {VM_HUGEPAGE, "hugepage" },
> {VM_NOHUGEPAGE, "nohugepage" },
> {VM_MERGEABLE, "mergeable" },
> + {0, NULL },
> +};
> +
> +const struct trace_print_flags gfpflag_names[] = {
> + __def_gfpflag_names,
> + {0, NULL},
> };
>
> +void dump_page_badflags(struct page *page, const char *reason,
> + unsigned long badflags)
> +{
> + unsigned long printflags = page->flags;
> +
> + pr_emerg("page:%p count:%d mapcount:%d mapping:%p index:%#lx\n",
> + page, atomic_read(&page->_count), page_mapcount(page),
> + page->mapping, page->index);
> + BUILD_BUG_ON(ARRAY_SIZE(pageflag_names) != __NR_PAGEFLAGS + 1);
> +
> + pr_emerg("flags: %#lx(%pgp)\n", printflags, &printflags);
> +
> + if (reason)
> + pr_alert("page dumped because: %s\n", reason);
> + if (page->flags & badflags) {
> + printflags = page->flags & badflags;
> + pr_alert("bad because of flags: %#lx(%pgp)\n", printflags,
> + &printflags);
> + }
> +#ifdef CONFIG_MEMCG
> + if (page->mem_cgroup)
> + pr_alert("page->mem_cgroup:%p\n", page->mem_cgroup);
> +#endif
> +}
> +
> +void dump_page(struct page *page, const char *reason)
> +{
> + dump_page_badflags(page, reason, 0);
> + dump_page_owner(page);
> +}
> +EXPORT_SYMBOL(dump_page);
> +
> +#ifdef CONFIG_DEBUG_VM
> +
> 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);
> - pr_emerg("flags: %#lx", vma->vm_flags);
> - dump_flag_names(vma->vm_flags, vmaflags_names,
> - ARRAY_SIZE(vmaflags_names));
> + vma->vm_file, vma->vm_private_data,
> + vma->vm_flags, &vma->vm_flags);
> }
> EXPORT_SYMBOL(dump_vma);
>
> @@ -263,9 +226,7 @@ void dump_mm(const struct mm_struct *mm)
> "" /* This is here to not have a comma! */
> );
>
> - pr_emerg("def_flags: %#lx", mm->def_flags);
> - dump_flag_names(mm->def_flags, vmaflags_names,
> - ARRAY_SIZE(vmaflags_names));
> + pr_emerg("def_flags: %#lx(%pgv)\n", mm->def_flags, &mm->def_flags);
> }
>
> #endif /* CONFIG_DEBUG_VM */
> diff --git a/mm/oom_kill.c b/mm/oom_kill.c
> index 542d56c93209..07bba5a46b47 100644
> --- a/mm/oom_kill.c
> +++ b/mm/oom_kill.c
> @@ -387,10 +387,9 @@ static void dump_header(struct oom_control *oc, struct task_struct *p,
> struct mem_cgroup *memcg)
> {
> pr_warning("%s invoked oom-killer: order=%d, oom_score_adj=%hd, "
> - "gfp_mask=0x%x",
> + "gfp_mask=%#x(%pgg)\n",
> current->comm, oc->order, current->signal->oom_score_adj,
> - oc->gfp_mask);
> - dump_gfpflag_names(oc->gfp_mask);
> + oc->gfp_mask, &oc->gfp_mask);
>
> cpuset_print_current_mems_allowed();
> dump_stack();
> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> index d6d7c97c0b28..bd94c7465dea 100644
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
> @@ -2711,9 +2711,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",
> - current->comm, order, gfp_mask);
> - dump_gfpflag_names(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);
> diff --git a/mm/page_owner.c b/mm/page_owner.c
> index f4acd2452c35..313251f36d86 100644
> --- a/mm/page_owner.c
> +++ b/mm/page_owner.c
> @@ -208,9 +208,9 @@ void __dump_page_owner(struct page *page)
> return;
> }
>
> - pr_alert("page allocated via order %u, migratetype %s, gfp_mask 0x%x",
> - page_ext->order, migratetype_names[mt], gfp_mask);
> - dump_gfpflag_names(gfp_mask);
> + 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)
> --
> 2.6.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH v2 1/3] mm, printk: introduce new format string for flags
@ 2015-12-10 3:51 ` Steven Rostedt
0 siblings, 0 replies; 115+ messages in thread
From: Steven Rostedt @ 2015-12-10 3:51 UTC (permalink / raw)
To: Vlastimil Babka
Cc: linux-mm, linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko,
Rasmus Villemoes, Ingo Molnar
I should have been Cc'd on this as I'm the maintainer of a few of the files
here that is being modified.
On Fri, Dec 04, 2015 at 04:16:33PM +0100, 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: 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>
> ---
> Should hopefully apply to mmots (release mmotm doesn't have the 3 -fix patches yet?)
>
> Documentation/printk-formats.txt | 14 ++++
> include/linux/mmdebug.h | 7 +-
> include/linux/trace_events.h | 10 ---
> include/linux/tracepoint.h | 10 +++
> lib/vsprintf.c | 75 ++++++++++++++++++++++
> mm/debug.c | 135 ++++++++++++++-------------------------
> mm/oom_kill.c | 5 +-
> mm/page_alloc.c | 5 +-
> mm/page_owner.c | 6 +-
> 9 files changed, 160 insertions(+), 107 deletions(-)
>
> diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt
> index b784c270105f..8b6ab00fcfc9 100644
> --- a/Documentation/printk-formats.txt
> +++ b/Documentation/printk-formats.txt
> @@ -292,6 +292,20 @@ 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, [g]fp_flags and
> + [v]ma_flags. The flag names and print order depends on the particular
> + type.
> +
> + Passed by reference.
> +
> Network device features:
>
> %pNF 0x000000000000c000
> diff --git a/include/linux/mmdebug.h b/include/linux/mmdebug.h
> index 3b77fab7ad28..2c8286cf162e 100644
> --- a/include/linux/mmdebug.h
> +++ b/include/linux/mmdebug.h
> @@ -2,15 +2,20 @@
> #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);
> -extern void dump_gfpflag_names(unsigned long gfp_flags);
> void dump_vma(const struct vm_area_struct *vma);
> void dump_mm(const struct mm_struct *mm);
>
> 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;
> -};
> -
Ingo took some patches from Andi Kleen that creates a tracepoint-defs.h file
If anything, these should be moved there. That code is currently in tip.
-- Steve
> 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.h b/include/linux/tracepoint.h
> index 7834a8a8bf1e..a5d0ab46724d 100644
> --- a/include/linux/tracepoint.h
> +++ b/include/linux/tracepoint.h
> @@ -43,6 +43,16 @@ struct trace_enum_map {
> unsigned long enum_value;
> };
>
> +struct trace_print_flags {
> + unsigned long mask;
> + const char *name;
> +};
> +
> +struct trace_print_flags_u64 {
> + unsigned long long mask;
> + const char *name;
> +};
> +
> #define TRACEPOINT_DEFAULT_PRIO 10
>
> extern int
> diff --git a/lib/vsprintf.c b/lib/vsprintf.c
> index f9cee8e1233c..9a0697b14ea3 100644
> --- a/lib/vsprintf.c
> +++ b/lib/vsprintf.c
> @@ -31,6 +31,7 @@
> #include <linux/dcache.h>
> #include <linux/cred.h>
> #include <net/addrconf.h>
> +#include <linux/mmdebug.h>
>
> #include <asm/page.h> /* for PAGE_SIZE */
> #include <asm/sections.h> /* for dereference_function_descriptor() */
> @@ -1361,6 +1362,73 @@ 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->mask || 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,
> + struct printf_spec spec, 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;
>
> /*
> @@ -1448,6 +1516,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 **
> *
> @@ -1600,6 +1673,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, spec, fmt);
> }
> spec.flags |= SMALL;
> if (spec.field_width == -1) {
> diff --git a/mm/debug.c b/mm/debug.c
> index 9416524839d8..c42bb4c13c2d 100644
> --- a/mm/debug.c
> +++ b/mm/debug.c
> @@ -23,7 +23,7 @@ char *migrate_reason_names[MR_TYPES] = {
> "cma",
> };
>
> -static const struct trace_print_flags pageflag_names[] = {
> +const struct trace_print_flags pageflag_names[] = {
> {1UL << PG_locked, "locked" },
> {1UL << PG_error, "error" },
> {1UL << PG_referenced, "referenced" },
> @@ -57,86 +57,10 @@ static const struct trace_print_flags pageflag_names[] = {
> {1UL << PG_young, "young" },
> {1UL << PG_idle, "idle" },
> #endif
> + {0, NULL },
> };
>
> -static const struct trace_print_flags gfpflag_names[] = {
> - __def_gfpflag_names
> -};
> -
> -static void dump_flag_names(unsigned long flags,
> - const struct trace_print_flags *names, int count)
> -{
> - const char *delim = "";
> - unsigned long mask;
> - int i;
> -
> - pr_cont("(");
> -
> - 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_gfpflag_names(unsigned long gfp_flags)
> -{
> - dump_flag_names(gfp_flags, gfpflag_names, ARRAY_SIZE(gfpflag_names));
> -}
> -
> -void dump_page_badflags(struct page *page, const char *reason,
> - unsigned long badflags)
> -{
> - unsigned long printflags = page->flags;
> -
> - pr_emerg("page:%p count:%d mapcount:%d mapping:%p index:%#lx",
> - page, atomic_read(&page->_count), page_mapcount(page),
> - page->mapping, page->index);
> - if (PageCompound(page))
> - pr_cont(" compound_mapcount: %d", compound_mapcount(page));
> - pr_cont("\n");
> - BUILD_BUG_ON(ARRAY_SIZE(pageflag_names) != __NR_PAGEFLAGS);
> -
> - pr_emerg("flags: %#lx", printflags);
> - /* remove zone id */
> - printflags &= (1UL << NR_PAGEFLAGS) - 1;
> - dump_flag_names(printflags, pageflag_names, ARRAY_SIZE(pageflag_names));
> -
> - if (reason)
> - pr_alert("page dumped because: %s\n", reason);
> - if (page->flags & badflags) {
> - printflags = page->flags & badflags;
> - pr_alert("bad because of flags: %#lx:", printflags);
> - dump_flag_names(printflags, pageflag_names,
> - ARRAY_SIZE(pageflag_names));
> - }
> -#ifdef CONFIG_MEMCG
> - if (page->mem_cgroup)
> - pr_alert("page->mem_cgroup:%p\n", page->mem_cgroup);
> -#endif
> -}
> -
> -void dump_page(struct page *page, const char *reason)
> -{
> - dump_page_badflags(page, reason, 0);
> - dump_page_owner(page);
> -}
> -EXPORT_SYMBOL(dump_page);
> -
> -#ifdef CONFIG_DEBUG_VM
> -
> -static const struct trace_print_flags vmaflags_names[] = {
> +const struct trace_print_flags vmaflag_names[] = {
> {VM_READ, "read" },
> {VM_WRITE, "write" },
> {VM_EXEC, "exec" },
> @@ -177,22 +101,61 @@ static const struct trace_print_flags vmaflags_names[] = {
> {VM_HUGEPAGE, "hugepage" },
> {VM_NOHUGEPAGE, "nohugepage" },
> {VM_MERGEABLE, "mergeable" },
> + {0, NULL },
> +};
> +
> +const struct trace_print_flags gfpflag_names[] = {
> + __def_gfpflag_names,
> + {0, NULL},
> };
>
> +void dump_page_badflags(struct page *page, const char *reason,
> + unsigned long badflags)
> +{
> + unsigned long printflags = page->flags;
> +
> + pr_emerg("page:%p count:%d mapcount:%d mapping:%p index:%#lx\n",
> + page, atomic_read(&page->_count), page_mapcount(page),
> + page->mapping, page->index);
> + BUILD_BUG_ON(ARRAY_SIZE(pageflag_names) != __NR_PAGEFLAGS + 1);
> +
> + pr_emerg("flags: %#lx(%pgp)\n", printflags, &printflags);
> +
> + if (reason)
> + pr_alert("page dumped because: %s\n", reason);
> + if (page->flags & badflags) {
> + printflags = page->flags & badflags;
> + pr_alert("bad because of flags: %#lx(%pgp)\n", printflags,
> + &printflags);
> + }
> +#ifdef CONFIG_MEMCG
> + if (page->mem_cgroup)
> + pr_alert("page->mem_cgroup:%p\n", page->mem_cgroup);
> +#endif
> +}
> +
> +void dump_page(struct page *page, const char *reason)
> +{
> + dump_page_badflags(page, reason, 0);
> + dump_page_owner(page);
> +}
> +EXPORT_SYMBOL(dump_page);
> +
> +#ifdef CONFIG_DEBUG_VM
> +
> 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);
> - pr_emerg("flags: %#lx", vma->vm_flags);
> - dump_flag_names(vma->vm_flags, vmaflags_names,
> - ARRAY_SIZE(vmaflags_names));
> + vma->vm_file, vma->vm_private_data,
> + vma->vm_flags, &vma->vm_flags);
> }
> EXPORT_SYMBOL(dump_vma);
>
> @@ -263,9 +226,7 @@ void dump_mm(const struct mm_struct *mm)
> "" /* This is here to not have a comma! */
> );
>
> - pr_emerg("def_flags: %#lx", mm->def_flags);
> - dump_flag_names(mm->def_flags, vmaflags_names,
> - ARRAY_SIZE(vmaflags_names));
> + pr_emerg("def_flags: %#lx(%pgv)\n", mm->def_flags, &mm->def_flags);
> }
>
> #endif /* CONFIG_DEBUG_VM */
> diff --git a/mm/oom_kill.c b/mm/oom_kill.c
> index 542d56c93209..07bba5a46b47 100644
> --- a/mm/oom_kill.c
> +++ b/mm/oom_kill.c
> @@ -387,10 +387,9 @@ static void dump_header(struct oom_control *oc, struct task_struct *p,
> struct mem_cgroup *memcg)
> {
> pr_warning("%s invoked oom-killer: order=%d, oom_score_adj=%hd, "
> - "gfp_mask=0x%x",
> + "gfp_mask=%#x(%pgg)\n",
> current->comm, oc->order, current->signal->oom_score_adj,
> - oc->gfp_mask);
> - dump_gfpflag_names(oc->gfp_mask);
> + oc->gfp_mask, &oc->gfp_mask);
>
> cpuset_print_current_mems_allowed();
> dump_stack();
> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> index d6d7c97c0b28..bd94c7465dea 100644
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
> @@ -2711,9 +2711,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",
> - current->comm, order, gfp_mask);
> - dump_gfpflag_names(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);
> diff --git a/mm/page_owner.c b/mm/page_owner.c
> index f4acd2452c35..313251f36d86 100644
> --- a/mm/page_owner.c
> +++ b/mm/page_owner.c
> @@ -208,9 +208,9 @@ void __dump_page_owner(struct page *page)
> return;
> }
>
> - pr_alert("page allocated via order %u, migratetype %s, gfp_mask 0x%x",
> - page_ext->order, migratetype_names[mt], gfp_mask);
> - dump_gfpflag_names(gfp_mask);
> + 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)
> --
> 2.6.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH v2 1/3] mm, printk: introduce new format string for flags
2015-12-10 3:51 ` Steven Rostedt
@ 2015-12-10 9:51 ` Vlastimil Babka
-1 siblings, 0 replies; 115+ messages in thread
From: Vlastimil Babka @ 2015-12-10 9:51 UTC (permalink / raw)
To: Steven Rostedt
Cc: linux-mm, linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko,
Rasmus Villemoes, Ingo Molnar
On 12/10/2015 04:51 AM, Steven Rostedt wrote:
> I should have been Cc'd on this as I'm the maintainer of a few of the files
> here that is being modified.
Sorry about that.
>> --- 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;
>> -};
>> -
>
> Ingo took some patches from Andi Kleen that creates a tracepoint-defs.h file
> If anything, these should be moved there. That code is currently in tip.
Yeah I noticed that yesterday and seems like a good idea. Rasmus
suggested types.h but these didn't seem general enough for that one. Thanks.
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH v2 1/3] mm, printk: introduce new format string for flags
@ 2015-12-10 9:51 ` Vlastimil Babka
0 siblings, 0 replies; 115+ messages in thread
From: Vlastimil Babka @ 2015-12-10 9:51 UTC (permalink / raw)
To: Steven Rostedt
Cc: linux-mm, linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko,
Rasmus Villemoes, Ingo Molnar
On 12/10/2015 04:51 AM, Steven Rostedt wrote:
> I should have been Cc'd on this as I'm the maintainer of a few of the files
> here that is being modified.
Sorry about that.
>> --- 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;
>> -};
>> -
>
> Ingo took some patches from Andi Kleen that creates a tracepoint-defs.h file
> If anything, these should be moved there. That code is currently in tip.
Yeah I noticed that yesterday and seems like a good idea. Rasmus
suggested types.h but these didn't seem general enough for that one. Thanks.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH 1/2] mm, printk: introduce new format string for flags
2015-11-30 16:10 ` Vlastimil Babka
@ 2015-12-02 17:40 ` yalin wang
-1 siblings, 0 replies; 115+ messages in thread
From: yalin wang @ 2015-12-02 17:40 UTC (permalink / raw)
To: Vlastimil Babka
Cc: linux-mm, linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko,
Rasmus Villemoes
> On Nov 30, 2015, at 08:10, Vlastimil Babka <vbabka@suse.cz> 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.
>
> Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
> Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk>
> ---
> I'm sending it on top of the page_owner series, as it's already in mmotm.
> But to reduce churn (in case this approach is accepted), I can later
> incorporate it and resend it whole.
>
> Documentation/printk-formats.txt | 14 ++++
> include/linux/mmdebug.h | 5 +-
> lib/vsprintf.c | 31 ++++++++
> mm/debug.c | 150 ++++++++++++++++++++++-----------------
> mm/oom_kill.c | 5 +-
> mm/page_alloc.c | 5 +-
> mm/page_owner.c | 5 +-
> 7 files changed, 140 insertions(+), 75 deletions(-)
>
> diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt
> index b784c270105f..4b5156e74b09 100644
> --- a/Documentation/printk-formats.txt
> +++ b/Documentation/printk-formats.txt
> @@ -292,6 +292,20 @@ Raw pointer value SHOULD be printed with %p. The kernel supports
>
> Passed by reference.
>
> +Flags bitfields such as page flags, gfp_flags:
> +
> + %pgp 0x1fffff8000086c(referenced|uptodate|lru|active|private)
> + %pgg 0x24202c4(GFP_USER|GFP_DMA32|GFP_NOWARN)
> + %pgv 0x875(read|exec|mayread|maywrite|mayexec|denywrite)
> +
> + For printing raw values of flags bitfields together with symbolic
> + strings that would construct the value. The type of flags is given by
> + the third character. Currently supported are [p]age flags, [g]fp_flags
> + and [v]ma_flags. The flag names and print order depends on the
> + particular type.
> +
> + Passed by reference.
> +
> Network device features:
>
> %pNF 0x000000000000c000
> diff --git a/include/linux/mmdebug.h b/include/linux/mmdebug.h
> index 3b77fab7ad28..e6518df259ca 100644
> --- a/include/linux/mmdebug.h
> +++ b/include/linux/mmdebug.h
> @@ -2,6 +2,7 @@
> #define LINUX_MM_DEBUG_H 1
>
> #include <linux/stringify.h>
> +#include <linux/types.h>
>
> struct page;
> struct vm_area_struct;
> @@ -10,7 +11,9 @@ struct mm_struct;
> 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_gfpflag_names(unsigned long gfp_flags);
> +extern char *format_page_flags(unsigned long flags, char *buf, char *end);
> +extern char *format_vma_flags(unsigned long flags, char *buf, char *end);
> +extern char *format_gfp_flags(gfp_t gfp_flags, char *buf, char*end);
> void dump_vma(const struct vm_area_struct *vma);
> void dump_mm(const struct mm_struct *mm);
>
> diff --git a/lib/vsprintf.c b/lib/vsprintf.c
> index f9cee8e1233c..41cd122bd307 100644
> --- a/lib/vsprintf.c
> +++ b/lib/vsprintf.c
> @@ -31,6 +31,7 @@
> #include <linux/dcache.h>
> #include <linux/cred.h>
> #include <net/addrconf.h>
> +#include <linux/mmdebug.h>
>
> #include <asm/page.h> /* for PAGE_SIZE */
> #include <asm/sections.h> /* for dereference_function_descriptor() */
> @@ -1361,6 +1362,29 @@ char *clock(char *buf, char *end, struct clk *clk, struct printf_spec spec,
> }
> }
>
> +static noinline_for_stack
> +char *flags_string(char *buf, char *end, void *flags_ptr,
> + struct printf_spec spec, const char *fmt)
> +{
> + unsigned long flags;
> + gfp_t gfp_flags;
> +
> + switch (fmt[1]) {
> + case 'p':
> + flags = *(unsigned long *)flags_ptr;
> + return format_page_flags(flags, buf, end);
> + case 'v':
> + flags = *(unsigned long *)flags_ptr;
> + return format_vma_flags(flags, buf, end);
> + case 'g':
> + gfp_flags = *(gfp_t *)flags_ptr;
> + return format_gfp_flags(gfp_flags, buf, end);
> + default:
> + WARN_ONCE(1, "Unsupported flags modifier: %c\n", fmt[1]);
> + return 0;
> + }
> +}
> +
> int kptr_restrict __read_mostly;
>
> /*
> @@ -1448,6 +1472,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 **
> *
> @@ -1600,6 +1629,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, spec, fmt);
> }
> spec.flags |= SMALL;
> if (spec.field_width == -1) {
> diff --git a/mm/debug.c b/mm/debug.c
> index 2fdf0999e6f9..a092111920e7 100644
> --- a/mm/debug.c
> +++ b/mm/debug.c
> @@ -59,40 +59,109 @@ static const struct trace_print_flags pageflag_names[] = {
> #endif
> };
>
> +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 gfpflag_names[] = {
> __def_gfpflag_names
> };
>
> -static void dump_flag_names(unsigned long flags,
> - const struct trace_print_flags *names, int count)
> +static char *format_flag_names(unsigned long flags, unsigned long mask_out,
> + const struct trace_print_flags *names, int count,
> + char *buf, char *end)
> {
> const char *delim = "";
> unsigned long mask;
> int i;
>
> - pr_cont("(");
> + buf += snprintf(buf, end - buf, "%#lx(", flags);
> +
> + flags &= ~mask_out;
>
> for (i = 0; i < count && flags; i++) {
> + if (buf >= end)
> + break;
>
> mask = names[i].mask;
> if ((flags & mask) != mask)
> continue;
>
> flags &= ~mask;
> - pr_cont("%s%s", delim, names[i].name);
> + buf += snprintf(buf, end - buf, "%s%s", delim, names[i].name);
> delim = "|";
> }
>
> /* check for left over flags */
> - if (flags)
> - pr_cont("%s%#lx", delim, flags);
> + if (flags && (buf < end))
> + buf += snprintf(buf, end - buf, "%s%#lx", delim, flags);
> +
> + if (buf < end) {
> + *buf = ')';
> + buf++;
> + }
>
> - pr_cont(")\n");
> + return buf;
> }
>
> -void dump_gfpflag_names(unsigned long gfp_flags)
> +char *format_page_flags(unsigned long flags, char *buf, char *end)
> {
> - dump_flag_names(gfp_flags, gfpflag_names, ARRAY_SIZE(gfpflag_names));
> + /* remove zone id */
> + unsigned long mask = (1UL << NR_PAGEFLAGS) - 1;
> +
> + return format_flag_names(flags, ~mask, pageflag_names,
> + ARRAY_SIZE(pageflag_names), buf, end);
> +}
> +
> +char *format_vma_flags(unsigned long flags, char *buf, char *end)
> +{
> + return format_flag_names(flags, 0, vmaflags_names,
> + ARRAY_SIZE(vmaflags_names), buf, end);
> +}
> +
> +char *format_gfp_flags(gfp_t gfp_flags, char *buf, char *end)
> +{
> + return format_flag_names(gfp_flags, 0, gfpflag_names,
> + ARRAY_SIZE(gfpflag_names), buf, end);
> }
>
> void dump_page_badflags(struct page *page, const char *reason,
> @@ -108,18 +177,15 @@ void dump_page_badflags(struct page *page, const char *reason,
> pr_cont("\n");
> BUILD_BUG_ON(ARRAY_SIZE(pageflag_names) != __NR_PAGEFLAGS);
>
> - pr_emerg("flags: %#lx", printflags);
> + pr_emerg("flags: %pgp\n", &printflags);
> /* remove zone id */
> printflags &= (1UL << NR_PAGEFLAGS) - 1;
> - dump_flag_names(printflags, pageflag_names, ARRAY_SIZE(pageflag_names));
>
> if (reason)
> pr_alert("page dumped because: %s\n", reason);
> if (page->flags & badflags) {
> printflags = page->flags & badflags;
> - pr_alert("bad because of flags: %#lx:", printflags);
> - dump_flag_names(printflags, pageflag_names,
> - ARRAY_SIZE(pageflag_names));
> + pr_alert("bad because of flags: %pgp\n", &printflags);
> }
> #ifdef CONFIG_MEMCG
> if (page->mem_cgroup)
> @@ -136,63 +202,19 @@ 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" },
> -};
> -
> 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: %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);
> - pr_emerg("flags: %#lx", vma->vm_flags);
> - dump_flag_names(vma->vm_flags, vmaflags_names,
> - ARRAY_SIZE(vmaflags_names));
> + vma->vm_file, vma->vm_private_data,
> + &vma->vm_flags);
> }
> EXPORT_SYMBOL(dump_vma);
>
> @@ -263,9 +285,7 @@ void dump_mm(const struct mm_struct *mm)
> "" /* This is here to not have a comma! */
> );
>
> - pr_emerg("def_flags: %#lx", mm->def_flags);
> - dump_flag_names(mm->def_flags, vmaflags_names,
> - ARRAY_SIZE(vmaflags_names));
> + pr_emerg("def_flags: %pgv\n", &mm->def_flags);
> }
>
> #endif /* CONFIG_DEBUG_VM */
> diff --git a/mm/oom_kill.c b/mm/oom_kill.c
> index 542d56c93209..63a68b62ee68 100644
> --- a/mm/oom_kill.c
> +++ b/mm/oom_kill.c
> @@ -387,10 +387,9 @@ static void dump_header(struct oom_control *oc, struct task_struct *p,
> struct mem_cgroup *memcg)
> {
> pr_warning("%s invoked oom-killer: order=%d, oom_score_adj=%hd, "
> - "gfp_mask=0x%x",
> + "gfp_mask=%pgg\n",
> current->comm, oc->order, current->signal->oom_score_adj,
> - oc->gfp_mask);
> - dump_gfpflag_names(oc->gfp_mask);
> + &oc->gfp_mask);
>
> cpuset_print_current_mems_allowed();
> dump_stack();
> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> index 80349acd8c17..77d2c75f80e4 100644
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
> @@ -2711,9 +2711,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",
> - current->comm, order, gfp_mask);
> - dump_gfpflag_names(gfp_mask);
> + pr_warn("%s: page allocation failure: order:%u, mode:%pgg\n",
> + current->comm, order, &gfp_mask);
> dump_stack();
> if (!should_suppress_show_mem())
> show_mem(filter);
> diff --git a/mm/page_owner.c b/mm/page_owner.c
> index f4acd2452c35..ff862b6d12da 100644
> --- a/mm/page_owner.c
> +++ b/mm/page_owner.c
> @@ -208,9 +208,8 @@ void __dump_page_owner(struct page *page)
> return;
> }
>
> - pr_alert("page allocated via order %u, migratetype %s, gfp_mask 0x%x",
> - page_ext->order, migratetype_names[mt], gfp_mask);
> - dump_gfpflag_names(gfp_mask);
> + pr_alert("page allocated via order %u, migratetype %s, gfp_mask %pgg\n",
> + page_ext->order, migratetype_names[mt], &gfp_mask);
> print_stack_trace(&trace, 0);
>
> if (page_ext->last_migrate_reason != -1)
> --
> 2.6.3
>
i am thinking why not make %pg* to be more generic ?
not restricted to only GFP / vma flags / page flags .
so could we change format like this ?
define a flag spec struct to include flag and trace_print_flags and some other option :
typedef struct {
unsigned long flag;
struct trace_print_flags *flags;
unsigned long option; } flag_sec;
flag_sec my_flag;
in printk we only pass like this :
printk(“%pg\n”, &my_flag) ;
then it can print any flags defined by user .
more useful for other drivers to use .
Thanks
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH 1/2] mm, printk: introduce new format string for flags
@ 2015-12-02 17:40 ` yalin wang
0 siblings, 0 replies; 115+ messages in thread
From: yalin wang @ 2015-12-02 17:40 UTC (permalink / raw)
To: Vlastimil Babka
Cc: linux-mm, linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko,
Rasmus Villemoes
> On Nov 30, 2015, at 08:10, Vlastimil Babka <vbabka@suse.cz> 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.
>
> Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
> Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk>
> ---
> I'm sending it on top of the page_owner series, as it's already in mmotm.
> But to reduce churn (in case this approach is accepted), I can later
> incorporate it and resend it whole.
>
> Documentation/printk-formats.txt | 14 ++++
> include/linux/mmdebug.h | 5 +-
> lib/vsprintf.c | 31 ++++++++
> mm/debug.c | 150 ++++++++++++++++++++++-----------------
> mm/oom_kill.c | 5 +-
> mm/page_alloc.c | 5 +-
> mm/page_owner.c | 5 +-
> 7 files changed, 140 insertions(+), 75 deletions(-)
>
> diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt
> index b784c270105f..4b5156e74b09 100644
> --- a/Documentation/printk-formats.txt
> +++ b/Documentation/printk-formats.txt
> @@ -292,6 +292,20 @@ Raw pointer value SHOULD be printed with %p. The kernel supports
>
> Passed by reference.
>
> +Flags bitfields such as page flags, gfp_flags:
> +
> + %pgp 0x1fffff8000086c(referenced|uptodate|lru|active|private)
> + %pgg 0x24202c4(GFP_USER|GFP_DMA32|GFP_NOWARN)
> + %pgv 0x875(read|exec|mayread|maywrite|mayexec|denywrite)
> +
> + For printing raw values of flags bitfields together with symbolic
> + strings that would construct the value. The type of flags is given by
> + the third character. Currently supported are [p]age flags, [g]fp_flags
> + and [v]ma_flags. The flag names and print order depends on the
> + particular type.
> +
> + Passed by reference.
> +
> Network device features:
>
> %pNF 0x000000000000c000
> diff --git a/include/linux/mmdebug.h b/include/linux/mmdebug.h
> index 3b77fab7ad28..e6518df259ca 100644
> --- a/include/linux/mmdebug.h
> +++ b/include/linux/mmdebug.h
> @@ -2,6 +2,7 @@
> #define LINUX_MM_DEBUG_H 1
>
> #include <linux/stringify.h>
> +#include <linux/types.h>
>
> struct page;
> struct vm_area_struct;
> @@ -10,7 +11,9 @@ struct mm_struct;
> 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_gfpflag_names(unsigned long gfp_flags);
> +extern char *format_page_flags(unsigned long flags, char *buf, char *end);
> +extern char *format_vma_flags(unsigned long flags, char *buf, char *end);
> +extern char *format_gfp_flags(gfp_t gfp_flags, char *buf, char*end);
> void dump_vma(const struct vm_area_struct *vma);
> void dump_mm(const struct mm_struct *mm);
>
> diff --git a/lib/vsprintf.c b/lib/vsprintf.c
> index f9cee8e1233c..41cd122bd307 100644
> --- a/lib/vsprintf.c
> +++ b/lib/vsprintf.c
> @@ -31,6 +31,7 @@
> #include <linux/dcache.h>
> #include <linux/cred.h>
> #include <net/addrconf.h>
> +#include <linux/mmdebug.h>
>
> #include <asm/page.h> /* for PAGE_SIZE */
> #include <asm/sections.h> /* for dereference_function_descriptor() */
> @@ -1361,6 +1362,29 @@ char *clock(char *buf, char *end, struct clk *clk, struct printf_spec spec,
> }
> }
>
> +static noinline_for_stack
> +char *flags_string(char *buf, char *end, void *flags_ptr,
> + struct printf_spec spec, const char *fmt)
> +{
> + unsigned long flags;
> + gfp_t gfp_flags;
> +
> + switch (fmt[1]) {
> + case 'p':
> + flags = *(unsigned long *)flags_ptr;
> + return format_page_flags(flags, buf, end);
> + case 'v':
> + flags = *(unsigned long *)flags_ptr;
> + return format_vma_flags(flags, buf, end);
> + case 'g':
> + gfp_flags = *(gfp_t *)flags_ptr;
> + return format_gfp_flags(gfp_flags, buf, end);
> + default:
> + WARN_ONCE(1, "Unsupported flags modifier: %c\n", fmt[1]);
> + return 0;
> + }
> +}
> +
> int kptr_restrict __read_mostly;
>
> /*
> @@ -1448,6 +1472,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 **
> *
> @@ -1600,6 +1629,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, spec, fmt);
> }
> spec.flags |= SMALL;
> if (spec.field_width == -1) {
> diff --git a/mm/debug.c b/mm/debug.c
> index 2fdf0999e6f9..a092111920e7 100644
> --- a/mm/debug.c
> +++ b/mm/debug.c
> @@ -59,40 +59,109 @@ static const struct trace_print_flags pageflag_names[] = {
> #endif
> };
>
> +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 gfpflag_names[] = {
> __def_gfpflag_names
> };
>
> -static void dump_flag_names(unsigned long flags,
> - const struct trace_print_flags *names, int count)
> +static char *format_flag_names(unsigned long flags, unsigned long mask_out,
> + const struct trace_print_flags *names, int count,
> + char *buf, char *end)
> {
> const char *delim = "";
> unsigned long mask;
> int i;
>
> - pr_cont("(");
> + buf += snprintf(buf, end - buf, "%#lx(", flags);
> +
> + flags &= ~mask_out;
>
> for (i = 0; i < count && flags; i++) {
> + if (buf >= end)
> + break;
>
> mask = names[i].mask;
> if ((flags & mask) != mask)
> continue;
>
> flags &= ~mask;
> - pr_cont("%s%s", delim, names[i].name);
> + buf += snprintf(buf, end - buf, "%s%s", delim, names[i].name);
> delim = "|";
> }
>
> /* check for left over flags */
> - if (flags)
> - pr_cont("%s%#lx", delim, flags);
> + if (flags && (buf < end))
> + buf += snprintf(buf, end - buf, "%s%#lx", delim, flags);
> +
> + if (buf < end) {
> + *buf = ')';
> + buf++;
> + }
>
> - pr_cont(")\n");
> + return buf;
> }
>
> -void dump_gfpflag_names(unsigned long gfp_flags)
> +char *format_page_flags(unsigned long flags, char *buf, char *end)
> {
> - dump_flag_names(gfp_flags, gfpflag_names, ARRAY_SIZE(gfpflag_names));
> + /* remove zone id */
> + unsigned long mask = (1UL << NR_PAGEFLAGS) - 1;
> +
> + return format_flag_names(flags, ~mask, pageflag_names,
> + ARRAY_SIZE(pageflag_names), buf, end);
> +}
> +
> +char *format_vma_flags(unsigned long flags, char *buf, char *end)
> +{
> + return format_flag_names(flags, 0, vmaflags_names,
> + ARRAY_SIZE(vmaflags_names), buf, end);
> +}
> +
> +char *format_gfp_flags(gfp_t gfp_flags, char *buf, char *end)
> +{
> + return format_flag_names(gfp_flags, 0, gfpflag_names,
> + ARRAY_SIZE(gfpflag_names), buf, end);
> }
>
> void dump_page_badflags(struct page *page, const char *reason,
> @@ -108,18 +177,15 @@ void dump_page_badflags(struct page *page, const char *reason,
> pr_cont("\n");
> BUILD_BUG_ON(ARRAY_SIZE(pageflag_names) != __NR_PAGEFLAGS);
>
> - pr_emerg("flags: %#lx", printflags);
> + pr_emerg("flags: %pgp\n", &printflags);
> /* remove zone id */
> printflags &= (1UL << NR_PAGEFLAGS) - 1;
> - dump_flag_names(printflags, pageflag_names, ARRAY_SIZE(pageflag_names));
>
> if (reason)
> pr_alert("page dumped because: %s\n", reason);
> if (page->flags & badflags) {
> printflags = page->flags & badflags;
> - pr_alert("bad because of flags: %#lx:", printflags);
> - dump_flag_names(printflags, pageflag_names,
> - ARRAY_SIZE(pageflag_names));
> + pr_alert("bad because of flags: %pgp\n", &printflags);
> }
> #ifdef CONFIG_MEMCG
> if (page->mem_cgroup)
> @@ -136,63 +202,19 @@ 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" },
> -};
> -
> 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: %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);
> - pr_emerg("flags: %#lx", vma->vm_flags);
> - dump_flag_names(vma->vm_flags, vmaflags_names,
> - ARRAY_SIZE(vmaflags_names));
> + vma->vm_file, vma->vm_private_data,
> + &vma->vm_flags);
> }
> EXPORT_SYMBOL(dump_vma);
>
> @@ -263,9 +285,7 @@ void dump_mm(const struct mm_struct *mm)
> "" /* This is here to not have a comma! */
> );
>
> - pr_emerg("def_flags: %#lx", mm->def_flags);
> - dump_flag_names(mm->def_flags, vmaflags_names,
> - ARRAY_SIZE(vmaflags_names));
> + pr_emerg("def_flags: %pgv\n", &mm->def_flags);
> }
>
> #endif /* CONFIG_DEBUG_VM */
> diff --git a/mm/oom_kill.c b/mm/oom_kill.c
> index 542d56c93209..63a68b62ee68 100644
> --- a/mm/oom_kill.c
> +++ b/mm/oom_kill.c
> @@ -387,10 +387,9 @@ static void dump_header(struct oom_control *oc, struct task_struct *p,
> struct mem_cgroup *memcg)
> {
> pr_warning("%s invoked oom-killer: order=%d, oom_score_adj=%hd, "
> - "gfp_mask=0x%x",
> + "gfp_mask=%pgg\n",
> current->comm, oc->order, current->signal->oom_score_adj,
> - oc->gfp_mask);
> - dump_gfpflag_names(oc->gfp_mask);
> + &oc->gfp_mask);
>
> cpuset_print_current_mems_allowed();
> dump_stack();
> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> index 80349acd8c17..77d2c75f80e4 100644
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
> @@ -2711,9 +2711,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",
> - current->comm, order, gfp_mask);
> - dump_gfpflag_names(gfp_mask);
> + pr_warn("%s: page allocation failure: order:%u, mode:%pgg\n",
> + current->comm, order, &gfp_mask);
> dump_stack();
> if (!should_suppress_show_mem())
> show_mem(filter);
> diff --git a/mm/page_owner.c b/mm/page_owner.c
> index f4acd2452c35..ff862b6d12da 100644
> --- a/mm/page_owner.c
> +++ b/mm/page_owner.c
> @@ -208,9 +208,8 @@ void __dump_page_owner(struct page *page)
> return;
> }
>
> - pr_alert("page allocated via order %u, migratetype %s, gfp_mask 0x%x",
> - page_ext->order, migratetype_names[mt], gfp_mask);
> - dump_gfpflag_names(gfp_mask);
> + pr_alert("page allocated via order %u, migratetype %s, gfp_mask %pgg\n",
> + page_ext->order, migratetype_names[mt], &gfp_mask);
> print_stack_trace(&trace, 0);
>
> if (page_ext->last_migrate_reason != -1)
> --
> 2.6.3
>
i am thinking why not make %pg* to be more generic ?
not restricted to only GFP / vma flags / page flags .
so could we change format like this ?
define a flag spec struct to include flag and trace_print_flags and some other option :
typedef struct {
unsigned long flag;
struct trace_print_flags *flags;
unsigned long option; } flag_sec;
flag_sec my_flag;
in printk we only pass like this :
printk(“%pg\n”, &my_flag) ;
then it can print any flags defined by user .
more useful for other drivers to use .
Thanks
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH 1/2] mm, printk: introduce new format string for flags
2015-12-02 17:40 ` yalin wang
@ 2015-12-02 21:04 ` Vlastimil Babka
-1 siblings, 0 replies; 115+ messages in thread
From: Vlastimil Babka @ 2015-12-02 21:04 UTC (permalink / raw)
To: yalin wang
Cc: linux-mm, linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko,
Rasmus Villemoes
On 12/02/2015 06:40 PM, yalin wang wrote:
(please trim your reply next time, no need to quote whole patch here)
> i am thinking why not make %pg* to be more generic ?
> not restricted to only GFP / vma flags / page flags .
> so could we change format like this ?
> define a flag spec struct to include flag and trace_print_flags and some other option :
> typedef struct {
> unsigned long flag;
> struct trace_print_flags *flags;
> unsigned long option; } flag_sec;
> flag_sec my_flag;
> in printk we only pass like this :
> printk(“%pg\n”, &my_flag) ;
> then it can print any flags defined by user .
> more useful for other drivers to use .
I don't know, it sounds quite complicated given that we had no flags printing
for years and now there's just three kinds of them. The extra struct flag_sec is
IMHO nuissance. No other printk format needs such thing AFAIK? For example, if I
were to print page flags from several places, each would have to define the
struct flag_sec instance, or some header would have to provide it?
I could maybe accept passing a flag value and trace_print_flags * as two
separate parameters, but I guess that breaks an ancient invariant of one
parameter per format string...
> Thanks
>
>
>
>
>
>
>
>
>
>
>
>
>
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH 1/2] mm, printk: introduce new format string for flags
@ 2015-12-02 21:04 ` Vlastimil Babka
0 siblings, 0 replies; 115+ messages in thread
From: Vlastimil Babka @ 2015-12-02 21:04 UTC (permalink / raw)
To: yalin wang
Cc: linux-mm, linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko,
Rasmus Villemoes
On 12/02/2015 06:40 PM, yalin wang wrote:
(please trim your reply next time, no need to quote whole patch here)
> i am thinking why not make %pg* to be more generic ?
> not restricted to only GFP / vma flags / page flags .
> so could we change format like this ?
> define a flag spec struct to include flag and trace_print_flags and some other option :
> typedef struct {
> unsigned long flag;
> struct trace_print_flags *flags;
> unsigned long option; } flag_sec;
> flag_sec my_flag;
> in printk we only pass like this :
> printk(a??%pg\na??, &my_flag) ;
> then it can print any flags defined by user .
> more useful for other drivers to use .
I don't know, it sounds quite complicated given that we had no flags printing
for years and now there's just three kinds of them. The extra struct flag_sec is
IMHO nuissance. No other printk format needs such thing AFAIK? For example, if I
were to print page flags from several places, each would have to define the
struct flag_sec instance, or some header would have to provide it?
I could maybe accept passing a flag value and trace_print_flags * as two
separate parameters, but I guess that breaks an ancient invariant of one
parameter per format string...
> Thanks
>
>
>
>
>
>
>
>
>
>
>
>
>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH 1/2] mm, printk: introduce new format string for flags
2015-12-02 21:04 ` Vlastimil Babka
@ 2015-12-03 0:11 ` yalin wang
-1 siblings, 0 replies; 115+ messages in thread
From: yalin wang @ 2015-12-03 0:11 UTC (permalink / raw)
To: Vlastimil Babka
Cc: open list:MEMORY MANAGEMENT, linux-kernel, Andrew Morton,
Joonsoo Kim, Minchan Kim, Sasha Levin, Kirill A. Shutemov,
Mel Gorman, Michal Hocko, Rasmus Villemoes
> On Dec 2, 2015, at 13:04, Vlastimil Babka <vbabka@suse.cz> wrote:
>
> On 12/02/2015 06:40 PM, yalin wang wrote:
>
> (please trim your reply next time, no need to quote whole patch here)
>
>> i am thinking why not make %pg* to be more generic ?
>> not restricted to only GFP / vma flags / page flags .
>> so could we change format like this ?
>> define a flag spec struct to include flag and trace_print_flags and some other option :
>> typedef struct {
>> unsigned long flag;
>> structtrace_print_flags *flags;
>> unsigned long option; } flag_sec;
>> flag_sec my_flag;
>> in printk we only pass like this :
>> printk(“%pg\n”, &my_flag) ;
>> then it can print any flags defined by user .
>> more useful for other drivers to use .
>
> I don't know, it sounds quite complicated given that we had no flags printing
> for years and now there's just three kinds of them. The extra struct flag_sec is
> IMHO nuissance. No other printk format needs such thing AFAIK? For example, if I
> were to print page flags from several places, each would have to define the
> struct flag_sec instance, or some header would have to provide it?
this can be avoided by provide a macro in header file .
we can add a new struct to declare trace_print_flags :
for example:
#define DECLARE_FLAG_PRINTK_FMT(name, flags_array) flag_spec name = { .flags = flags_array};
#define FLAG_PRINTK_FMT(name, flag) ({ name.flag = flag; &name})
in source code :
DECLARE_FLAG_PRINTK_FMT(my_flag, vmaflags_names);
printk(“%pg\n”, FLAG_PRINTK_FMT(my_flag, vma->flag));
i am not if DECLARE_FLAG_PRINTK_FMT and FLAG_PRINTK_FMT macro
can be defined into one macro ?
maybe need some trick here .
is it possible ?
Thanks
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH 1/2] mm, printk: introduce new format string for flags
@ 2015-12-03 0:11 ` yalin wang
0 siblings, 0 replies; 115+ messages in thread
From: yalin wang @ 2015-12-03 0:11 UTC (permalink / raw)
To: Vlastimil Babka
Cc: open list:MEMORY MANAGEMENT, linux-kernel, Andrew Morton,
Joonsoo Kim, Minchan Kim, Sasha Levin, Kirill A. Shutemov,
Mel Gorman, Michal Hocko, Rasmus Villemoes
> On Dec 2, 2015, at 13:04, Vlastimil Babka <vbabka@suse.cz> wrote:
>
> On 12/02/2015 06:40 PM, yalin wang wrote:
>
> (please trim your reply next time, no need to quote whole patch here)
>
>> i am thinking why not make %pg* to be more generic ?
>> not restricted to only GFP / vma flags / page flags .
>> so could we change format like this ?
>> define a flag spec struct to include flag and trace_print_flags and some other option :
>> typedef struct {
>> unsigned long flag;
>> structtrace_print_flags *flags;
>> unsigned long option; } flag_sec;
>> flag_sec my_flag;
>> in printk we only pass like this :
>> printk(“%pg\n”, &my_flag) ;
>> then it can print any flags defined by user .
>> more useful for other drivers to use .
>
> I don't know, it sounds quite complicated given that we had no flags printing
> for years and now there's just three kinds of them. The extra struct flag_sec is
> IMHO nuissance. No other printk format needs such thing AFAIK? For example, if I
> were to print page flags from several places, each would have to define the
> struct flag_sec instance, or some header would have to provide it?
this can be avoided by provide a macro in header file .
we can add a new struct to declare trace_print_flags :
for example:
#define DECLARE_FLAG_PRINTK_FMT(name, flags_array) flag_spec name = { .flags = flags_array};
#define FLAG_PRINTK_FMT(name, flag) ({ name.flag = flag; &name})
in source code :
DECLARE_FLAG_PRINTK_FMT(my_flag, vmaflags_names);
printk(“%pg\n”, FLAG_PRINTK_FMT(my_flag, vma->flag));
i am not if DECLARE_FLAG_PRINTK_FMT and FLAG_PRINTK_FMT macro
can be defined into one macro ?
maybe need some trick here .
is it possible ?
Thanks
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH 1/2] mm, printk: introduce new format string for flags
2015-12-03 0:11 ` yalin wang
@ 2015-12-03 8:03 ` Rasmus Villemoes
-1 siblings, 0 replies; 115+ messages in thread
From: Rasmus Villemoes @ 2015-12-03 8:03 UTC (permalink / raw)
To: yalin wang
Cc: Vlastimil Babka, open list:MEMORY MANAGEMENT, linux-kernel,
Andrew Morton, Joonsoo Kim, Minchan Kim, Sasha Levin,
Kirill A. Shutemov, Mel Gorman, Michal Hocko
On Thu, Dec 03 2015, yalin wang <yalin.wang2010@gmail.com> wrote:
>> On Dec 2, 2015, at 13:04, Vlastimil Babka <vbabka@suse.cz> wrote:
>>
>> On 12/02/2015 06:40 PM, yalin wang wrote:
>>
>> (please trim your reply next time, no need to quote whole patch here)
>>
>>> i am thinking why not make %pg* to be more generic ?
>>> not restricted to only GFP / vma flags / page flags .
>>> so could we change format like this ?
>>> define a flag spec struct to include flag and trace_print_flags and some other option :
>>> typedef struct {
>>> unsigned long flag;
>>> structtrace_print_flags *flags;
>>> unsigned long option; } flag_sec;
>>> flag_sec my_flag;
>>> in printk we only pass like this :
>>> printk(“%pg\n”, &my_flag) ;
>>> then it can print any flags defined by user .
>>> more useful for other drivers to use .
>>
>> I don't know, it sounds quite complicated
Agreed, I think this would be premature generalization. There's also
some value in having the individual %pgX specifiers, as that allows
individual tweaks such as the mask_out for page flags.
given that we had no flags printing
>> for years and now there's just three kinds of them. The extra struct flag_sec is
>> IMHO nuissance. No other printk format needs such thing AFAIK? For example, if I
>> were to print page flags from several places, each would have to define the
>> struct flag_sec instance, or some header would have to provide it?
> this can be avoided by provide a macro in header file .
> we can add a new struct to declare trace_print_flags :
> for example:
> #define DECLARE_FLAG_PRINTK_FMT(name, flags_array) flag_spec name = { .flags = flags_array};
> #define FLAG_PRINTK_FMT(name, flag) ({ name.flag = flag; &name})
>
> in source code :
> DECLARE_FLAG_PRINTK_FMT(my_flag, vmaflags_names);
> printk(“%pg\n”, FLAG_PRINTK_FMT(my_flag, vma->flag));
>
Compared to printk("%pgv\n", &vma->flag), I know which I'd prefer to read.
> i am not if DECLARE_FLAG_PRINTK_FMT and FLAG_PRINTK_FMT macro
> can be defined into one macro ?
> maybe need some trick here .
>
> is it possible ?
Technically, I think the answer is yes, at least in C99 (and I suppose
gcc would accept it in gnu89 mode as well).
printk("%pg\n", &(struct flag_printer){.flags = my_flags, .names = vmaflags_names});
Not tested, and I still don't think it would be particularly readable
even when macroized
printk("%pg\n", PRINTF_VMAFLAGS(my_flags));
Rasmus
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH 1/2] mm, printk: introduce new format string for flags
@ 2015-12-03 8:03 ` Rasmus Villemoes
0 siblings, 0 replies; 115+ messages in thread
From: Rasmus Villemoes @ 2015-12-03 8:03 UTC (permalink / raw)
To: yalin wang
Cc: Vlastimil Babka, open list:MEMORY MANAGEMENT, linux-kernel,
Andrew Morton, Joonsoo Kim, Minchan Kim, Sasha Levin,
Kirill A. Shutemov, Mel Gorman, Michal Hocko
On Thu, Dec 03 2015, yalin wang <yalin.wang2010@gmail.com> wrote:
>> On Dec 2, 2015, at 13:04, Vlastimil Babka <vbabka@suse.cz> wrote:
>>
>> On 12/02/2015 06:40 PM, yalin wang wrote:
>>
>> (please trim your reply next time, no need to quote whole patch here)
>>
>>> i am thinking why not make %pg* to be more generic ?
>>> not restricted to only GFP / vma flags / page flags .
>>> so could we change format like this ?
>>> define a flag spec struct to include flag and trace_print_flags and some other option :
>>> typedef struct {
>>> unsigned long flag;
>>> structtrace_print_flags *flags;
>>> unsigned long option; } flag_sec;
>>> flag_sec my_flag;
>>> in printk we only pass like this :
>>> printk(“%pg\n”, &my_flag) ;
>>> then it can print any flags defined by user .
>>> more useful for other drivers to use .
>>
>> I don't know, it sounds quite complicated
Agreed, I think this would be premature generalization. There's also
some value in having the individual %pgX specifiers, as that allows
individual tweaks such as the mask_out for page flags.
given that we had no flags printing
>> for years and now there's just three kinds of them. The extra struct flag_sec is
>> IMHO nuissance. No other printk format needs such thing AFAIK? For example, if I
>> were to print page flags from several places, each would have to define the
>> struct flag_sec instance, or some header would have to provide it?
> this can be avoided by provide a macro in header file .
> we can add a new struct to declare trace_print_flags :
> for example:
> #define DECLARE_FLAG_PRINTK_FMT(name, flags_array) flag_spec name = { .flags = flags_array};
> #define FLAG_PRINTK_FMT(name, flag) ({ name.flag = flag; &name})
>
> in source code :
> DECLARE_FLAG_PRINTK_FMT(my_flag, vmaflags_names);
> printk(“%pg\n”, FLAG_PRINTK_FMT(my_flag, vma->flag));
>
Compared to printk("%pgv\n", &vma->flag), I know which I'd prefer to read.
> i am not if DECLARE_FLAG_PRINTK_FMT and FLAG_PRINTK_FMT macro
> can be defined into one macro ?
> maybe need some trick here .
>
> is it possible ?
Technically, I think the answer is yes, at least in C99 (and I suppose
gcc would accept it in gnu89 mode as well).
printk("%pg\n", &(struct flag_printer){.flags = my_flags, .names = vmaflags_names});
Not tested, and I still don't think it would be particularly readable
even when macroized
printk("%pg\n", PRINTF_VMAFLAGS(my_flags));
Rasmus
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH 1/2] mm, printk: introduce new format string for flags
2015-12-03 8:03 ` Rasmus Villemoes
@ 2015-12-03 18:38 ` yalin wang
-1 siblings, 0 replies; 115+ messages in thread
From: yalin wang @ 2015-12-03 18:38 UTC (permalink / raw)
To: Rasmus Villemoes
Cc: Vlastimil Babka, open list:MEMORY MANAGEMENT, linux-kernel,
Andrew Morton, Joonsoo Kim, Minchan Kim, Sasha Levin,
Kirill A. Shutemov, Mel Gorman, Michal Hocko
> On Dec 3, 2015, at 00:03, Rasmus Villemoes <linux@rasmusvillemoes.dk> wrote:
>
> On Thu, Dec 03 2015, yalin wang <yalin.wang2010@gmail.com> wrote:
>
>>> On Dec 2, 2015, at 13:04, Vlastimil Babka <vbabka@suse.cz> wrote:
>>>
>>> On 12/02/2015 06:40 PM, yalin wang wrote:
>>>
>>> (please trim your reply next time, no need to quote whole patch here)
>>>
>>>> i am thinking why not make %pg* to be more generic ?
>>>> not restricted to only GFP / vma flags / page flags .
>>>> so could we change format like this ?
>>>> define a flag spec struct to include flag and trace_print_flags and some other option :
>>>> typedef struct {
>>>> unsigned long flag;
>>>> structtrace_print_flags *flags;
>>>> unsigned long option; } flag_sec;
>>>> flag_sec my_flag;
>>>> in printk we only pass like this :
>>>> printk(“%pg\n”, &my_flag) ;
>>>> then it can print any flags defined by user .
>>>> more useful for other drivers to use .
>>>
>>> I don't know, it sounds quite complicated
>
> Agreed, I think this would be premature generalization. There's also
> some value in having the individual %pgX specifiers, as that allows
> individual tweaks such as the mask_out for page flags.
>
> given that we had no flags printing
>>
if we use this generic method, %pgX where X can be used to specify some flag to
mask out some thing . it will be great .
>
> Compared to printk("%pgv\n", &vma->flag), I know which I'd prefer to read.
>
>> i am not if DECLARE_FLAG_PRINTK_FMT and FLAG_PRINTK_FMT macro
>> can be defined into one macro ?
>> maybe need some trick here .
>>
>> is it possible ?
>
> Technically, I think the answer is yes, at least in C99 (and I suppose
> gcc would accept it in gnu89 mode as well).
>
> printk("%pg\n", &(struct flag_printer){.flags = my_flags, .names = vmaflags_names});
>
> Not tested, and I still don't think it would be particularly readable
> even when macroized
>
> printk("%pg\n", PRINTF_VMAFLAGS(my_flags));
i test on gcc 4.9.3, it can work for this method,
so the final solution like this:
printk.h:
struct flag_fmt_spec {
unsigned long flag;
struct trace_print_flags *flags;
int array_size;
char delimiter; }
#define FLAG_FORMAT(flag, flag_array, delimiter) (&(struct flag_ft_spec){ .flag = flag, .flags = flag_array, .array_size = ARRAY_SIZE(flag_array), .delimiter = delimiter})
#define VMA_FLAG_FORMAT(flag) FLAG_FORMAT(flag, vmaflags_names, ‘|')
source code:
printk("%pg\n", VMA_FLAG_FORMAT(my_flags));
that’s all, see cpumask_pr_args(masks) macro,
it also use macro and %*pb to print cpu mask .
i think this method is not very complex to use .
search source code ,
there is lots of printk to print flag into hex number :
$ grep -n -r 'printk.*flag.*%x’ .
it will be great if this flag string print is generic.
Thanks
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH 1/2] mm, printk: introduce new format string for flags
@ 2015-12-03 18:38 ` yalin wang
0 siblings, 0 replies; 115+ messages in thread
From: yalin wang @ 2015-12-03 18:38 UTC (permalink / raw)
To: Rasmus Villemoes
Cc: Vlastimil Babka, open list:MEMORY MANAGEMENT, linux-kernel,
Andrew Morton, Joonsoo Kim, Minchan Kim, Sasha Levin,
Kirill A. Shutemov, Mel Gorman, Michal Hocko
> On Dec 3, 2015, at 00:03, Rasmus Villemoes <linux@rasmusvillemoes.dk> wrote:
>
> On Thu, Dec 03 2015, yalin wang <yalin.wang2010@gmail.com> wrote:
>
>>> On Dec 2, 2015, at 13:04, Vlastimil Babka <vbabka@suse.cz> wrote:
>>>
>>> On 12/02/2015 06:40 PM, yalin wang wrote:
>>>
>>> (please trim your reply next time, no need to quote whole patch here)
>>>
>>>> i am thinking why not make %pg* to be more generic ?
>>>> not restricted to only GFP / vma flags / page flags .
>>>> so could we change format like this ?
>>>> define a flag spec struct to include flag and trace_print_flags and some other option :
>>>> typedef struct {
>>>> unsigned long flag;
>>>> structtrace_print_flags *flags;
>>>> unsigned long option; } flag_sec;
>>>> flag_sec my_flag;
>>>> in printk we only pass like this :
>>>> printk(“%pg\n”, &my_flag) ;
>>>> then it can print any flags defined by user .
>>>> more useful for other drivers to use .
>>>
>>> I don't know, it sounds quite complicated
>
> Agreed, I think this would be premature generalization. There's also
> some value in having the individual %pgX specifiers, as that allows
> individual tweaks such as the mask_out for page flags.
>
> given that we had no flags printing
>>
if we use this generic method, %pgX where X can be used to specify some flag to
mask out some thing . it will be great .
>
> Compared to printk("%pgv\n", &vma->flag), I know which I'd prefer to read.
>
>> i am not if DECLARE_FLAG_PRINTK_FMT and FLAG_PRINTK_FMT macro
>> can be defined into one macro ?
>> maybe need some trick here .
>>
>> is it possible ?
>
> Technically, I think the answer is yes, at least in C99 (and I suppose
> gcc would accept it in gnu89 mode as well).
>
> printk("%pg\n", &(struct flag_printer){.flags = my_flags, .names = vmaflags_names});
>
> Not tested, and I still don't think it would be particularly readable
> even when macroized
>
> printk("%pg\n", PRINTF_VMAFLAGS(my_flags));
i test on gcc 4.9.3, it can work for this method,
so the final solution like this:
printk.h:
struct flag_fmt_spec {
unsigned long flag;
struct trace_print_flags *flags;
int array_size;
char delimiter; }
#define FLAG_FORMAT(flag, flag_array, delimiter) (&(struct flag_ft_spec){ .flag = flag, .flags = flag_array, .array_size = ARRAY_SIZE(flag_array), .delimiter = delimiter})
#define VMA_FLAG_FORMAT(flag) FLAG_FORMAT(flag, vmaflags_names, ‘|')
source code:
printk("%pg\n", VMA_FLAG_FORMAT(my_flags));
that’s all, see cpumask_pr_args(masks) macro,
it also use macro and %*pb to print cpu mask .
i think this method is not very complex to use .
search source code ,
there is lots of printk to print flag into hex number :
$ grep -n -r 'printk.*flag.*%x’ .
it will be great if this flag string print is generic.
Thanks
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH 1/2] mm, printk: introduce new format string for flags
2015-12-03 18:38 ` yalin wang
@ 2015-12-04 1:04 ` yalin wang
-1 siblings, 0 replies; 115+ messages in thread
From: yalin wang @ 2015-12-04 1:04 UTC (permalink / raw)
To: Rasmus Villemoes
Cc: Vlastimil Babka, open list:MEMORY MANAGEMENT, linux-kernel,
Andrew Morton, Joonsoo Kim, Minchan Kim, Sasha Levin,
Kirill A. Shutemov, Mel Gorman, Michal Hocko
>> Technically, I think the answer is yes, at least in C99 (and I suppose
>> gcc would accept it in gnu89 mode as well).
>>
>> printk("%pg\n", &(struct flag_printer){.flags = my_flags, .names = vmaflags_names});
>>
>> Not tested, and I still don't think it would be particularly readable
>> even when macroized
>>
>> printk("%pg\n", PRINTF_VMAFLAGS(my_flags));
> i test on gcc 4.9.3, it can work for this method,
> so the final solution like this:
> printk.h:
> struct flag_fmt_spec {
> unsigned long flag;
> struct trace_print_flags *flags;
> int array_size;
> char delimiter; }
>
> #define FLAG_FORMAT(flag, flag_array, delimiter) (&(struct flag_ft_spec){ .flag = flag, .flags = flag_array, .array_size = ARRAY_SIZE(flag_array), .delimiter = delimiter})
> #define VMA_FLAG_FORMAT(flag) FLAG_FORMAT(flag, vmaflags_names, ‘|’)
a little change:
#define VMA_FLAG_FORMAT(vma) FLAG_FORMAT(vma->vm_flags, vmaflags_names, ‘|’)
> source code:
> printk("%pg\n", VMA_FLAG_FORMAT(my_flags));
a little change:
printk("%pg\n", VMA_FLAG_FORMAT(vma));
>
> that’s all, see cpumask_pr_args(masks) macro,
> it also use macro and %*pb to print cpu mask .
> i think this method is not very complex to use .
>
> search source code ,
> there is lots of printk to print flag into hex number :
> $ grep -n -r 'printk.*flag.*%x’ .
> it will be great if this flag string print is generic.
>
> Thanks
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH 1/2] mm, printk: introduce new format string for flags
@ 2015-12-04 1:04 ` yalin wang
0 siblings, 0 replies; 115+ messages in thread
From: yalin wang @ 2015-12-04 1:04 UTC (permalink / raw)
To: Rasmus Villemoes
Cc: Vlastimil Babka, open list:MEMORY MANAGEMENT, linux-kernel,
Andrew Morton, Joonsoo Kim, Minchan Kim, Sasha Levin,
Kirill A. Shutemov, Mel Gorman, Michal Hocko
>> Technically, I think the answer is yes, at least in C99 (and I suppose
>> gcc would accept it in gnu89 mode as well).
>>
>> printk("%pg\n", &(struct flag_printer){.flags = my_flags, .names = vmaflags_names});
>>
>> Not tested, and I still don't think it would be particularly readable
>> even when macroized
>>
>> printk("%pg\n", PRINTF_VMAFLAGS(my_flags));
> i test on gcc 4.9.3, it can work for this method,
> so the final solution like this:
> printk.h:
> struct flag_fmt_spec {
> unsigned long flag;
> struct trace_print_flags *flags;
> int array_size;
> char delimiter; }
>
> #define FLAG_FORMAT(flag, flag_array, delimiter) (&(struct flag_ft_spec){ .flag = flag, .flags = flag_array, .array_size = ARRAY_SIZE(flag_array), .delimiter = delimiter})
> #define VMA_FLAG_FORMAT(flag) FLAG_FORMAT(flag, vmaflags_names, ‘|’)
a little change:
#define VMA_FLAG_FORMAT(vma) FLAG_FORMAT(vma->vm_flags, vmaflags_names, ‘|’)
> source code:
> printk("%pg\n", VMA_FLAG_FORMAT(my_flags));
a little change:
printk("%pg\n", VMA_FLAG_FORMAT(vma));
>
> that’s all, see cpumask_pr_args(masks) macro,
> it also use macro and %*pb to print cpu mask .
> i think this method is not very complex to use .
>
> search source code ,
> there is lots of printk to print flag into hex number :
> $ grep -n -r 'printk.*flag.*%x’ .
> it will be great if this flag string print is generic.
>
> Thanks
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH 1/2] mm, printk: introduce new format string for flags
2015-12-03 18:38 ` yalin wang
@ 2015-12-04 14:15 ` Vlastimil Babka
-1 siblings, 0 replies; 115+ messages in thread
From: Vlastimil Babka @ 2015-12-04 14:15 UTC (permalink / raw)
To: yalin wang, Rasmus Villemoes
Cc: open list:MEMORY MANAGEMENT, linux-kernel, Andrew Morton,
Joonsoo Kim, Minchan Kim, Sasha Levin, Kirill A. Shutemov,
Mel Gorman, Michal Hocko
On 12/03/2015 07:38 PM, yalin wang wrote:
> that’s all, see cpumask_pr_args(masks) macro,
> it also use macro and %*pb to print cpu mask .
> i think this method is not very complex to use .
Well, one also has to write the appropriate translation tables.
> search source code ,
> there is lots of printk to print flag into hex number :
> $ grep -n -r 'printk.*flag.*%x’ .
> it will be great if this flag string print is generic.
I think it can always be done later, this is an internal API. For now we
just have 3 quite generic flags, so let's not over-engineer things right
now.
> Thanks
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH 1/2] mm, printk: introduce new format string for flags
@ 2015-12-04 14:15 ` Vlastimil Babka
0 siblings, 0 replies; 115+ messages in thread
From: Vlastimil Babka @ 2015-12-04 14:15 UTC (permalink / raw)
To: yalin wang, Rasmus Villemoes
Cc: open list:MEMORY MANAGEMENT, linux-kernel, Andrew Morton,
Joonsoo Kim, Minchan Kim, Sasha Levin, Kirill A. Shutemov,
Mel Gorman, Michal Hocko
On 12/03/2015 07:38 PM, yalin wang wrote:
> thata??s all, see cpumask_pr_args(masks) macro,
> it also use macro and %*pb to print cpu mask .
> i think this method is not very complex to use .
Well, one also has to write the appropriate translation tables.
> search source code ,
> there is lots of printk to print flag into hex number :
> $ grep -n -r 'printk.*flag.*%xa?? .
> it will be great if this flag string print is generic.
I think it can always be done later, this is an internal API. For now we
just have 3 quite generic flags, so let's not over-engineer things right
now.
> Thanks
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH 1/2] mm, printk: introduce new format string for flags
2015-12-04 14:15 ` Vlastimil Babka
@ 2015-12-10 4:03 ` Steven Rostedt
-1 siblings, 0 replies; 115+ messages in thread
From: Steven Rostedt @ 2015-12-10 4:03 UTC (permalink / raw)
To: Vlastimil Babka
Cc: yalin wang, Rasmus Villemoes, open list:MEMORY MANAGEMENT,
linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko
On Fri, Dec 04, 2015 at 03:15:45PM +0100, Vlastimil Babka wrote:
> On 12/03/2015 07:38 PM, yalin wang wrote:
> >that’s all, see cpumask_pr_args(masks) macro,
> >it also use macro and %*pb to print cpu mask .
> >i think this method is not very complex to use .
>
> Well, one also has to write the appropriate translation tables.
>
> >search source code ,
> >there is lots of printk to print flag into hex number :
> >$ grep -n -r 'printk.*flag.*%x’ .
> >it will be great if this flag string print is generic.
>
> I think it can always be done later, this is an internal API. For now we
> just have 3 quite generic flags, so let's not over-engineer things right
> now.
>
As long as it is never used in the TP_printk() part of a tracepoint. As soon
as it is, trace-cmd and perf will update parse-events to handle that
parameter, and as soon as that is done, it becomes a userspace ABI.
Just be warned.
-- Steve
^ permalink raw reply [flat|nested] 115+ messages in thread
* Re: [PATCH 1/2] mm, printk: introduce new format string for flags
@ 2015-12-10 4:03 ` Steven Rostedt
0 siblings, 0 replies; 115+ messages in thread
From: Steven Rostedt @ 2015-12-10 4:03 UTC (permalink / raw)
To: Vlastimil Babka
Cc: yalin wang, Rasmus Villemoes, open list:MEMORY MANAGEMENT,
linux-kernel, Andrew Morton, Joonsoo Kim, Minchan Kim,
Sasha Levin, Kirill A. Shutemov, Mel Gorman, Michal Hocko
On Fri, Dec 04, 2015 at 03:15:45PM +0100, Vlastimil Babka wrote:
> On 12/03/2015 07:38 PM, yalin wang wrote:
> >thata??s all, see cpumask_pr_args(masks) macro,
> >it also use macro and %*pb to print cpu mask .
> >i think this method is not very complex to use .
>
> Well, one also has to write the appropriate translation tables.
>
> >search source code ,
> >there is lots of printk to print flag into hex number :
> >$ grep -n -r 'printk.*flag.*%xa?? .
> >it will be great if this flag string print is generic.
>
> I think it can always be done later, this is an internal API. For now we
> just have 3 quite generic flags, so let's not over-engineer things right
> now.
>
As long as it is never used in the TP_printk() part of a tracepoint. As soon
as it is, trace-cmd and perf will update parse-events to handle that
parameter, and as soon as that is done, it becomes a userspace ABI.
Just be warned.
-- Steve
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 115+ messages in thread