hotplug memory remove: generic __remove_pages() support
[linux-2.6-block.git] / mm / sparse.c
index 7e9191381f86d0635e9ec68cda34cff6313ea859..186a85bf7912b559cda312ec636e4bb962233785 100644 (file)
@@ -208,12 +208,13 @@ static unsigned long sparse_encode_mem_map(struct page *mem_map, unsigned long p
 }
 
 /*
- * We need this if we ever free the mem_maps.  While not implemented yet,
- * this function is included for parity with its sibling.
+ * Decode mem_map from the coded memmap
  */
-static __attribute((unused))
+static
 struct page *sparse_decode_mem_map(unsigned long coded_mem_map, unsigned long pnum)
 {
+       /* mask off the extra low bits of information */
+       coded_mem_map &= SECTION_MAP_MASK;
        return ((struct page *)coded_mem_map) + section_nr_to_pfn(pnum);
 }
 
@@ -404,6 +405,28 @@ static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages)
 }
 #endif /* CONFIG_SPARSEMEM_VMEMMAP */
 
+static void free_section_usemap(struct page *memmap, unsigned long *usemap)
+{
+       if (!usemap)
+               return;
+
+       /*
+        * Check to see if allocation came from hot-plug-add
+        */
+       if (PageSlab(virt_to_page(usemap))) {
+               kfree(usemap);
+               if (memmap)
+                       __kfree_section_memmap(memmap, PAGES_PER_SECTION);
+               return;
+       }
+
+       /*
+        * TODO: Allocations came from bootmem - how do I free up ?
+        */
+       printk(KERN_WARNING "Not freeing up allocations from bootmem "
+                       "- leaking memory\n");
+}
+
 /*
  * returns the number of sections whose mem_maps were properly
  * set.  If this is <=0, then that means that the passed-in
@@ -456,4 +479,20 @@ out:
        }
        return ret;
 }
+
+void sparse_remove_one_section(struct zone *zone, struct mem_section *ms)
+{
+       struct page *memmap = NULL;
+       unsigned long *usemap = NULL;
+
+       if (ms->section_mem_map) {
+               usemap = ms->pageblock_flags;
+               memmap = sparse_decode_mem_map(ms->section_mem_map,
+                                               __section_nr(ms));
+               ms->section_mem_map = 0;
+               ms->pageblock_flags = NULL;
+       }
+
+       free_section_usemap(memmap, usemap);
+}
 #endif