percpu: misc preparations for nommu support
[safe/jmp/linux-2.6] / mm / memory_hotplug.c
index 380aef4..be211a5 100644 (file)
@@ -26,6 +26,9 @@
 #include <linux/migrate.h>
 #include <linux/page-isolation.h>
 #include <linux/pfn.h>
+#include <linux/suspend.h>
+#include <linux/mm_inline.h>
+#include <linux/firmware-map.h>
 
 #include <asm/tlbflush.h>
 
@@ -70,7 +73,9 @@ static void get_page_bootmem(unsigned long info,  struct page *page, int type)
        atomic_inc(&page->_count);
 }
 
-void put_page_bootmem(struct page *page)
+/* reference to __meminit __free_pages_bootmem is valid
+ * so use __ref to tell modpost not to generate a warning */
+void __ref put_page_bootmem(struct page *page)
 {
        int type;
 
@@ -485,14 +490,18 @@ int __ref add_memory(int nid, u64 start, u64 size)
        struct resource *res;
        int ret;
 
+       lock_system_sleep();
+
        res = register_memory_resource(start, size);
+       ret = -EEXIST;
        if (!res)
-               return -EEXIST;
+               goto out;
 
        if (!node_online(nid)) {
                pgdat = hotadd_new_pgdat(nid, start);
+               ret = -ENOMEM;
                if (!pgdat)
-                       return -ENOMEM;
+                       goto out;
                new_pgdat = 1;
        }
 
@@ -515,7 +524,11 @@ int __ref add_memory(int nid, u64 start, u64 size)
                BUG_ON(ret);
        }
 
-       return ret;
+       /* create new memmap entry */
+       firmware_map_add_hotplug(start, start + size, "System RAM");
+
+       goto out;
+
 error:
        /* rollback pgdat allocation and others */
        if (new_pgdat)
@@ -523,6 +536,8 @@ error:
        if (res)
                release_memory_resource(res);
 
+out:
+       unlock_system_sleep();
        return ret;
 }
 EXPORT_SYMBOL_GPL(add_memory);
@@ -664,15 +679,18 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
                if (!ret) { /* Success */
                        list_add_tail(&page->lru, &source);
                        move_pages--;
+                       inc_zone_page_state(page, NR_ISOLATED_ANON +
+                                           page_is_file_cache(page));
+
                } else {
                        /* Becasue we don't have big zone->lock. we should
                           check this again here. */
                        if (page_count(page))
                                not_managed++;
 #ifdef CONFIG_DEBUG_VM
-                       printk(KERN_INFO "removing from LRU failed"
-                                        " %lx/%d/%lx\n",
-                               pfn, page_count(page), page->flags);
+                       printk(KERN_ALERT "removing pfn %lx from LRU failed\n",
+                              pfn);
+                       dump_page(page);
 #endif
                }
        }
@@ -686,7 +704,7 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
        if (list_empty(&source))
                goto out;
        /* this function returns # of failed pages */
-       ret = migrate_pages(&source, hotremove_migrate_alloc, 0);
+       ret = migrate_pages(&source, hotremove_migrate_alloc, 0, 1);
 
 out:
        return ret;
@@ -739,7 +757,7 @@ check_pages_isolated(unsigned long start_pfn, unsigned long end_pfn)
        return offlined;
 }
 
-int offline_pages(unsigned long start_pfn,
+static int offline_pages(unsigned long start_pfn,
                  unsigned long end_pfn, unsigned long timeout)
 {
        unsigned long pfn, nr_pages, expire;
@@ -759,6 +777,8 @@ int offline_pages(unsigned long start_pfn,
        if (!test_pages_in_a_zone(start_pfn, end_pfn))
                return -EINVAL;
 
+       lock_system_sleep();
+
        zone = page_zone(pfn_to_page(start_pfn));
        node = zone_to_nid(zone);
        nr_pages = end_pfn - start_pfn;
@@ -766,7 +786,7 @@ int offline_pages(unsigned long start_pfn,
        /* set above range as isolated */
        ret = start_isolate_page_range(start_pfn, end_pfn);
        if (ret)
-               return ret;
+               goto out;
 
        arg.start_pfn = start_pfn;
        arg.nr_pages = nr_pages;
@@ -839,11 +859,16 @@ repeat:
 
        setup_per_zone_wmarks();
        calculate_zone_inactive_ratio(zone);
+       if (!node_present_pages(node)) {
+               node_clear_state(node, N_HIGH_MEMORY);
+               kswapd_stop(node);
+       }
 
        vm_total_pages = nr_free_pagecache_pages();
        writeback_set_ratelimit();
 
        memory_notify(MEM_OFFLINE, &arg);
+       unlock_system_sleep();
        return 0;
 
 failed_removal:
@@ -853,6 +878,8 @@ failed_removal:
        /* pushback to free area */
        undo_isolate_page_range(start_pfn, end_pfn);
 
+out:
+       unlock_system_sleep();
        return ret;
 }