diff options
author | Mel Gorman <mel@csn.ul.ie> | 2008-07-24 00:26:51 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-24 13:47:13 -0400 |
commit | 708614e6180f398cd307ea0048d48ba6fa274610 (patch) | |
tree | 8fedf22cf9a2f404e2aef10c5b3858b99880c4c2 | |
parent | 6b74ab97bc12ce74acec900f1d89a4aee2e4d70d (diff) |
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>
-rw-r--r-- | mm/internal.h | 12 | ||||
-rw-r--r-- | mm/mm_init.c | 71 | ||||
-rw-r--r-- | mm/page_alloc.c | 8 |
3 files changed, 91 insertions, 0 deletions
diff --git a/mm/internal.h b/mm/internal.h index a7ee05253294..7a4a2885dc8e 100644 --- a/mm/internal.h +++ b/mm/internal.h | |||
@@ -78,6 +78,10 @@ do { \ | |||
78 | } \ | 78 | } \ |
79 | } while (0) | 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 | #else | 85 | #else |
82 | 86 | ||
83 | static inline void mminit_dprintk(enum mminit_level level, | 87 | static inline void mminit_dprintk(enum mminit_level level, |
@@ -85,5 +89,13 @@ static inline void mminit_dprintk(enum mminit_level level, | |||
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 | #endif /* CONFIG_DEBUG_MEMORY_INIT */ | 100 | #endif /* CONFIG_DEBUG_MEMORY_INIT */ |
89 | #endif | 101 | #endif |
diff --git a/mm/mm_init.c b/mm/mm_init.c index c01d8dfec817..e16990d629e6 100644 --- a/mm/mm_init.c +++ b/mm/mm_init.c | |||
@@ -7,9 +7,80 @@ | |||
7 | */ | 7 | */ |
8 | #include <linux/kernel.h> | 8 | #include <linux/kernel.h> |
9 | #include <linux/init.h> | 9 | #include <linux/init.h> |
10 | #include "internal.h" | ||
10 | 11 | ||
11 | int __meminitdata mminit_loglevel; | 12 | int __meminitdata mminit_loglevel; |
12 | 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 | } | ||
83 | |||
13 | static __init int set_mminit_loglevel(char *str) | 84 | static __init int set_mminit_loglevel(char *str) |
14 | { | 85 | { |
15 | get_option(&str, &mminit_loglevel); | 86 | get_option(&str, &mminit_loglevel); |
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 0908352ba727..acab6ad326df 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -2534,6 +2534,7 @@ void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone, | |||
2534 | } | 2534 | } |
2535 | page = pfn_to_page(pfn); | 2535 | page = pfn_to_page(pfn); |
2536 | set_page_links(page, zone, nid, pfn); | 2536 | set_page_links(page, zone, nid, pfn); |
2537 | mminit_verify_page_links(page, zone, nid, pfn); | ||
2537 | init_page_count(page); | 2538 | init_page_count(page); |
2538 | reset_page_mapcount(page); | 2539 | reset_page_mapcount(page); |
2539 | SetPageReserved(page); | 2540 | SetPageReserved(page); |
@@ -2836,6 +2837,12 @@ __meminit int init_currently_empty_zone(struct zone *zone, | |||
2836 | 2837 | ||
2837 | zone->zone_start_pfn = zone_start_pfn; | 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 | zone_init_free_lists(zone); | 2846 | zone_init_free_lists(zone); |
2840 | 2847 | ||
2841 | return 0; | 2848 | return 0; |
@@ -3961,6 +3968,7 @@ void __init free_area_init_nodes(unsigned long *max_zone_pfn) | |||
3961 | early_node_map[i].end_pfn); | 3968 | early_node_map[i].end_pfn); |
3962 | 3969 | ||
3963 | /* Initialise every node */ | 3970 | /* Initialise every node */ |
3971 | mminit_verify_pageflags_layout(); | ||
3964 | setup_nr_node_ids(); | 3972 | setup_nr_node_ids(); |
3965 | for_each_online_node(nid) { | 3973 | for_each_online_node(nid) { |
3966 | pg_data_t *pgdat = NODE_DATA(nid); | 3974 | pg_data_t *pgdat = NODE_DATA(nid); |