]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - mm/memory_hotplug.c
powerpc/ibmebus: Fix further device reference leaks
[mirror_ubuntu-artful-kernel.git] / mm / memory_hotplug.c
index 67d488ab495e57b9018484932e135078c787903c..43eb230ff2e0fd58830a227184dd32bf26702f28 100644 (file)
@@ -76,6 +76,9 @@ static struct {
 #define memhp_lock_acquire()      lock_map_acquire(&mem_hotplug.dep_map)
 #define memhp_lock_release()      lock_map_release(&mem_hotplug.dep_map)
 
+bool memhp_auto_online;
+EXPORT_SYMBOL_GPL(memhp_auto_online);
+
 void get_online_mems(void)
 {
        might_sleep();
@@ -1231,8 +1234,13 @@ int zone_for_memory(int nid, u64 start, u64 size, int zone_default,
        return zone_default;
 }
 
+static int online_memory_block(struct memory_block *mem, void *arg)
+{
+       return memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE);
+}
+
 /* we are OK calling __meminit stuff here - we have CONFIG_MEMORY_HOTPLUG */
-int __ref add_memory_resource(int nid, struct resource *res)
+int __ref add_memory_resource(int nid, struct resource *res, bool online)
 {
        u64 start, size;
        pg_data_t *pgdat = NULL;
@@ -1292,6 +1300,11 @@ int __ref add_memory_resource(int nid, struct resource *res)
        /* create new memmap entry */
        firmware_map_add_hotplug(start, start + size, "System RAM");
 
+       /* online pages if requested */
+       if (online)
+               walk_memory_range(PFN_DOWN(start), PFN_UP(start + size - 1),
+                                 NULL, online_memory_block);
+
        goto out;
 
 error:
@@ -1315,7 +1328,7 @@ int __ref add_memory(int nid, u64 start, u64 size)
        if (!res)
                return -EEXIST;
 
-       ret = add_memory_resource(nid, res);
+       ret = add_memory_resource(nid, res, memhp_auto_online);
        if (ret < 0)
                release_memory_resource(res);
        return ret;
@@ -1375,23 +1388,30 @@ int is_mem_section_removable(unsigned long start_pfn, unsigned long nr_pages)
  */
 int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn)
 {
-       unsigned long pfn;
+       unsigned long pfn, sec_end_pfn;
        struct zone *zone = NULL;
        struct page *page;
        int i;
-       for (pfn = start_pfn;
+       for (pfn = start_pfn, sec_end_pfn = SECTION_ALIGN_UP(start_pfn);
             pfn < end_pfn;
-            pfn += MAX_ORDER_NR_PAGES) {
-               i = 0;
-               /* This is just a CONFIG_HOLES_IN_ZONE check.*/
-               while ((i < MAX_ORDER_NR_PAGES) && !pfn_valid_within(pfn + i))
-                       i++;
-               if (i == MAX_ORDER_NR_PAGES)
+            pfn = sec_end_pfn + 1, sec_end_pfn += PAGES_PER_SECTION) {
+               /* Make sure the memory section is present first */
+               if (!present_section_nr(pfn_to_section_nr(pfn)))
                        continue;
-               page = pfn_to_page(pfn + i);
-               if (zone && page_zone(page) != zone)
-                       return 0;
-               zone = page_zone(page);
+               for (; pfn < sec_end_pfn && pfn < end_pfn;
+                    pfn += MAX_ORDER_NR_PAGES) {
+                       i = 0;
+                       /* This is just a CONFIG_HOLES_IN_ZONE check.*/
+                       while ((i < MAX_ORDER_NR_PAGES) &&
+                               !pfn_valid_within(pfn + i))
+                               i++;
+                       if (i == MAX_ORDER_NR_PAGES)
+                               continue;
+                       page = pfn_to_page(pfn + i);
+                       if (zone && page_zone(page) != zone)
+                               return 0;
+                       zone = page_zone(page);
+               }
        }
        return 1;
 }