diff options
Diffstat (limited to 'mm/sparse.c')
-rw-r--r-- | mm/sparse.c | 51 |
1 files changed, 47 insertions, 4 deletions
diff --git a/mm/sparse.c b/mm/sparse.c index 08f053218ee8..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> |
@@ -376,6 +377,9 @@ static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages) | |||
376 | { | 377 | { |
377 | return; /* XXX: Not implemented yet */ | 378 | return; /* XXX: Not implemented yet */ |
378 | } | 379 | } |
380 | static void free_map_bootmem(struct page *page, unsigned long nr_pages) | ||
381 | { | ||
382 | } | ||
379 | #else | 383 | #else |
380 | static struct page *__kmalloc_section_memmap(unsigned long nr_pages) | 384 | static struct page *__kmalloc_section_memmap(unsigned long nr_pages) |
381 | { | 385 | { |
@@ -413,17 +417,47 @@ static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages) | |||
413 | free_pages((unsigned long)memmap, | 417 | free_pages((unsigned long)memmap, |
414 | get_order(sizeof(struct page) * nr_pages)); | 418 | get_order(sizeof(struct page) * nr_pages)); |
415 | } | 419 | } |
420 | |||
421 | static 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 | } | ||
416 | #endif /* CONFIG_SPARSEMEM_VMEMMAP */ | 446 | #endif /* CONFIG_SPARSEMEM_VMEMMAP */ |
417 | 447 | ||
418 | static void free_section_usemap(struct page *memmap, unsigned long *usemap) | 448 | static void free_section_usemap(struct page *memmap, unsigned long *usemap) |
419 | { | 449 | { |
450 | struct page *usemap_page; | ||
451 | unsigned long nr_pages; | ||
452 | |||
420 | if (!usemap) | 453 | if (!usemap) |
421 | return; | 454 | return; |
422 | 455 | ||
456 | usemap_page = virt_to_page(usemap); | ||
423 | /* | 457 | /* |
424 | * Check to see if allocation came from hot-plug-add | 458 | * Check to see if allocation came from hot-plug-add |
425 | */ | 459 | */ |
426 | if (PageSlab(virt_to_page(usemap))) { | 460 | if (PageSlab(usemap_page)) { |
427 | kfree(usemap); | 461 | kfree(usemap); |
428 | if (memmap) | 462 | if (memmap) |
429 | __kfree_section_memmap(memmap, PAGES_PER_SECTION); | 463 | __kfree_section_memmap(memmap, PAGES_PER_SECTION); |
@@ -431,10 +465,19 @@ static void free_section_usemap(struct page *memmap, unsigned long *usemap) | |||
431 | } | 465 | } |
432 | 466 | ||
433 | /* | 467 | /* |
434 | * TODO: Allocations came from bootmem - how do I free up ? | 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. | ||
435 | */ | 470 | */ |
436 | printk(KERN_WARNING "Not freeing up allocations from bootmem " | 471 | |
437 | "- leaking memory\n"); | 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 | } | ||
438 | } | 481 | } |
439 | 482 | ||
440 | /* | 483 | /* |