Commit 6b74ab97bc12ce74acec900f1d89a4aee2e4d70d

Authored by Mel Gorman
Committed by Linus Torvalds
1 parent 9483a578df

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
... ... @@ -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
... ... @@ -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
... ... @@ -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
  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);
... ... @@ -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++) {