Commit 708614e6180f398cd307ea0048d48ba6fa274610
Committed by
Linus Torvalds
1 parent
6b74ab97bc
Exists in
master
and in
20 other branches
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
mm/internal.h
... | ... | @@ -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 |
mm/mm_init.c
... | ... | @@ -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 | { |
mm/page_alloc.c
... | ... | @@ -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); |