aboutsummaryrefslogtreecommitdiffstats
path: root/mm/sparse.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/sparse.c')
-rw-r--r--mm/sparse.c108
1 files changed, 100 insertions, 8 deletions
diff --git a/mm/sparse.c b/mm/sparse.c
index 7e9191381f86..dff71f173ae9 100644
--- a/mm/sparse.c
+++ b/mm/sparse.c
@@ -8,6 +8,7 @@
8#include <linux/module.h> 8#include <linux/module.h>
9#include <linux/spinlock.h> 9#include <linux/spinlock.h>
10#include <linux/vmalloc.h> 10#include <linux/vmalloc.h>
11#include "internal.h"
11#include <asm/dma.h> 12#include <asm/dma.h>
12#include <asm/pgalloc.h> 13#include <asm/pgalloc.h>
13#include <asm/pgtable.h> 14#include <asm/pgtable.h>
@@ -208,12 +209,12 @@ static unsigned long sparse_encode_mem_map(struct page *mem_map, unsigned long p
208} 209}
209 210
210/* 211/*
211 * We need this if we ever free the mem_maps. While not implemented yet, 212 * Decode mem_map from the coded memmap
212 * this function is included for parity with its sibling.
213 */ 213 */
214static __attribute((unused))
215struct page *sparse_decode_mem_map(unsigned long coded_mem_map, unsigned long pnum) 214struct page *sparse_decode_mem_map(unsigned long coded_mem_map, unsigned long pnum)
216{ 215{
216 /* mask off the extra low bits of information */
217 coded_mem_map &= SECTION_MAP_MASK;
217 return ((struct page *)coded_mem_map) + section_nr_to_pfn(pnum); 218 return ((struct page *)coded_mem_map) + section_nr_to_pfn(pnum);
218} 219}
219 220
@@ -232,7 +233,7 @@ static int __meminit sparse_init_one_section(struct mem_section *ms,
232 return 1; 233 return 1;
233} 234}
234 235
235static unsigned long usemap_size(void) 236unsigned long usemap_size(void)
236{ 237{
237 unsigned long size_bytes; 238 unsigned long size_bytes;
238 size_bytes = roundup(SECTION_BLOCKFLAGS_BITS, 8) / 8; 239 size_bytes = roundup(SECTION_BLOCKFLAGS_BITS, 8) / 8;
@@ -249,11 +250,22 @@ static unsigned long *__kmalloc_section_usemap(void)
249 250
250static unsigned long *__init sparse_early_usemap_alloc(unsigned long pnum) 251static unsigned long *__init sparse_early_usemap_alloc(unsigned long pnum)
251{ 252{
252 unsigned long *usemap; 253 unsigned long *usemap, section_nr;
253 struct mem_section *ms = __nr_to_section(pnum); 254 struct mem_section *ms = __nr_to_section(pnum);
254 int nid = sparse_early_nid(ms); 255 int nid = sparse_early_nid(ms);
256 struct pglist_data *pgdat = NODE_DATA(nid);
255 257
256 usemap = alloc_bootmem_node(NODE_DATA(nid), usemap_size()); 258 /*
259 * Usemap's page can't be freed until freeing other sections
260 * which use it. And, Pgdat has same feature.
261 * If section A has pgdat and section B has usemap for other
262 * sections (includes section A), both sections can't be removed,
263 * because there is the dependency each other.
264 * To solve above issue, this collects all usemap on the same section
265 * which has pgdat.
266 */
267 section_nr = pfn_to_section_nr(__pa(pgdat) >> PAGE_SHIFT);
268 usemap = alloc_bootmem_section(usemap_size(), section_nr);
257 if (usemap) 269 if (usemap)
258 return usemap; 270 return usemap;
259 271
@@ -273,8 +285,8 @@ struct page __init *sparse_mem_map_populate(unsigned long pnum, int nid)
273 if (map) 285 if (map)
274 return map; 286 return map;
275 287
276 map = alloc_bootmem_node(NODE_DATA(nid), 288 map = alloc_bootmem_pages_node(NODE_DATA(nid),
277 sizeof(struct page) * PAGES_PER_SECTION); 289 PAGE_ALIGN(sizeof(struct page) * PAGES_PER_SECTION));
278 return map; 290 return map;
279} 291}
280#endif /* !CONFIG_SPARSEMEM_VMEMMAP */ 292#endif /* !CONFIG_SPARSEMEM_VMEMMAP */
@@ -365,6 +377,9 @@ static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages)
365{ 377{
366 return; /* XXX: Not implemented yet */ 378 return; /* XXX: Not implemented yet */
367} 379}
380static void free_map_bootmem(struct page *page, unsigned long nr_pages)
381{
382}
368#else 383#else
369static struct page *__kmalloc_section_memmap(unsigned long nr_pages) 384static struct page *__kmalloc_section_memmap(unsigned long nr_pages)
370{ 385{
@@ -402,8 +417,69 @@ static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages)
402 free_pages((unsigned long)memmap, 417 free_pages((unsigned long)memmap,
403 get_order(sizeof(struct page) * nr_pages)); 418 get_order(sizeof(struct page) * nr_pages));
404} 419}
420
421static void free_map_bootmem(struct page *page, unsigned long nr_pages)
422{
423 unsigned long maps_section_nr, removing_section_nr, i;
424 int magic;
425
426 for (i = 0; i < nr_pages; i++, page++) {
427 magic = atomic_read(&page->_mapcount);
428
429 BUG_ON(magic == NODE_INFO);
430
431 maps_section_nr = pfn_to_section_nr(page_to_pfn(page));
432 removing_section_nr = page->private;
433
434 /*
435 * When this function is called, the removing section is
436 * logical offlined state. This means all pages are isolated
437 * from page allocator. If removing section's memmap is placed
438 * on the same section, it must not be freed.
439 * If it is freed, page allocator may allocate it which will
440 * be removed physically soon.
441 */
442 if (maps_section_nr != removing_section_nr)
443 put_page_bootmem(page);
444 }
445}
405#endif /* CONFIG_SPARSEMEM_VMEMMAP */ 446#endif /* CONFIG_SPARSEMEM_VMEMMAP */
406 447
448static void free_section_usemap(struct page *memmap, unsigned long *usemap)
449{
450 struct page *usemap_page;
451 unsigned long nr_pages;
452
453 if (!usemap)
454 return;
455
456 usemap_page = virt_to_page(usemap);
457 /*
458 * Check to see if allocation came from hot-plug-add
459 */
460 if (PageSlab(usemap_page)) {
461 kfree(usemap);
462 if (memmap)
463 __kfree_section_memmap(memmap, PAGES_PER_SECTION);
464 return;
465 }
466
467 /*
468 * The usemap came from bootmem. This is packed with other usemaps
469 * on the section which has pgdat at boot time. Just keep it as is now.
470 */
471
472 if (memmap) {
473 struct page *memmap_page;
474 memmap_page = virt_to_page(memmap);
475
476 nr_pages = PAGE_ALIGN(PAGES_PER_SECTION * sizeof(struct page))
477 >> PAGE_SHIFT;
478
479 free_map_bootmem(memmap_page, nr_pages);
480 }
481}
482
407/* 483/*
408 * returns the number of sections whose mem_maps were properly 484 * returns the number of sections whose mem_maps were properly
409 * set. If this is <=0, then that means that the passed-in 485 * set. If this is <=0, then that means that the passed-in
@@ -456,4 +532,20 @@ out:
456 } 532 }
457 return ret; 533 return ret;
458} 534}
535
536void sparse_remove_one_section(struct zone *zone, struct mem_section *ms)
537{
538 struct page *memmap = NULL;
539 unsigned long *usemap = NULL;
540
541 if (ms->section_mem_map) {
542 usemap = ms->pageblock_flags;
543 memmap = sparse_decode_mem_map(ms->section_mem_map,
544 __section_nr(ms));
545 ms->section_mem_map = 0;
546 ms->pageblock_flags = NULL;
547 }
548
549 free_section_usemap(memmap, usemap);
550}
459#endif 551#endif