diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/bootmem.c | 1 | ||||
-rw-r--r-- | mm/memory_hotplug.c | 99 | ||||
-rw-r--r-- | mm/sparse.c | 3 |
3 files changed, 100 insertions, 3 deletions
diff --git a/mm/bootmem.c b/mm/bootmem.c index b6791646143e..369624d2789c 100644 --- a/mm/bootmem.c +++ b/mm/bootmem.c | |||
@@ -461,6 +461,7 @@ void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr, | |||
461 | 461 | ||
462 | unsigned long __init free_all_bootmem_node(pg_data_t *pgdat) | 462 | unsigned long __init free_all_bootmem_node(pg_data_t *pgdat) |
463 | { | 463 | { |
464 | register_page_bootmem_info_node(pgdat); | ||
464 | return free_all_bootmem_core(pgdat); | 465 | return free_all_bootmem_core(pgdat); |
465 | } | 466 | } |
466 | 467 | ||
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index c8b3ca79de2d..cba36ef0d506 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c | |||
@@ -58,8 +58,105 @@ static void release_memory_resource(struct resource *res) | |||
58 | return; | 58 | return; |
59 | } | 59 | } |
60 | 60 | ||
61 | |||
62 | #ifdef CONFIG_MEMORY_HOTPLUG_SPARSE | 61 | #ifdef CONFIG_MEMORY_HOTPLUG_SPARSE |
62 | #ifndef CONFIG_SPARSEMEM_VMEMMAP | ||
63 | static void get_page_bootmem(unsigned long info, struct page *page, int magic) | ||
64 | { | ||
65 | atomic_set(&page->_mapcount, magic); | ||
66 | SetPagePrivate(page); | ||
67 | set_page_private(page, info); | ||
68 | atomic_inc(&page->_count); | ||
69 | } | ||
70 | |||
71 | void put_page_bootmem(struct page *page) | ||
72 | { | ||
73 | int magic; | ||
74 | |||
75 | magic = atomic_read(&page->_mapcount); | ||
76 | BUG_ON(magic >= -1); | ||
77 | |||
78 | if (atomic_dec_return(&page->_count) == 1) { | ||
79 | ClearPagePrivate(page); | ||
80 | set_page_private(page, 0); | ||
81 | reset_page_mapcount(page); | ||
82 | __free_pages_bootmem(page, 0); | ||
83 | } | ||
84 | |||
85 | } | ||
86 | |||
87 | void register_page_bootmem_info_section(unsigned long start_pfn) | ||
88 | { | ||
89 | unsigned long *usemap, mapsize, section_nr, i; | ||
90 | struct mem_section *ms; | ||
91 | struct page *page, *memmap; | ||
92 | |||
93 | if (!pfn_valid(start_pfn)) | ||
94 | return; | ||
95 | |||
96 | section_nr = pfn_to_section_nr(start_pfn); | ||
97 | ms = __nr_to_section(section_nr); | ||
98 | |||
99 | /* Get section's memmap address */ | ||
100 | memmap = sparse_decode_mem_map(ms->section_mem_map, section_nr); | ||
101 | |||
102 | /* | ||
103 | * Get page for the memmap's phys address | ||
104 | * XXX: need more consideration for sparse_vmemmap... | ||
105 | */ | ||
106 | page = virt_to_page(memmap); | ||
107 | mapsize = sizeof(struct page) * PAGES_PER_SECTION; | ||
108 | mapsize = PAGE_ALIGN(mapsize) >> PAGE_SHIFT; | ||
109 | |||
110 | /* remember memmap's page */ | ||
111 | for (i = 0; i < mapsize; i++, page++) | ||
112 | get_page_bootmem(section_nr, page, SECTION_INFO); | ||
113 | |||
114 | usemap = __nr_to_section(section_nr)->pageblock_flags; | ||
115 | page = virt_to_page(usemap); | ||
116 | |||
117 | mapsize = PAGE_ALIGN(usemap_size()) >> PAGE_SHIFT; | ||
118 | |||
119 | for (i = 0; i < mapsize; i++, page++) | ||
120 | get_page_bootmem(section_nr, page, MIX_INFO); | ||
121 | |||
122 | } | ||
123 | |||
124 | void register_page_bootmem_info_node(struct pglist_data *pgdat) | ||
125 | { | ||
126 | unsigned long i, pfn, end_pfn, nr_pages; | ||
127 | int node = pgdat->node_id; | ||
128 | struct page *page; | ||
129 | struct zone *zone; | ||
130 | |||
131 | nr_pages = PAGE_ALIGN(sizeof(struct pglist_data)) >> PAGE_SHIFT; | ||
132 | page = virt_to_page(pgdat); | ||
133 | |||
134 | for (i = 0; i < nr_pages; i++, page++) | ||
135 | get_page_bootmem(node, page, NODE_INFO); | ||
136 | |||
137 | zone = &pgdat->node_zones[0]; | ||
138 | for (; zone < pgdat->node_zones + MAX_NR_ZONES - 1; zone++) { | ||
139 | if (zone->wait_table) { | ||
140 | nr_pages = zone->wait_table_hash_nr_entries | ||
141 | * sizeof(wait_queue_head_t); | ||
142 | nr_pages = PAGE_ALIGN(nr_pages) >> PAGE_SHIFT; | ||
143 | page = virt_to_page(zone->wait_table); | ||
144 | |||
145 | for (i = 0; i < nr_pages; i++, page++) | ||
146 | get_page_bootmem(node, page, NODE_INFO); | ||
147 | } | ||
148 | } | ||
149 | |||
150 | pfn = pgdat->node_start_pfn; | ||
151 | end_pfn = pfn + pgdat->node_spanned_pages; | ||
152 | |||
153 | /* register_section info */ | ||
154 | for (; pfn < end_pfn; pfn += PAGES_PER_SECTION) | ||
155 | register_page_bootmem_info_section(pfn); | ||
156 | |||
157 | } | ||
158 | #endif /* !CONFIG_SPARSEMEM_VMEMMAP */ | ||
159 | |||
63 | static int __add_zone(struct zone *zone, unsigned long phys_start_pfn) | 160 | static int __add_zone(struct zone *zone, unsigned long phys_start_pfn) |
64 | { | 161 | { |
65 | struct pglist_data *pgdat = zone->zone_pgdat; | 162 | struct pglist_data *pgdat = zone->zone_pgdat; |
diff --git a/mm/sparse.c b/mm/sparse.c index 186a85bf7912..8903c484389a 100644 --- a/mm/sparse.c +++ b/mm/sparse.c | |||
@@ -210,7 +210,6 @@ static unsigned long sparse_encode_mem_map(struct page *mem_map, unsigned long p | |||
210 | /* | 210 | /* |
211 | * Decode mem_map from the coded memmap | 211 | * Decode mem_map from the coded memmap |
212 | */ | 212 | */ |
213 | static | ||
214 | struct page *sparse_decode_mem_map(unsigned long coded_mem_map, unsigned long pnum) | 213 | struct page *sparse_decode_mem_map(unsigned long coded_mem_map, unsigned long pnum) |
215 | { | 214 | { |
216 | /* mask off the extra low bits of information */ | 215 | /* mask off the extra low bits of information */ |
@@ -233,7 +232,7 @@ static int __meminit sparse_init_one_section(struct mem_section *ms, | |||
233 | return 1; | 232 | return 1; |
234 | } | 233 | } |
235 | 234 | ||
236 | static unsigned long usemap_size(void) | 235 | unsigned long usemap_size(void) |
237 | { | 236 | { |
238 | unsigned long size_bytes; | 237 | unsigned long size_bytes; |
239 | size_bytes = roundup(SECTION_BLOCKFLAGS_BITS, 8) / 8; | 238 | size_bytes = roundup(SECTION_BLOCKFLAGS_BITS, 8) / 8; |