Commit 708614e6180f398cd307ea0048d48ba6fa274610

Authored by Mel Gorman
Committed by Linus Torvalds
1 parent 6b74ab97bc

mm: verify the page links and memory model

Print out information on how the page flags are being used if mminit_loglevel
is MMINIT_VERIFY or higher and unconditionally performs sanity checks on the
flags regardless of loglevel.

When the page flags are updated with section, node and zone information, a
check are made to ensure the values can be retrieved correctly.  Finally we
confirm that pfn_to_page and page_to_pfn are the correct inverse functions.

[akpm@linux-foundation.org: fix printk warnings]
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 3 changed files with 91 additions and 0 deletions Side-by-side Diff

... ... @@ -78,6 +78,10 @@
78 78 } \
79 79 } while (0)
80 80  
  81 +extern void mminit_verify_pageflags_layout(void);
  82 +extern void mminit_verify_page_links(struct page *page,
  83 + enum zone_type zone, unsigned long nid, unsigned long pfn);
  84 +
81 85 #else
82 86  
83 87 static inline void mminit_dprintk(enum mminit_level level,
... ... @@ -85,6 +89,14 @@
85 89 {
86 90 }
87 91  
  92 +static inline void mminit_verify_pageflags_layout(void)
  93 +{
  94 +}
  95 +
  96 +static inline void mminit_verify_page_links(struct page *page,
  97 + enum zone_type zone, unsigned long nid, unsigned long pfn)
  98 +{
  99 +}
88 100 #endif /* CONFIG_DEBUG_MEMORY_INIT */
89 101 #endif
... ... @@ -7,8 +7,79 @@
7 7 */
8 8 #include <linux/kernel.h>
9 9 #include <linux/init.h>
  10 +#include "internal.h"
10 11  
11 12 int __meminitdata mminit_loglevel;
  13 +
  14 +void __init mminit_verify_pageflags_layout(void)
  15 +{
  16 + int shift, width;
  17 + unsigned long or_mask, add_mask;
  18 +
  19 + shift = 8 * sizeof(unsigned long);
  20 + width = shift - SECTIONS_WIDTH - NODES_WIDTH - ZONES_WIDTH;
  21 + mminit_dprintk(MMINIT_TRACE, "pageflags_layout_widths",
  22 + "Section %d Node %d Zone %d Flags %d\n",
  23 + SECTIONS_WIDTH,
  24 + NODES_WIDTH,
  25 + ZONES_WIDTH,
  26 + NR_PAGEFLAGS);
  27 + mminit_dprintk(MMINIT_TRACE, "pageflags_layout_shifts",
  28 + "Section %d Node %d Zone %d\n",
  29 +#ifdef SECTIONS_SHIFT
  30 + SECTIONS_SHIFT,
  31 +#else
  32 + 0,
  33 +#endif
  34 + NODES_SHIFT,
  35 + ZONES_SHIFT);
  36 + mminit_dprintk(MMINIT_TRACE, "pageflags_layout_offsets",
  37 + "Section %lu Node %lu Zone %lu\n",
  38 + (unsigned long)SECTIONS_PGSHIFT,
  39 + (unsigned long)NODES_PGSHIFT,
  40 + (unsigned long)ZONES_PGSHIFT);
  41 + mminit_dprintk(MMINIT_TRACE, "pageflags_layout_zoneid",
  42 + "Zone ID: %lu -> %lu\n",
  43 + (unsigned long)ZONEID_PGOFF,
  44 + (unsigned long)(ZONEID_PGOFF + ZONEID_SHIFT));
  45 + mminit_dprintk(MMINIT_TRACE, "pageflags_layout_usage",
  46 + "location: %d -> %d unused %d -> %d flags %d -> %d\n",
  47 + shift, width, width, NR_PAGEFLAGS, NR_PAGEFLAGS, 0);
  48 +#ifdef NODE_NOT_IN_PAGE_FLAGS
  49 + mminit_dprintk(MMINIT_TRACE, "pageflags_layout_nodeflags",
  50 + "Node not in page flags");
  51 +#endif
  52 +
  53 + if (SECTIONS_WIDTH) {
  54 + shift -= SECTIONS_WIDTH;
  55 + BUG_ON(shift != SECTIONS_PGSHIFT);
  56 + }
  57 + if (NODES_WIDTH) {
  58 + shift -= NODES_WIDTH;
  59 + BUG_ON(shift != NODES_PGSHIFT);
  60 + }
  61 + if (ZONES_WIDTH) {
  62 + shift -= ZONES_WIDTH;
  63 + BUG_ON(shift != ZONES_PGSHIFT);
  64 + }
  65 +
  66 + /* Check for bitmask overlaps */
  67 + or_mask = (ZONES_MASK << ZONES_PGSHIFT) |
  68 + (NODES_MASK << NODES_PGSHIFT) |
  69 + (SECTIONS_MASK << SECTIONS_PGSHIFT);
  70 + add_mask = (ZONES_MASK << ZONES_PGSHIFT) +
  71 + (NODES_MASK << NODES_PGSHIFT) +
  72 + (SECTIONS_MASK << SECTIONS_PGSHIFT);
  73 + BUG_ON(or_mask != add_mask);
  74 +}
  75 +
  76 +void __meminit mminit_verify_page_links(struct page *page, enum zone_type zone,
  77 + unsigned long nid, unsigned long pfn)
  78 +{
  79 + BUG_ON(page_to_nid(page) != nid);
  80 + BUG_ON(page_zonenum(page) != zone);
  81 + BUG_ON(page_to_pfn(page) != pfn);
  82 +}
12 83  
13 84 static __init int set_mminit_loglevel(char *str)
14 85 {
... ... @@ -2534,6 +2534,7 @@
2534 2534 }
2535 2535 page = pfn_to_page(pfn);
2536 2536 set_page_links(page, zone, nid, pfn);
  2537 + mminit_verify_page_links(page, zone, nid, pfn);
2537 2538 init_page_count(page);
2538 2539 reset_page_mapcount(page);
2539 2540 SetPageReserved(page);
... ... @@ -2836,6 +2837,12 @@
2836 2837  
2837 2838 zone->zone_start_pfn = zone_start_pfn;
2838 2839  
  2840 + mminit_dprintk(MMINIT_TRACE, "memmap_init",
  2841 + "Initialising map node %d zone %lu pfns %lu -> %lu\n",
  2842 + pgdat->node_id,
  2843 + (unsigned long)zone_idx(zone),
  2844 + zone_start_pfn, (zone_start_pfn + size));
  2845 +
2839 2846 zone_init_free_lists(zone);
2840 2847  
2841 2848 return 0;
... ... @@ -3961,6 +3968,7 @@
3961 3968 early_node_map[i].end_pfn);
3962 3969  
3963 3970 /* Initialise every node */
  3971 + mminit_verify_pageflags_layout();
3964 3972 setup_nr_node_ids();
3965 3973 for_each_online_node(nid) {
3966 3974 pg_data_t *pgdat = NODE_DATA(nid);