Commit 6b74ab97 authored by Mel Gorman's avatar Mel Gorman Committed by Linus Torvalds

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: default avatarMel Gorman <>
Cc: Christoph Lameter <>
Cc: Andy Whitcroft <>
Cc: Ingo Molnar <>
Signed-off-by: default avatarAndrew Morton <>
Signed-off-by: default avatarLinus Torvalds <>
parent 9483a578
......@@ -1225,6 +1225,14 @@ and is between 256 and 4096 characters. It is defined in the file
mga= [HW,DRM]
parameter allows control of the logging verbosity for
the additional memory initialisation checks. A value
of 0 disables mminit logging and a level of 4 will
log everything. Information is printed at KERN_DEBUG
so loglevel=8 may also need to be specified.
[MOUSE] Maximum time between finger touching and
leaving touchpad surface for touch to be considered
......@@ -505,6 +505,18 @@ config DEBUG_WRITECOUNT
If unsure, say N.
bool "Debug memory initialisation" if EMBEDDED
default !EMBEDDED
Enable this for additional checks during memory initialisation.
The sanity checks verify aspects of the VM such as the memory model
and other information provided by the architecture. Verbose
information will be printed at KERN_DEBUG loglevel depending
on the mminit_loglevel= command-line option.
If unsure, say Y
bool "Debug linked list manipulation"
depends on DEBUG_KERNEL
......@@ -26,6 +26,7 @@ obj-$(CONFIG_TMPFS_POSIX_ACL) += shmem_acl.o
obj-$(CONFIG_TINY_SHMEM) += tiny-shmem.o
obj-$(CONFIG_SLOB) += slob.o
obj-$(CONFIG_SLAB) += slab.o
obj-$(CONFIG_DEBUG_MEMORY_INIT) += mm_init.o
obj-$(CONFIG_SLUB) += slub.o
obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o
obj-$(CONFIG_FS_XIP) += filemap_xip.o
......@@ -59,4 +59,31 @@ static inline unsigned long page_order(struct page *page)
#define __paginginit __init
/* Memory initialisation debug and verification */
enum mminit_level {
extern int mminit_loglevel;
#define mminit_dprintk(level, prefix, fmt, arg...) \
do { \
if (level < mminit_loglevel) { \
printk(KERN_CONT "mminit::" prefix " " fmt, ##arg); \
} \
} while (0)
static inline void mminit_dprintk(enum mminit_level level,
const char *prefix, const char *fmt, ...)
* mm_init.c - Memory initialisation verification and debugging
* Copyright 2008 IBM Corporation, 2008
* Author Mel Gorman <>
#include <linux/kernel.h>
#include <linux/init.h>
int __meminitdata mminit_loglevel;
static __init int set_mminit_loglevel(char *str)
get_option(&str, &mminit_loglevel);
return 0;
early_param("mminit_loglevel", set_mminit_loglevel);
......@@ -2975,7 +2975,8 @@ void __init sparse_memory_present_with_active_regions(int nid)
void __init push_node_boundaries(unsigned int nid,
unsigned long start_pfn, unsigned long end_pfn)
printk(KERN_DEBUG "Entering push_node_boundaries(%u, %lu, %lu)\n",
mminit_dprintk(MMINIT_TRACE, "zoneboundary",
"Entering push_node_boundaries(%u, %lu, %lu)\n",
nid, start_pfn, end_pfn);
/* Initialise the boundary for this node if necessary */
......@@ -2993,7 +2994,8 @@ void __init push_node_boundaries(unsigned int nid,
static void __meminit account_node_boundary(unsigned int nid,
unsigned long *start_pfn, unsigned long *end_pfn)
printk(KERN_DEBUG "Entering account_node_boundary(%u, %lu, %lu)\n",
mminit_dprintk(MMINIT_TRACE, "zoneboundary",
"Entering account_node_boundary(%u, %lu, %lu)\n",
nid, *start_pfn, *end_pfn);
/* Return if boundary information has not been provided */
......@@ -3368,8 +3370,8 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat,
PAGE_ALIGN(size * sizeof(struct page)) >> PAGE_SHIFT;
if (realsize >= memmap_pages) {
realsize -= memmap_pages;
" %s zone: %lu pages used for memmap\n",
mminit_dprintk(MMINIT_TRACE, "memmap_init",
"%s zone: %lu pages used for memmap\n",
zone_names[j], memmap_pages);
} else
......@@ -3379,7 +3381,8 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat,
/* Account for reserved pages */
if (j == 0 && realsize > dma_reserve) {
realsize -= dma_reserve;
printk(KERN_DEBUG " %s zone: %lu pages reserved\n",
mminit_dprintk(MMINIT_TRACE, "memmap_init",
"%s zone: %lu pages reserved\n",
zone_names[0], dma_reserve);
......@@ -3520,10 +3523,11 @@ void __init add_active_range(unsigned int nid, unsigned long start_pfn,
int i;
printk(KERN_DEBUG "Entering add_active_range(%d, %#lx, %#lx) "
"%d entries of %d used\n",
nid, start_pfn, end_pfn,
nr_nodemap_entries, MAX_ACTIVE_REGIONS);
mminit_dprintk(MMINIT_TRACE, "memory_register",
"Entering add_active_range(%d, %#lx, %#lx) "
"%d entries of %d used\n",
nid, start_pfn, end_pfn,
nr_nodemap_entries, MAX_ACTIVE_REGIONS);
/* Merge with existing active regions if possible */
for (i = 0; i < nr_nodemap_entries; i++) {
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment