memory unplug: page offline
[deliverable/linux.git] / mm / page_alloc.c
index 17797d062c3b832aade2dcfa664230934479c47d..d315e1127dc91891980d180618d78ca51277aae7 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/pfn.h>
 #include <linux/backing-dev.h>
 #include <linux/fault-inject.h>
+#include <linux/page-isolation.h>
 
 #include <asm/tlbflush.h>
 #include <asm/div64.h>
@@ -149,7 +150,7 @@ static unsigned long __meminitdata dma_reserve;
   static unsigned long __meminitdata node_boundary_end_pfn[MAX_NUMNODES];
 #endif /* CONFIG_MEMORY_HOTPLUG_RESERVE */
   unsigned long __initdata required_kernelcore;
-  unsigned long __initdata required_movablecore;
+  static unsigned long __initdata required_movablecore;
   unsigned long __meminitdata zone_movable_pfn[MAX_NUMNODES];
 
   /* movable_zone is the "real" zone pages in ZONE_MOVABLE are taken from */
@@ -313,16 +314,6 @@ static inline void prep_zero_page(struct page *page, int order, gfp_t gfp_flags)
                clear_highpage(page + i);
 }
 
-/*
- * function for dealing with page's order in buddy system.
- * zone->lock is already acquired when we use these.
- * So, we don't need atomic page->flags operations here.
- */
-static inline unsigned long page_order(struct page *page)
-{
-       return page_private(page);
-}
-
 static inline void set_page_order(struct page *page, int order)
 {
        set_page_private(page, order);
@@ -3644,7 +3635,7 @@ unsigned long __init find_max_pfn_with_active_regions(void)
  * Sum pages in active regions for movable zone.
  * Populate N_HIGH_MEMORY for calculating usable_nodes.
  */
-unsigned long __init early_calculate_totalpages(void)
+static unsigned long __init early_calculate_totalpages(void)
 {
        int i;
        unsigned long totalpages = 0;
@@ -4443,3 +4434,93 @@ void set_pageblock_flags_group(struct page *page, unsigned long flags,
                else
                        __clear_bit(bitidx + start_bitidx, bitmap);
 }
+
+/*
+ * This is designed as sub function...plz see page_isolation.c also.
+ * set/clear page block's type to be ISOLATE.
+ * page allocater never alloc memory from ISOLATE block.
+ */
+
+int set_migratetype_isolate(struct page *page)
+{
+       struct zone *zone;
+       unsigned long flags;
+       int ret = -EBUSY;
+
+       zone = page_zone(page);
+       spin_lock_irqsave(&zone->lock, flags);
+       /*
+        * In future, more migrate types will be able to be isolation target.
+        */
+       if (get_pageblock_migratetype(page) != MIGRATE_MOVABLE)
+               goto out;
+       set_pageblock_migratetype(page, MIGRATE_ISOLATE);
+       move_freepages_block(zone, page, MIGRATE_ISOLATE);
+       ret = 0;
+out:
+       spin_unlock_irqrestore(&zone->lock, flags);
+       if (!ret)
+               drain_all_local_pages();
+       return ret;
+}
+
+void unset_migratetype_isolate(struct page *page)
+{
+       struct zone *zone;
+       unsigned long flags;
+       zone = page_zone(page);
+       spin_lock_irqsave(&zone->lock, flags);
+       if (get_pageblock_migratetype(page) != MIGRATE_ISOLATE)
+               goto out;
+       set_pageblock_migratetype(page, MIGRATE_MOVABLE);
+       move_freepages_block(zone, page, MIGRATE_MOVABLE);
+out:
+       spin_unlock_irqrestore(&zone->lock, flags);
+}
+
+#ifdef CONFIG_MEMORY_HOTREMOVE
+/*
+ * All pages in the range must be isolated before calling this.
+ */
+void
+__offline_isolated_pages(unsigned long start_pfn, unsigned long end_pfn)
+{
+       struct page *page;
+       struct zone *zone;
+       int order, i;
+       unsigned long pfn;
+       unsigned long flags;
+       /* find the first valid pfn */
+       for (pfn = start_pfn; pfn < end_pfn; pfn++)
+               if (pfn_valid(pfn))
+                       break;
+       if (pfn == end_pfn)
+               return;
+       zone = page_zone(pfn_to_page(pfn));
+       spin_lock_irqsave(&zone->lock, flags);
+       pfn = start_pfn;
+       while (pfn < end_pfn) {
+               if (!pfn_valid(pfn)) {
+                       pfn++;
+                       continue;
+               }
+               page = pfn_to_page(pfn);
+               BUG_ON(page_count(page));
+               BUG_ON(!PageBuddy(page));
+               order = page_order(page);
+#ifdef CONFIG_DEBUG_VM
+               printk(KERN_INFO "remove from free list %lx %d %lx\n",
+                      pfn, 1 << order, end_pfn);
+#endif
+               list_del(&page->lru);
+               rmv_page_order(page);
+               zone->free_area[order].nr_free--;
+               __mod_zone_page_state(zone, NR_FREE_PAGES,
+                                     - (1UL << order));
+               for (i = 0; i < (1 << order); i++)
+                       SetPageReserved((page+i));
+               pfn += (1 << order);
+       }
+       spin_unlock_irqrestore(&zone->lock, flags);
+}
+#endif
This page took 0.038877 seconds and 5 git commands to generate.