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