Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mm, printk: introduce new format string for flags

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>
Acked-by: Michal Hocko <mhocko@suse.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Cc: Minchan Kim <minchan@kernel.org>
Cc: Sasha Levin <sasha.levin@oracle.com>
Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
Cc: Mel Gorman <mgorman@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Vlastimil Babka and committed by
Linus Torvalds
edf14cdb 420adbe9

+172 -14
+18
Documentation/printk-formats.txt
··· 298 298 299 299 Passed by reference. 300 300 301 + Flags bitfields such as page flags, gfp_flags: 302 + 303 + %pGp referenced|uptodate|lru|active|private 304 + %pGg GFP_USER|GFP_DMA32|GFP_NOWARN 305 + %pGv read|exec|mayread|maywrite|mayexec|denywrite 306 + 307 + For printing flags bitfields as a collection of symbolic constants that 308 + would construct the value. The type of flags is given by the third 309 + character. Currently supported are [p]age flags, [v]ma_flags (both 310 + expect unsigned long *) and [g]fp_flags (expects gfp_t *). The flag 311 + names and print order depends on the particular type. 312 + 313 + Note that this format should not be used directly in TP_printk() part 314 + of a tracepoint. Instead, use the show_*_flags() functions from 315 + <trace/events/mmflags.h>. 316 + 317 + Passed by reference. 318 + 301 319 Network device features: 302 320 303 321 %pNF 0x000000000000c000
+53
lib/test_printf.c
··· 17 17 #include <linux/socket.h> 18 18 #include <linux/in.h> 19 19 20 + #include <linux/gfp.h> 21 + #include <linux/mm.h> 22 + 20 23 #define BUF_SIZE 256 21 24 #define PAD_SIZE 16 22 25 #define FILL_CHAR '$' ··· 414 411 } 415 412 416 413 static void __init 414 + flags(void) 415 + { 416 + unsigned long flags; 417 + gfp_t gfp; 418 + char *cmp_buffer; 419 + 420 + flags = 0; 421 + test("", "%pGp", &flags); 422 + 423 + /* Page flags should filter the zone id */ 424 + flags = 1UL << NR_PAGEFLAGS; 425 + test("", "%pGp", &flags); 426 + 427 + flags |= 1UL << PG_uptodate | 1UL << PG_dirty | 1UL << PG_lru 428 + | 1UL << PG_active | 1UL << PG_swapbacked; 429 + test("uptodate|dirty|lru|active|swapbacked", "%pGp", &flags); 430 + 431 + 432 + flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC 433 + | VM_DENYWRITE; 434 + test("read|exec|mayread|maywrite|mayexec|denywrite", "%pGv", &flags); 435 + 436 + gfp = GFP_TRANSHUGE; 437 + test("GFP_TRANSHUGE", "%pGg", &gfp); 438 + 439 + gfp = GFP_ATOMIC|__GFP_DMA; 440 + test("GFP_ATOMIC|GFP_DMA", "%pGg", &gfp); 441 + 442 + gfp = __GFP_ATOMIC; 443 + test("__GFP_ATOMIC", "%pGg", &gfp); 444 + 445 + cmp_buffer = kmalloc(BUF_SIZE, GFP_KERNEL); 446 + if (!cmp_buffer) 447 + return; 448 + 449 + /* Any flags not translated by the table should remain numeric */ 450 + gfp = ~__GFP_BITS_MASK; 451 + snprintf(cmp_buffer, BUF_SIZE, "%#lx", (unsigned long) gfp); 452 + test(cmp_buffer, "%pGg", &gfp); 453 + 454 + snprintf(cmp_buffer, BUF_SIZE, "__GFP_ATOMIC|%#lx", 455 + (unsigned long) gfp); 456 + gfp |= __GFP_ATOMIC; 457 + test(cmp_buffer, "%pGg", &gfp); 458 + 459 + kfree(cmp_buffer); 460 + } 461 + 462 + static void __init 417 463 test_pointer(void) 418 464 { 419 465 plain(); ··· 480 428 struct_clk(); 481 429 bitmap(); 482 430 netdev_features(); 431 + flags(); 483 432 } 484 433 485 434 static int __init
+75
lib/vsprintf.c
··· 35 35 #include <linux/blkdev.h> 36 36 #endif 37 37 38 + #include "../mm/internal.h" /* For the trace_print_flags arrays */ 39 + 38 40 #include <asm/page.h> /* for PAGE_SIZE */ 39 41 #include <asm/sections.h> /* for dereference_function_descriptor() */ 40 42 #include <asm/byteorder.h> /* cpu_to_le16 */ ··· 1409 1407 } 1410 1408 } 1411 1409 1410 + static 1411 + char *format_flags(char *buf, char *end, unsigned long flags, 1412 + const struct trace_print_flags *names) 1413 + { 1414 + unsigned long mask; 1415 + const struct printf_spec strspec = { 1416 + .field_width = -1, 1417 + .precision = -1, 1418 + }; 1419 + const struct printf_spec numspec = { 1420 + .flags = SPECIAL|SMALL, 1421 + .field_width = -1, 1422 + .precision = -1, 1423 + .base = 16, 1424 + }; 1425 + 1426 + for ( ; flags && names->name; names++) { 1427 + mask = names->mask; 1428 + if ((flags & mask) != mask) 1429 + continue; 1430 + 1431 + buf = string(buf, end, names->name, strspec); 1432 + 1433 + flags &= ~mask; 1434 + if (flags) { 1435 + if (buf < end) 1436 + *buf = '|'; 1437 + buf++; 1438 + } 1439 + } 1440 + 1441 + if (flags) 1442 + buf = number(buf, end, flags, numspec); 1443 + 1444 + return buf; 1445 + } 1446 + 1447 + static noinline_for_stack 1448 + char *flags_string(char *buf, char *end, void *flags_ptr, const char *fmt) 1449 + { 1450 + unsigned long flags; 1451 + const struct trace_print_flags *names; 1452 + 1453 + switch (fmt[1]) { 1454 + case 'p': 1455 + flags = *(unsigned long *)flags_ptr; 1456 + /* Remove zone id */ 1457 + flags &= (1UL << NR_PAGEFLAGS) - 1; 1458 + names = pageflag_names; 1459 + break; 1460 + case 'v': 1461 + flags = *(unsigned long *)flags_ptr; 1462 + names = vmaflag_names; 1463 + break; 1464 + case 'g': 1465 + flags = *(gfp_t *)flags_ptr; 1466 + names = gfpflag_names; 1467 + break; 1468 + default: 1469 + WARN_ONCE(1, "Unsupported flags modifier: %c\n", fmt[1]); 1470 + return buf; 1471 + } 1472 + 1473 + return format_flags(buf, end, flags, names); 1474 + } 1475 + 1412 1476 int kptr_restrict __read_mostly; 1413 1477 1414 1478 /* ··· 1563 1495 * - 'Cn' For a clock, it prints the name (Common Clock Framework) or address 1564 1496 * (legacy clock framework) of the clock 1565 1497 * - 'Cr' For a clock, it prints the current rate of the clock 1498 + * - 'G' For flags to be printed as a collection of symbolic strings that would 1499 + * construct the specific value. Supported flags given by option: 1500 + * p page flags (see struct page) given as pointer to unsigned long 1501 + * g gfp flags (GFP_* and __GFP_*) given as pointer to gfp_t 1502 + * v vma flags (VM_*) given as pointer to unsigned long 1566 1503 * 1567 1504 * ** Please update also Documentation/printk-formats.txt when making changes ** 1568 1505 * ··· 1721 1648 return bdev_name(buf, end, ptr, spec, fmt); 1722 1649 #endif 1723 1650 1651 + case 'G': 1652 + return flags_string(buf, end, ptr, fmt); 1724 1653 } 1725 1654 spec.flags |= SMALL; 1726 1655 if (spec.field_width == -1) {
+20 -14
mm/debug.c
··· 11 11 #include <linux/memcontrol.h> 12 12 #include <trace/events/mmflags.h> 13 13 14 - static const struct trace_print_flags pageflag_names[] = { 15 - __def_pageflag_names 14 + #include "internal.h" 15 + 16 + const struct trace_print_flags pageflag_names[] = { 17 + __def_pageflag_names, 18 + {0, NULL} 16 19 }; 17 20 18 - static const struct trace_print_flags gfpflag_names[] = { 19 - __def_gfpflag_names 21 + const struct trace_print_flags gfpflag_names[] = { 22 + __def_gfpflag_names, 23 + {0, NULL} 24 + }; 25 + 26 + const struct trace_print_flags vmaflag_names[] = { 27 + __def_vmaflag_names, 28 + {0, NULL} 20 29 }; 21 30 22 31 static void dump_flags(unsigned long flags, ··· 67 58 if (PageCompound(page)) 68 59 pr_cont(" compound_mapcount: %d", compound_mapcount(page)); 69 60 pr_cont("\n"); 70 - BUILD_BUG_ON(ARRAY_SIZE(pageflag_names) != __NR_PAGEFLAGS); 71 - dump_flags(page->flags, pageflag_names, ARRAY_SIZE(pageflag_names)); 61 + BUILD_BUG_ON(ARRAY_SIZE(pageflag_names) != __NR_PAGEFLAGS + 1); 62 + dump_flags(page->flags, pageflag_names, 63 + ARRAY_SIZE(pageflag_names) - 1); 72 64 if (reason) 73 65 pr_alert("page dumped because: %s\n", reason); 74 66 if (page->flags & badflags) { 75 67 pr_alert("bad because of flags:\n"); 76 - dump_flags(page->flags & badflags, 77 - pageflag_names, ARRAY_SIZE(pageflag_names)); 68 + dump_flags(page->flags & badflags, pageflag_names, 69 + ARRAY_SIZE(pageflag_names) - 1); 78 70 } 79 71 #ifdef CONFIG_MEMCG 80 72 if (page->mem_cgroup) ··· 91 81 92 82 #ifdef CONFIG_DEBUG_VM 93 83 94 - static const struct trace_print_flags vmaflag_names[] = { 95 - __def_vmaflag_names 96 - }; 97 - 98 84 void dump_vma(const struct vm_area_struct *vma) 99 85 { 100 86 pr_emerg("vma %p start %p end %p\n" ··· 102 96 (unsigned long)pgprot_val(vma->vm_page_prot), 103 97 vma->anon_vma, vma->vm_ops, vma->vm_pgoff, 104 98 vma->vm_file, vma->vm_private_data); 105 - dump_flags(vma->vm_flags, vmaflag_names, ARRAY_SIZE(vmaflag_names)); 99 + dump_flags(vma->vm_flags, vmaflag_names, ARRAY_SIZE(vmaflag_names) - 1); 106 100 } 107 101 EXPORT_SYMBOL(dump_vma); 108 102 ··· 174 168 ); 175 169 176 170 dump_flags(mm->def_flags, vmaflag_names, 177 - ARRAY_SIZE(vmaflag_names)); 171 + ARRAY_SIZE(vmaflag_names) - 1); 178 172 } 179 173 180 174 #endif /* CONFIG_DEBUG_VM */
+6
mm/internal.h
··· 14 14 #include <linux/fs.h> 15 15 #include <linux/mm.h> 16 16 #include <linux/pagemap.h> 17 + #include <linux/tracepoint-defs.h> 17 18 18 19 /* 19 20 * The set of flags that only affect watermark checking and reclaim ··· 467 466 } 468 467 469 468 #endif /* CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH */ 469 + 470 + extern const struct trace_print_flags pageflag_names[]; 471 + extern const struct trace_print_flags vmaflag_names[]; 472 + extern const struct trace_print_flags gfpflag_names[]; 473 + 470 474 #endif /* __MM_INTERNAL_H */