aboutsummaryrefslogtreecommitdiffstats
path: root/mm/sparse.c
diff options
context:
space:
mode:
authorYasunori Goto <y-goto@jp.fujitsu.com>2008-04-28 05:13:34 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-28 11:58:26 -0400
commit0c0a4a517a31e05efb38304668198a873bfec6ca (patch)
tree3d02fe9dbf160cd5d328c1e2cf4b40ce37426c5f /mm/sparse.c
parent86f6dae1377523689bd8468fed2f2dd180fc0560 (diff)
memory hotplug: free memmaps allocated by bootmem
This patch is to free memmaps which is allocated by bootmem. Freeing usemap is not necessary. The pages of usemap may be necessary for other sections. If removing section is last section on the node, its section is the final user of usemap page. (usemaps are allocated on its section by previous patch.) But it shouldn't be freed too, because the section must be logical offline state which all pages are isolated against page allocater. If it is freed, page alloctor may use it which will be removed physically soon. It will be disaster. So, this patch keeps it as it is. Signed-off-by: Yasunori Goto <y-goto@jp.fujitsu.com> Cc: Badari Pulavarty <pbadari@us.ibm.com> Cc: Yinghai Lu <yhlu.kernel@gmail.com> Cc: Yasunori Goto <y-goto@jp.fujitsu.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/sparse.c')
-rw-r--r--mm/sparse.c51
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}
380static void free_map_bootmem(struct page *page, unsigned long nr_pages)
381{
382}
379#else 383#else
380static struct page *__kmalloc_section_memmap(unsigned long nr_pages) 384static 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
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}
416#endif /* CONFIG_SPARSEMEM_VMEMMAP */ 446#endif /* CONFIG_SPARSEMEM_VMEMMAP */
417 447
418static void free_section_usemap(struct page *memmap, unsigned long *usemap) 448static 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/*