diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/sparse.c | 78 |
1 files changed, 77 insertions, 1 deletions
diff --git a/mm/sparse.c b/mm/sparse.c index 7a3650923d9a..8ffc08990008 100644 --- a/mm/sparse.c +++ b/mm/sparse.c | |||
@@ -269,16 +269,92 @@ static unsigned long *__kmalloc_section_usemap(void) | |||
269 | } | 269 | } |
270 | #endif /* CONFIG_MEMORY_HOTPLUG */ | 270 | #endif /* CONFIG_MEMORY_HOTPLUG */ |
271 | 271 | ||
272 | #ifdef CONFIG_MEMORY_HOTREMOVE | ||
273 | static unsigned long * __init | ||
274 | sparse_early_usemap_alloc_pgdat_section(struct pglist_data *pgdat) | ||
275 | { | ||
276 | unsigned long section_nr; | ||
277 | |||
278 | /* | ||
279 | * A page may contain usemaps for other sections preventing the | ||
280 | * page being freed and making a section unremovable while | ||
281 | * other sections referencing the usemap retmain active. Similarly, | ||
282 | * a pgdat can prevent a section being removed. If section A | ||
283 | * contains a pgdat and section B contains the usemap, both | ||
284 | * sections become inter-dependent. This allocates usemaps | ||
285 | * from the same section as the pgdat where possible to avoid | ||
286 | * this problem. | ||
287 | */ | ||
288 | section_nr = pfn_to_section_nr(__pa(pgdat) >> PAGE_SHIFT); | ||
289 | return alloc_bootmem_section(usemap_size(), section_nr); | ||
290 | } | ||
291 | |||
292 | static void __init check_usemap_section_nr(int nid, unsigned long *usemap) | ||
293 | { | ||
294 | unsigned long usemap_snr, pgdat_snr; | ||
295 | static unsigned long old_usemap_snr = NR_MEM_SECTIONS; | ||
296 | static unsigned long old_pgdat_snr = NR_MEM_SECTIONS; | ||
297 | struct pglist_data *pgdat = NODE_DATA(nid); | ||
298 | int usemap_nid; | ||
299 | |||
300 | usemap_snr = pfn_to_section_nr(__pa(usemap) >> PAGE_SHIFT); | ||
301 | pgdat_snr = pfn_to_section_nr(__pa(pgdat) >> PAGE_SHIFT); | ||
302 | if (usemap_snr == pgdat_snr) | ||
303 | return; | ||
304 | |||
305 | if (old_usemap_snr == usemap_snr && old_pgdat_snr == pgdat_snr) | ||
306 | /* skip redundant message */ | ||
307 | return; | ||
308 | |||
309 | old_usemap_snr = usemap_snr; | ||
310 | old_pgdat_snr = pgdat_snr; | ||
311 | |||
312 | usemap_nid = sparse_early_nid(__nr_to_section(usemap_snr)); | ||
313 | if (usemap_nid != nid) { | ||
314 | printk(KERN_INFO | ||
315 | "node %d must be removed before remove section %ld\n", | ||
316 | nid, usemap_snr); | ||
317 | return; | ||
318 | } | ||
319 | /* | ||
320 | * There is a circular dependency. | ||
321 | * Some platforms allow un-removable section because they will just | ||
322 | * gather other removable sections for dynamic partitioning. | ||
323 | * Just notify un-removable section's number here. | ||
324 | */ | ||
325 | printk(KERN_INFO "Section %ld and %ld (node %d)", usemap_snr, | ||
326 | pgdat_snr, nid); | ||
327 | printk(KERN_CONT | ||
328 | " have a circular dependency on usemap and pgdat allocations\n"); | ||
329 | } | ||
330 | #else | ||
331 | static unsigned long * __init | ||
332 | sparse_early_usemap_alloc_pgdat_section(struct pglist_data *pgdat) | ||
333 | { | ||
334 | return NULL; | ||
335 | } | ||
336 | |||
337 | static void __init check_usemap_section_nr(int nid, unsigned long *usemap) | ||
338 | { | ||
339 | } | ||
340 | #endif /* CONFIG_MEMORY_HOTREMOVE */ | ||
341 | |||
272 | static unsigned long *__init sparse_early_usemap_alloc(unsigned long pnum) | 342 | static unsigned long *__init sparse_early_usemap_alloc(unsigned long pnum) |
273 | { | 343 | { |
274 | unsigned long *usemap; | 344 | unsigned long *usemap; |
275 | struct mem_section *ms = __nr_to_section(pnum); | 345 | struct mem_section *ms = __nr_to_section(pnum); |
276 | int nid = sparse_early_nid(ms); | 346 | int nid = sparse_early_nid(ms); |
277 | 347 | ||
278 | usemap = alloc_bootmem_node(NODE_DATA(nid), usemap_size()); | 348 | usemap = sparse_early_usemap_alloc_pgdat_section(NODE_DATA(nid)); |
279 | if (usemap) | 349 | if (usemap) |
280 | return usemap; | 350 | return usemap; |
281 | 351 | ||
352 | usemap = alloc_bootmem_node(NODE_DATA(nid), usemap_size()); | ||
353 | if (usemap) { | ||
354 | check_usemap_section_nr(nid, usemap); | ||
355 | return usemap; | ||
356 | } | ||
357 | |||
282 | /* Stupid: suppress gcc warning for SPARSEMEM && !NUMA */ | 358 | /* Stupid: suppress gcc warning for SPARSEMEM && !NUMA */ |
283 | nid = 0; | 359 | nid = 0; |
284 | 360 | ||