Commit 6b74ab97bc12ce74acec900f1d89a4aee2e4d70d
Committed by
Linus Torvalds
1 parent
9483a578df
Exists in
master
and in
20 other branches
mm: add a basic debugging framework for memory initialisation
Boot initialisation is very complex, with significant numbers of architecture-specific routines, hooks and code ordering. While significant amounts of the initialisation is architecture-independent, it trusts the data received from the architecture layer. This is a mistake, and has resulted in a number of difficult-to-diagnose bugs. This patchset adds some validation and tracing to memory initialisation. It also introduces a few basic defensive measures. The validation code can be explicitly disabled for embedded systems. This patch: Add additional debugging and verification code for memory initialisation. Once enabled, the verification checks are always run and when required additional debugging information may be outputted via a mminit_loglevel= command-line parameter. The verification code is placed in a new file mm/mm_init.c. Ideally other mm initialisation code will be moved here over time. Signed-off-by: Mel Gorman <mel@csn.ul.ie> Cc: Christoph Lameter <cl@linux-foundation.org> Cc: Andy Whitcroft <apw@shadowen.org> Cc: Ingo Molnar <mingo@elte.hu> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 6 changed files with 79 additions and 9 deletions Side-by-side Diff
Documentation/kernel-parameters.txt
... | ... | @@ -1225,6 +1225,14 @@ |
1225 | 1225 | |
1226 | 1226 | mga= [HW,DRM] |
1227 | 1227 | |
1228 | + mminit_loglevel= | |
1229 | + [KNL] When CONFIG_DEBUG_MEMORY_INIT is set, this | |
1230 | + parameter allows control of the logging verbosity for | |
1231 | + the additional memory initialisation checks. A value | |
1232 | + of 0 disables mminit logging and a level of 4 will | |
1233 | + log everything. Information is printed at KERN_DEBUG | |
1234 | + so loglevel=8 may also need to be specified. | |
1235 | + | |
1228 | 1236 | mousedev.tap_time= |
1229 | 1237 | [MOUSE] Maximum time between finger touching and |
1230 | 1238 | leaving touchpad surface for touch to be considered |
lib/Kconfig.debug
... | ... | @@ -505,6 +505,18 @@ |
505 | 505 | |
506 | 506 | If unsure, say N. |
507 | 507 | |
508 | +config DEBUG_MEMORY_INIT | |
509 | + bool "Debug memory initialisation" if EMBEDDED | |
510 | + default !EMBEDDED | |
511 | + help | |
512 | + Enable this for additional checks during memory initialisation. | |
513 | + The sanity checks verify aspects of the VM such as the memory model | |
514 | + and other information provided by the architecture. Verbose | |
515 | + information will be printed at KERN_DEBUG loglevel depending | |
516 | + on the mminit_loglevel= command-line option. | |
517 | + | |
518 | + If unsure, say Y | |
519 | + | |
508 | 520 | config DEBUG_LIST |
509 | 521 | bool "Debug linked list manipulation" |
510 | 522 | depends on DEBUG_KERNEL |
mm/Makefile
... | ... | @@ -26,6 +26,7 @@ |
26 | 26 | obj-$(CONFIG_TINY_SHMEM) += tiny-shmem.o |
27 | 27 | obj-$(CONFIG_SLOB) += slob.o |
28 | 28 | obj-$(CONFIG_SLAB) += slab.o |
29 | +obj-$(CONFIG_DEBUG_MEMORY_INIT) += mm_init.o | |
29 | 30 | obj-$(CONFIG_SLUB) += slub.o |
30 | 31 | obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o |
31 | 32 | obj-$(CONFIG_FS_XIP) += filemap_xip.o |
mm/internal.h
... | ... | @@ -59,5 +59,32 @@ |
59 | 59 | #define __paginginit __init |
60 | 60 | #endif |
61 | 61 | |
62 | +/* Memory initialisation debug and verification */ | |
63 | +enum mminit_level { | |
64 | + MMINIT_WARNING, | |
65 | + MMINIT_VERIFY, | |
66 | + MMINIT_TRACE | |
67 | +}; | |
68 | + | |
69 | +#ifdef CONFIG_DEBUG_MEMORY_INIT | |
70 | + | |
71 | +extern int mminit_loglevel; | |
72 | + | |
73 | +#define mminit_dprintk(level, prefix, fmt, arg...) \ | |
74 | +do { \ | |
75 | + if (level < mminit_loglevel) { \ | |
76 | + printk(level <= MMINIT_WARNING ? KERN_WARNING : KERN_DEBUG); \ | |
77 | + printk(KERN_CONT "mminit::" prefix " " fmt, ##arg); \ | |
78 | + } \ | |
79 | +} while (0) | |
80 | + | |
81 | +#else | |
82 | + | |
83 | +static inline void mminit_dprintk(enum mminit_level level, | |
84 | + const char *prefix, const char *fmt, ...) | |
85 | +{ | |
86 | +} | |
87 | + | |
88 | +#endif /* CONFIG_DEBUG_MEMORY_INIT */ | |
62 | 89 | #endif |
mm/mm_init.c
1 | +/* | |
2 | + * mm_init.c - Memory initialisation verification and debugging | |
3 | + * | |
4 | + * Copyright 2008 IBM Corporation, 2008 | |
5 | + * Author Mel Gorman <mel@csn.ul.ie> | |
6 | + * | |
7 | + */ | |
8 | +#include <linux/kernel.h> | |
9 | +#include <linux/init.h> | |
10 | + | |
11 | +int __meminitdata mminit_loglevel; | |
12 | + | |
13 | +static __init int set_mminit_loglevel(char *str) | |
14 | +{ | |
15 | + get_option(&str, &mminit_loglevel); | |
16 | + return 0; | |
17 | +} | |
18 | +early_param("mminit_loglevel", set_mminit_loglevel); |
mm/page_alloc.c
... | ... | @@ -2975,7 +2975,8 @@ |
2975 | 2975 | void __init push_node_boundaries(unsigned int nid, |
2976 | 2976 | unsigned long start_pfn, unsigned long end_pfn) |
2977 | 2977 | { |
2978 | - printk(KERN_DEBUG "Entering push_node_boundaries(%u, %lu, %lu)\n", | |
2978 | + mminit_dprintk(MMINIT_TRACE, "zoneboundary", | |
2979 | + "Entering push_node_boundaries(%u, %lu, %lu)\n", | |
2979 | 2980 | nid, start_pfn, end_pfn); |
2980 | 2981 | |
2981 | 2982 | /* Initialise the boundary for this node if necessary */ |
... | ... | @@ -2993,7 +2994,8 @@ |
2993 | 2994 | static void __meminit account_node_boundary(unsigned int nid, |
2994 | 2995 | unsigned long *start_pfn, unsigned long *end_pfn) |
2995 | 2996 | { |
2996 | - printk(KERN_DEBUG "Entering account_node_boundary(%u, %lu, %lu)\n", | |
2997 | + mminit_dprintk(MMINIT_TRACE, "zoneboundary", | |
2998 | + "Entering account_node_boundary(%u, %lu, %lu)\n", | |
2997 | 2999 | nid, *start_pfn, *end_pfn); |
2998 | 3000 | |
2999 | 3001 | /* Return if boundary information has not been provided */ |
... | ... | @@ -3368,8 +3370,8 @@ |
3368 | 3370 | PAGE_ALIGN(size * sizeof(struct page)) >> PAGE_SHIFT; |
3369 | 3371 | if (realsize >= memmap_pages) { |
3370 | 3372 | realsize -= memmap_pages; |
3371 | - printk(KERN_DEBUG | |
3372 | - " %s zone: %lu pages used for memmap\n", | |
3373 | + mminit_dprintk(MMINIT_TRACE, "memmap_init", | |
3374 | + "%s zone: %lu pages used for memmap\n", | |
3373 | 3375 | zone_names[j], memmap_pages); |
3374 | 3376 | } else |
3375 | 3377 | printk(KERN_WARNING |
... | ... | @@ -3379,7 +3381,8 @@ |
3379 | 3381 | /* Account for reserved pages */ |
3380 | 3382 | if (j == 0 && realsize > dma_reserve) { |
3381 | 3383 | realsize -= dma_reserve; |
3382 | - printk(KERN_DEBUG " %s zone: %lu pages reserved\n", | |
3384 | + mminit_dprintk(MMINIT_TRACE, "memmap_init", | |
3385 | + "%s zone: %lu pages reserved\n", | |
3383 | 3386 | zone_names[0], dma_reserve); |
3384 | 3387 | } |
3385 | 3388 | |
... | ... | @@ -3520,10 +3523,11 @@ |
3520 | 3523 | { |
3521 | 3524 | int i; |
3522 | 3525 | |
3523 | - printk(KERN_DEBUG "Entering add_active_range(%d, %#lx, %#lx) " | |
3524 | - "%d entries of %d used\n", | |
3525 | - nid, start_pfn, end_pfn, | |
3526 | - nr_nodemap_entries, MAX_ACTIVE_REGIONS); | |
3526 | + mminit_dprintk(MMINIT_TRACE, "memory_register", | |
3527 | + "Entering add_active_range(%d, %#lx, %#lx) " | |
3528 | + "%d entries of %d used\n", | |
3529 | + nid, start_pfn, end_pfn, | |
3530 | + nr_nodemap_entries, MAX_ACTIVE_REGIONS); | |
3527 | 3531 | |
3528 | 3532 | /* Merge with existing active regions if possible */ |
3529 | 3533 | for (i = 0; i < nr_nodemap_entries; i++) { |