Linux Headquarters
[ Register ]
[ About us ] [ Home Page ]

Advertisement
[ Kernel ] [ Documentation ] [ Links ] [ Books ]

Advertisement

Kernel v2.6.24 /mm/sparse.c

Filename:/mm/sparse.c
Lines Added:100
Lines Deleted:22
Also changed in: (Previous) 2.6.24-rc8  2.6.24-rc7  2.6.24-rc6  2.6.24-rc5-git7  2.6.24-rc5-git6  2.6.24-rc5-git5 
(Following) 2.6.24-git15  2.6.24-git16  2.6.24-git17  2.6.24-git18  2.6.24-git19  2.6.24-git20 

Location
[  2.6.24
  [  mm
     o  sparse.c

Patch

diff --git a/mm/sparse.c b/mm/sparse.c
index 239f5a7..a2183cb 100644
--- a/mm/sparse.c
+++ b/mm/sparse.c
@@ -9,6 +9,8 @@
 #include <linux/spinlock.h>
 #include <linux/vmalloc.h>
 #include <asm/dma.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
 
 /*
  * Permanent SPARSEMEM data:
@@ -81,6 +83,8 @@ static int __meminit sparse_index_init(unsigned long section_nr, int nid)
       return -EEXIST;
 
    section = sparse_index_alloc(nid);
+   if (!section)
+      return -ENOMEM;
    /*
     * This lock keeps two different sections from
     * reallocating for the same index
@@ -106,7 +110,7 @@ static inline int sparse_index_init(unsigned long section_nr, int nid)
 
 /*
  * Although written for the SPARSEMEM_EXTREME case, this happens
- * to also work for the flat array case becase
+ * to also work for the flat array case because
  * NR_SECTION_ROOTS==NR_MEM_SECTIONS.
  */
 int __section_nr(struct mem_section* ms)
@@ -176,7 +180,7 @@ unsigned long __init node_memmap_size_bytes(int nid, unsigned long start_pfn,
       if (nid != early_pfn_to_nid(pfn))
          continue;
 
-      if (pfn_valid(pfn))
+      if (pfn_present(pfn))
          nr_pages += PAGES_PER_SECTION;
    }
 
@@ -204,44 +208,79 @@ struct page *sparse_decode_mem_map(unsigned long coded_mem_map, unsigned long pn
 }
 
 static int __meminit sparse_init_one_section(struct mem_section *ms,
-      unsigned long pnum, struct page *mem_map)
+      unsigned long pnum, struct page *mem_map,
+      unsigned long *pageblock_bitmap)
 {
-   if (!valid_section(ms))
+   if (!present_section(ms))
       return -EINVAL;
 
    ms->section_mem_map &= ~SECTION_MAP_MASK;
-   ms->section_mem_map |= sparse_encode_mem_map(mem_map, pnum);
+   ms->section_mem_map |= sparse_encode_mem_map(mem_map, pnum) |
+                     SECTION_HAS_MEM_MAP;
+    ms->pageblock_flags = pageblock_bitmap;
 
    return 1;
 }
 
-__attribute__((weak)) __init
-void *alloc_bootmem_high_node(pg_data_t *pgdat, unsigned long size)
+static unsigned long usemap_size(void)
 {
-   return NULL;
+   unsigned long size_bytes;
+   size_bytes = roundup(SECTION_BLOCKFLAGS_BITS, 8) / 8;
+   size_bytes = roundup(size_bytes, sizeof(unsigned long));
+   return size_bytes;
 }
 
-static struct page __init *sparse_early_mem_map_alloc(unsigned long pnum)
+#ifdef CONFIG_MEMORY_HOTPLUG
+static unsigned long *__kmalloc_section_usemap(void)
 {
-   struct page *map;
+   return kmalloc(usemap_size(), GFP_KERNEL);
+}
+#endif /* CONFIG_MEMORY_HOTPLUG */
+
+static unsigned long *sparse_early_usemap_alloc(unsigned long pnum)
+{
+   unsigned long *usemap;
    struct mem_section *ms = __nr_to_section(pnum);
    int nid = sparse_early_nid(ms);
 
-   map = alloc_remap(nid, sizeof(struct page) * PAGES_PER_SECTION);
-   if (map)
-      return map;
+   usemap = alloc_bootmem_node(NODE_DATA(nid), usemap_size());
+   if (usemap)
+      return usemap;
 
-     map = alloc_bootmem_high_node(NODE_DATA(nid),
-                       sizeof(struct page) * PAGES_PER_SECTION);
+   /* Stupid: suppress gcc warning for SPARSEMEM && !NUMA */
+   nid = 0;
+
+   printk(KERN_WARNING "%s: allocation failed\n", __FUNCTION__);
+   return NULL;
+}
+
+#ifndef CONFIG_SPARSEMEM_VMEMMAP
+struct page __init *sparse_mem_map_populate(unsigned long pnum, int nid)
+{
+   struct page *map;
+
+   map = alloc_remap(nid, sizeof(struct page) * PAGES_PER_SECTION);
    if (map)
       return map;
 
    map = alloc_bootmem_node(NODE_DATA(nid),
          sizeof(struct page) * PAGES_PER_SECTION);
+   return map;
+}
+#endif /* !CONFIG_SPARSEMEM_VMEMMAP */
+
+struct page __init *sparse_early_mem_map_alloc(unsigned long pnum)
+{
+   struct page *map;
+   struct mem_section *ms = __nr_to_section(pnum);
+   int nid = sparse_early_nid(ms);
+
+   map = sparse_mem_map_populate(pnum, nid);
    if (map)
       return map;
 
-   printk(KERN_WARNING "%s: allocation failed\n", __FUNCTION__);
+   printk(KERN_ERR "%s: sparsemem memory map backing failed "
+         "some memory will not be available.\n", __FUNCTION__);
    ms->section_mem_map = 0;
    return NULL;
 }
@@ -254,19 +293,38 @@ void __init sparse_init(void)
 {
    unsigned long pnum;
    struct page *map;
+   unsigned long *usemap;
 
    for (pnum = 0; pnum < NR_MEM_SECTIONS; pnum++) {
-      if (!valid_section_nr(pnum))
+      if (!present_section_nr(pnum))
          continue;
 
       map = sparse_early_mem_map_alloc(pnum);
       if (!map)
          continue;
-      sparse_init_one_section(__nr_to_section(pnum), pnum, map);
+
+      usemap = sparse_early_usemap_alloc(pnum);
+      if (!usemap)
+         continue;
+
+      sparse_init_one_section(__nr_to_section(pnum), pnum, map,
+                        usemap);
    }
 }
 
 #ifdef CONFIG_MEMORY_HOTPLUG
+#ifdef CONFIG_SPARSEMEM_VMEMMAP
+static inline struct page *kmalloc_section_memmap(unsigned long pnum, int nid,
+                   unsigned long nr_pages)
+{
+   /* This will make the necessary allocations eventually. */
+   return sparse_mem_map_populate(pnum, nid);
+}
+static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages)
+{
+   return; /* XXX: Not implemented yet */
+}
+#else
 static struct page *__kmalloc_section_memmap(unsigned long nr_pages)
 {
    struct page *page, *ret;
@@ -289,6 +347,12 @@ got_map_ptr:
    return ret;
 }
 
+static inline struct page *kmalloc_section_memmap(unsigned long pnum, int nid,
+                    unsigned long nr_pages)
+{
+   return __kmalloc_section_memmap(nr_pages);
+}
+
 static int vaddr_in_vmalloc_area(void *addr)
 {
    if (addr >= (void *)VMALLOC_START &&
@@ -305,6 +369,7 @@ static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages)
       free_pages((unsigned long)memmap,
             get_order(sizeof(struct page) * nr_pages));
 }
+#endif /* CONFIG_SPARSEMEM_VMEMMAP */
 
 /*
  * returns the number of sections whose mem_maps were properly
@@ -318,6 +383,7 @@ int sparse_add_one_section(struct zone *zone, unsigned long start_pfn,
    struct pglist_data *pgdat = zone->zone_pgdat;
    struct mem_section *ms;
    struct page *memmap;
+   unsigned long *usemap;
    unsigned long flags;
    int ret;
 
@@ -325,8 +391,17 @@ int sparse_add_one_section(struct zone *zone, unsigned long start_pfn,
     * no locking for this, because it does its own
     * plus, it does a kmalloc
     */
-   sparse_index_init(section_nr, pgdat->node_id);
-   memmap = __kmalloc_section_memmap(nr_pages);
+   ret = sparse_index_init(section_nr, pgdat->node_id);
+   if (ret < 0 && ret != -EEXIST)
+      return ret;
+   memmap = kmalloc_section_memmap(section_nr, pgdat->node_id, nr_pages);
+   if (!memmap)
+      return -ENOMEM;
+   usemap = __kmalloc_section_usemap();
+   if (!usemap) {
+      __kfree_section_memmap(memmap, nr_pages);
+      return -ENOMEM;
+   }
 
    pgdat_resize_lock(pgdat, &flags);
 
@@ -335,14 +410,17 @@ int sparse_add_one_section(struct zone *zone, unsigned long start_pfn,
       ret = -EEXIST;
       goto out;
    }
+
    ms->section_mem_map |= SECTION_MARKED_PRESENT;
 
-   ret = sparse_init_one_section(ms, section_nr, memmap);
+   ret = sparse_init_one_section(ms, section_nr, memmap, usemap);
 
 out:
    pgdat_resize_unlock(pgdat, &flags);
-   if (ret <= 0)
+   if (ret <= 0) {
+      kfree(usemap);
       __kfree_section_memmap(memmap, nr_pages);
+   }
    return ret;
 }
 #endif


Comments: webmaster (at) linuxhq.com.
Advertising: banners (at) linuxhq.com.
Compilation ©1998-2008 Linux Headquarters, Inc.