Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / mm / page_alloc.c
index d7270d7..b747cbf 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/pagemap.h>
 #include <linux/bootmem.h>
 #include <linux/compiler.h>
+#include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/suspend.h>
 #include <linux/pagevec.h>
 #include <linux/topology.h>
 #include <linux/sysctl.h>
 #include <linux/cpu.h>
-#include <linux/vs_base.h>
+#include <linux/cpuset.h>
+#include <linux/memory_hotplug.h>
+#include <linux/nodemask.h>
+#include <linux/vmalloc.h>
+#include <linux/mempolicy.h>
 #include <linux/vs_limit.h>
 
 #include <asm/tlbflush.h>
+#include <asm/div64.h>
+#include "internal.h"
 
-DECLARE_BITMAP(node_online_map, MAX_NUMNODES);
-struct pglist_data *pgdat_list;
-unsigned long totalram_pages;
-unsigned long totalhigh_pages;
-int nr_swap_pages;
-int numnodes = 1;
-int sysctl_lower_zone_protection = 0;
+/*
+ * MCD - HACK: Find somewhere to initialize this EARLY, or make this
+ * initializer cleaner
+ */
+nodemask_t node_online_map __read_mostly = { { [0] = 1UL } };
+EXPORT_SYMBOL(node_online_map);
+nodemask_t node_possible_map __read_mostly = NODE_MASK_ALL;
+EXPORT_SYMBOL(node_possible_map);
+unsigned long totalram_pages __read_mostly;
+unsigned long totalhigh_pages __read_mostly;
+unsigned long totalreserve_pages __read_mostly;
+long nr_swap_pages;
+int percpu_pagelist_fraction;
+
+static void __free_pages_ok(struct page *page, unsigned int order);
+
+/*
+ * results with 256, 32 in the lowmem_reserve sysctl:
+ *     1G machine -> (16M dma, 800M-16M normal, 1G-800M high)
+ *     1G machine -> (16M dma, 784M normal, 224M high)
+ *     NORMAL allocation will leave 784M/256 of ram reserved in the ZONE_DMA
+ *     HIGHMEM allocation will leave 224M/32 of ram reserved in ZONE_NORMAL
+ *     HIGHMEM allocation will (224M+784M)/256 of ram reserved in ZONE_DMA
+ *
+ * TBD: should special case ZONE_DMA32 machines here - in those we normally
+ * don't need any ZONE_NORMAL reservation
+ */
+int sysctl_lowmem_reserve_ratio[MAX_NR_ZONES-1] = { 256, 256, 32 };
 
 EXPORT_SYMBOL(totalram_pages);
-EXPORT_SYMBOL(nr_swap_pages);
 
 /*
  * Used by page_zone() to look up the address of the struct zone whose
  * id is encoded in the upper bits of page->flags
  */
-struct zone *zone_table[1 << (ZONES_SHIFT + NODES_SHIFT)];
+struct zone *zone_table[1 << ZONETABLE_SHIFT] __read_mostly;
 EXPORT_SYMBOL(zone_table);
 
-static char *zone_names[MAX_NR_ZONES] = { "DMA", "Normal", "HighMem" };
+static char *zone_names[MAX_NR_ZONES] = { "DMA", "DMA32", "Normal", "HighMem" };
 int min_free_kbytes = 1024;
 
+unsigned long __initdata nr_kernel_pages;
+unsigned long __initdata nr_all_pages;
+
+#ifdef CONFIG_DEBUG_VM
+static int page_outside_zone_boundaries(struct zone *zone, struct page *page)
+{
+       int ret = 0;
+       unsigned seq;
+       unsigned long pfn = page_to_pfn(page);
+
+       do {
+               seq = zone_span_seqbegin(zone);
+               if (pfn >= zone->zone_start_pfn + zone->spanned_pages)
+                       ret = 1;
+               else if (pfn < zone->zone_start_pfn)
+                       ret = 1;
+       } while (zone_span_seqretry(zone, seq));
+
+       return ret;
+}
+
+static int page_is_consistent(struct zone *zone, struct page *page)
+{
+#ifdef CONFIG_HOLES_IN_ZONE
+       if (!pfn_valid(page_to_pfn(page)))
+               return 0;
+#endif
+       if (zone != page_zone(page))
+               return 0;
+
+       return 1;
+}
 /*
  * Temporary debugging check for pages not lying within a given zone.
  */
 static int bad_range(struct zone *zone, struct page *page)
 {
-       if (page_to_pfn(page) >= zone->zone_start_pfn + zone->spanned_pages)
+       if (page_outside_zone_boundaries(zone, page))
                return 1;
-       if (page_to_pfn(page) < zone->zone_start_pfn)
-               return 1;
-       if (zone != page_zone(page))
+       if (!page_is_consistent(zone, page))
                return 1;
+
+       return 0;
+}
+
+#else
+static inline int bad_range(struct zone *zone, struct page *page)
+{
        return 0;
 }
+#endif
 
-static void bad_page(const char *function, struct page *page)
+static void bad_page(struct page *page)
 {
-       printk(KERN_EMERG "Bad page state at %s (in process '%s', page %p)\n",
-               function, current->comm, page);
-       printk(KERN_EMERG "flags:0x%08lx mapping:%p mapcount:%d count:%d\n",
+       printk(KERN_EMERG "Bad page state in process '%s'\n"
+               KERN_EMERG "page:%p flags:0x%0*lx mapping:%p mapcount:%d count:%d (%s)\n"
+               KERN_EMERG "Trying to fix it up, but a reboot is needed\n"
+               KERN_EMERG "Backtrace:\n",
+               current->comm, page, (int)(2*sizeof(unsigned long)),
                (unsigned long)page->flags, page->mapping,
-               (int)page->mapcount, page_count(page));
-       printk(KERN_EMERG "Backtrace:\n");
+               page_mapcount(page), page_count(page), print_tainted());
        dump_stack();
-       printk(KERN_EMERG "Trying to fix it up, but a reboot is needed\n");
-       page->flags &= ~(1 << PG_private        |
+       page->flags &= ~(1 << PG_lru    |
+                       1 << PG_private |
                        1 << PG_locked  |
-                       1 << PG_lru     |
                        1 << PG_active  |
                        1 << PG_dirty   |
-                       1 << PG_maplock |
-                       1 << PG_anon    |
+                       1 << PG_reclaim |
+                       1 << PG_slab    |
                        1 << PG_swapcache |
-                       1 << PG_writeback);
+                       1 << PG_writeback |
+                       1 << PG_buddy );
        set_page_count(page, 0);
+       reset_page_mapcount(page);
        page->mapping = NULL;
-       page->mapcount = 0;
+       add_taint(TAINT_BAD_PAGE);
 }
 
-#ifndef CONFIG_HUGETLB_PAGE
-#define prep_compound_page(page, order) do { } while (0)
-#define destroy_compound_page(page, order) do { } while (0)
-#else
 /*
  * Higher-order pages are called "compound pages".  They are structured thusly:
  *
@@ -109,25 +172,28 @@ static void bad_page(const char *function, struct page *page)
  * All pages have PG_compound set.  All pages have their ->private pointing at
  * the head page (even the head page has this).
  *
- * The first tail page's ->mapping, if non-zero, holds the address of the
- * compound page's put_page() function.
- *
- * The order of the allocation is stored in the first tail page's ->index
- * This is only for debug at present.  This usage means that zero-order pages
- * may not be compound.
+ * The first tail page's ->lru.next holds the address of the compound page's
+ * put_page() function.  Its ->lru.prev holds the order of allocation.
+ * This usage means that zero-order pages may not be compound.
  */
+
+static void free_compound_page(struct page *page)
+{
+       __free_pages_ok(page, (unsigned long)page[1].lru.prev);
+}
+
 static void prep_compound_page(struct page *page, unsigned long order)
 {
        int i;
        int nr_pages = 1 << order;
 
-       page[1].mapping = 0;
-       page[1].index = order;
+       page[1].lru.next = (void *)free_compound_page;  /* set dtor */
+       page[1].lru.prev = (void *)order;
        for (i = 0; i < nr_pages; i++) {
                struct page *p = page + i;
 
-               SetPageCompound(p);
-               p->private = (unsigned long)page;
+               __SetPageCompound(p);
+               set_page_private(p, (unsigned long)page);
        }
 }
 
@@ -136,23 +202,111 @@ static void destroy_compound_page(struct page *page, unsigned long order)
        int i;
        int nr_pages = 1 << order;
 
-       if (!PageCompound(page))
-               return;
-
-       if (page[1].index != order)
-               bad_page(__FUNCTION__, page);
+       if (unlikely((unsigned long)page[1].lru.prev != order))
+               bad_page(page);
 
        for (i = 0; i < nr_pages; i++) {
                struct page *p = page + i;
 
-               if (!PageCompound(p))
-                       bad_page(__FUNCTION__, page);
-               if (p->private != (unsigned long)page)
-                       bad_page(__FUNCTION__, page);
-               ClearPageCompound(p);
+               if (unlikely(!PageCompound(p) |
+                               (page_private(p) != (unsigned long)page)))
+                       bad_page(page);
+               __ClearPageCompound(p);
        }
 }
-#endif         /* CONFIG_HUGETLB_PAGE */
+
+static inline void prep_zero_page(struct page *page, int order, gfp_t gfp_flags)
+{
+       int i;
+
+       BUG_ON((gfp_flags & (__GFP_WAIT | __GFP_HIGHMEM)) == __GFP_HIGHMEM);
+       /*
+        * clear_highpage() will use KM_USER0, so it's a bug to use __GFP_ZERO
+        * and __GFP_HIGHMEM from hard or soft interrupt context.
+        */
+       BUG_ON((gfp_flags & __GFP_HIGHMEM) && in_interrupt());
+       for (i = 0; i < (1 << order); i++)
+               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);
+       __SetPageBuddy(page);
+}
+
+static inline void rmv_page_order(struct page *page)
+{
+       __ClearPageBuddy(page);
+       set_page_private(page, 0);
+}
+
+/*
+ * Locate the struct page for both the matching buddy in our
+ * pair (buddy1) and the combined O(n+1) page they form (page).
+ *
+ * 1) Any buddy B1 will have an order O twin B2 which satisfies
+ * the following equation:
+ *     B2 = B1 ^ (1 << O)
+ * For example, if the starting buddy (buddy2) is #8 its order
+ * 1 buddy is #10:
+ *     B2 = 8 ^ (1 << 1) = 8 ^ 2 = 10
+ *
+ * 2) Any buddy B will have an order O+1 parent P which
+ * satisfies the following equation:
+ *     P = B & ~(1 << O)
+ *
+ * Assumption: *_mem_map is contigious at least up to MAX_ORDER
+ */
+static inline struct page *
+__page_find_buddy(struct page *page, unsigned long page_idx, unsigned int order)
+{
+       unsigned long buddy_idx = page_idx ^ (1 << order);
+
+       return page + (buddy_idx - page_idx);
+}
+
+static inline unsigned long
+__find_combined_index(unsigned long page_idx, unsigned int order)
+{
+       return (page_idx & ~(1 << order));
+}
+
+/*
+ * This function checks whether a page is free && is the buddy
+ * we can do coalesce a page and its buddy if
+ * (a) the buddy is not in a hole &&
+ * (b) the buddy is in the buddy system &&
+ * (c) a page and its buddy have the same order.
+ *
+ * For recording whether a page is in the buddy system, we use PG_buddy.
+ * Setting, clearing, and testing PG_buddy is serialized by zone->lock.
+ *
+ * For recording page's order, we use page_private(page).
+ */
+static inline int page_is_buddy(struct page *page, int order)
+{
+#ifdef CONFIG_HOLES_IN_ZONE
+       if (!pfn_valid(page_to_pfn(page)))
+               return 0;
+#endif
+
+       if (PageBuddy(page) && page_order(page) == order) {
+               BUG_ON(page_count(page) != 0);
+               return 1;
+       }
+       return 0;
+}
 
 /*
  * Freeing function for a buddy system allocator.
@@ -166,9 +320,10 @@ static void destroy_compound_page(struct page *page, unsigned long order)
  * at the bottom level available, and propagating the changes upward
  * as necessary, plus some accounting needed to play nicely with other
  * parts of the VM system.
- * At each level, we keep one bit for each pair of blocks, which
- * is set to 1 iff only one of the pair is allocated.  So when we
- * are allocating or freeing one, we can derive the state of the
+ * At each level, we keep a list of pages, which are heads of continuous
+ * free pages of length of (1 << order) and marked with PG_buddy. Page's
+ * order is recorded in page_private(page) field.
+ * So when we are allocating or freeing one, we can derive the state of the
  * other.  That is, if we allocate a small block, and both were   
  * free, the remainder of the region must be split into blocks.   
  * If a block is freed, and its buddy is also free, then this
@@ -177,52 +332,49 @@ static void destroy_compound_page(struct page *page, unsigned long order)
  * -- wli
  */
 
-static inline void __free_pages_bulk (struct page *page, struct page *base,
-               struct zone *zone, struct free_area *area, unsigned long mask,
-               unsigned int order)
+static inline void __free_one_page(struct page *page,
+               struct zone *zone, unsigned int order)
 {
-       unsigned long page_idx, index;
+       unsigned long page_idx;
+       int order_size = 1 << order;
 
-       if (order)
+       if (unlikely(PageCompound(page)))
                destroy_compound_page(page, order);
-       page_idx = page - base;
-       if (page_idx & ~mask)
-               BUG();
-       index = page_idx >> (1 + order);
-
-       zone->free_pages -= mask;
-       while (mask + (1 << (MAX_ORDER-1))) {
-               struct page *buddy1, *buddy2;
 
-               BUG_ON(area >= zone->free_area + MAX_ORDER);
-               if (!__test_and_change_bit(index, area->map))
-                       /*
-                        * the buddy page is still allocated.
-                        */
-                       break;
-               /*
-                * Move the buddy up one level.
-                * This code is taking advantage of the identity:
-                *      -mask = 1+~mask
-                */
-               buddy1 = base + (page_idx ^ -mask);
-               buddy2 = base + page_idx;
-               BUG_ON(bad_range(zone, buddy1));
-               BUG_ON(bad_range(zone, buddy2));
-               list_del(&buddy1->lru);
-               mask <<= 1;
-               area++;
-               index >>= 1;
-               page_idx &= mask;
+       page_idx = page_to_pfn(page) & ((1 << MAX_ORDER) - 1);
+
+       BUG_ON(page_idx & (order_size - 1));
+       BUG_ON(bad_range(zone, page));
+
+       zone->free_pages += order_size;
+       while (order < MAX_ORDER-1) {
+               unsigned long combined_idx;
+               struct free_area *area;
+               struct page *buddy;
+
+               buddy = __page_find_buddy(page, page_idx, order);
+               if (!page_is_buddy(buddy, order))
+                       break;          /* Move the buddy up one level. */
+
+               list_del(&buddy->lru);
+               area = zone->free_area + order;
+               area->nr_free--;
+               rmv_page_order(buddy);
+               combined_idx = __find_combined_index(page_idx, order);
+               page = page + (combined_idx - page_idx);
+               page_idx = combined_idx;
+               order++;
        }
-       list_add(&(base + page_idx)->lru, &area->free_list);
+       set_page_order(page, order);
+       list_add(&page->lru, &zone->free_area[order].free_list);
+       zone->free_area[order].nr_free++;
 }
 
-static inline void free_pages_check(const char *function, struct page *page)
+static inline int free_pages_check(struct page *page)
 {
-       if (    page_mapped(page) ||
-               page->mapping != NULL ||
-               page_count(page) != 0 ||
+       if (unlikely(page_mapcount(page) |
+               (page->mapping != NULL)  |
+               (page_count(page) != 0)  |
                (page->flags & (
                        1 << PG_lru     |
                        1 << PG_private |
@@ -230,19 +382,25 @@ static inline void free_pages_check(const char *function, struct page *page)
                        1 << PG_active  |
                        1 << PG_reclaim |
                        1 << PG_slab    |
-                       1 << PG_maplock |
-                       1 << PG_anon    |
                        1 << PG_swapcache |
-                       1 << PG_writeback )))
-               bad_page(function, page);
+                       1 << PG_writeback |
+                       1 << PG_reserved |
+                       1 << PG_buddy ))))
+               bad_page(page);
        if (PageDirty(page))
-               ClearPageDirty(page);
+               __ClearPageDirty(page);
+       /*
+        * For now, we report if PG_reserved was found set, but do not
+        * clear it, and do not free the page.  But we shall soon need
+        * to do more, for when the ZERO_PAGE count wraps negative.
+        */
+       return PageReserved(page);
 }
 
 /*
  * Frees a list of pages. 
  * Assumes all pages on list are in same zone, and of same order.
- * count is the number of pages to free, or 0 for all on the list.
+ * count is the number of pages to free.
  *
  * If the zone was previously in an "all pages pinned" state then look to
  * see if this freeing clears that state.
@@ -250,107 +408,156 @@ static inline void free_pages_check(const char *function, struct page *page)
  * And clear the zone's pages_scanned counter, to hold off the "all pages are
  * pinned" detection logic.
  */
-static int
-free_pages_bulk(struct zone *zone, int count,
-               struct list_head *list, unsigned int order)
+static void free_pages_bulk(struct zone *zone, int count,
+                                       struct list_head *list, int order)
 {
-       unsigned long mask, flags;
-       struct free_area *area;
-       struct page *base, *page = NULL;
-       int ret = 0;
-
-       mask = (~0UL) << order;
-       base = zone->zone_mem_map;
-       area = zone->free_area + order;
-       spin_lock_irqsave(&zone->lock, flags);
+       spin_lock(&zone->lock);
        zone->all_unreclaimable = 0;
        zone->pages_scanned = 0;
-       while (!list_empty(list) && count--) {
+       while (count--) {
+               struct page *page;
+
+               BUG_ON(list_empty(list));
                page = list_entry(list->prev, struct page, lru);
-               /* have to delete it as __free_pages_bulk list manipulates */
+               /* have to delete it as __free_one_page list manipulates */
                list_del(&page->lru);
-               __free_pages_bulk(page, base, zone, area, mask, order);
-               ret++;
+               __free_one_page(page, zone, order);
        }
-       spin_unlock_irqrestore(&zone->lock, flags);
-       return ret;
+       spin_unlock(&zone->lock);
 }
 
-void __free_pages_ok(struct page *page, unsigned int order)
+static void free_one_page(struct zone *zone, struct page *page, int order)
 {
        LIST_HEAD(list);
+       list_add(&page->lru, &list);
+       free_pages_bulk(zone, 1, &list, order);
+}
+
+static void __free_pages_ok(struct page *page, unsigned int order)
+{
+       unsigned long flags;
        int i;
+       int reserved = 0;
+
+       arch_free_page(page, order);
+       if (!PageHighMem(page))
+               mutex_debug_check_no_locks_freed(page_address(page),
+                                                PAGE_SIZE<<order);
 
-       mod_page_state(pgfree, 1 << order);
        for (i = 0 ; i < (1 << order) ; ++i)
-               free_pages_check(__FUNCTION__, page + i);
-       list_add(&page->lru, &list);
-       kernel_map_pages(page, 1<<order, 0);
-       free_pages_bulk(page_zone(page), 1, &list, order);
+               reserved += free_pages_check(page + i);
+       if (reserved)
+               return;
+
+       kernel_map_pages(page, 1 << order, 0);
+       local_irq_save(flags);
+       __mod_page_state(pgfree, 1 << order);
+       free_one_page(page_zone(page), page, order);
+       local_irq_restore(flags);
 }
 
-#define MARK_USED(index, order, area) \
-       __change_bit((index) >> (1+(order)), (area)->map)
+/*
+ * permit the bootmem allocator to evade page validation on high-order frees
+ */
+void fastcall __init __free_pages_bootmem(struct page *page, unsigned int order)
+{
+       if (order == 0) {
+               __ClearPageReserved(page);
+               set_page_count(page, 0);
+               set_page_refcounted(page);
+               __free_page(page);
+       } else {
+               int loop;
 
-static inline struct page *
-expand(struct zone *zone, struct page *page,
-        unsigned long index, int low, int high, struct free_area *area)
+               prefetchw(page);
+               for (loop = 0; loop < BITS_PER_LONG; loop++) {
+                       struct page *p = &page[loop];
+
+                       if (loop + 1 < BITS_PER_LONG)
+                               prefetchw(p + 1);
+                       __ClearPageReserved(p);
+                       set_page_count(p, 0);
+               }
+
+               set_page_refcounted(page);
+               __free_pages(page, order);
+       }
+}
+
+
+/*
+ * The order of subdivision here is critical for the IO subsystem.
+ * Please do not alter this order without good reasons and regression
+ * testing. Specifically, as large blocks of memory are subdivided,
+ * the order in which smaller blocks are delivered depends on the order
+ * they're subdivided in this function. This is the primary factor
+ * influencing the order in which pages are delivered to the IO
+ * subsystem according to empirical testing, and this is also justified
+ * by considering the behavior of a buddy system containing a single
+ * large block of memory acted on by a series of small allocations.
+ * This behavior is a critical factor in sglist merging's success.
+ *
+ * -- wli
+ */
+static inline void expand(struct zone *zone, struct page *page,
+       int low, int high, struct free_area *area)
 {
        unsigned long size = 1 << high;
 
        while (high > low) {
-               BUG_ON(bad_range(zone, page));
                area--;
                high--;
                size >>= 1;
-               list_add(&page->lru, &area->free_list);
-               MARK_USED(index, high, area);
-               index += size;
-               page += size;
+               BUG_ON(bad_range(zone, &page[size]));
+               list_add(&page[size].lru, &area->free_list);
+               area->nr_free++;
+               set_page_order(&page[size], high);
        }
-       return page;
-}
-
-static inline void set_page_refs(struct page *page, int order)
-{
-#ifdef CONFIG_MMU
-       set_page_count(page, 1);
-#else
-       int i;
-
-       /*
-        * We need to reference all the pages for this order, otherwise if
-        * anyone accesses one of the pages with (get/put) it will be freed.
-        */
-       for (i = 0; i < (1 << order); i++)
-               set_page_count(page+i, 1);
-#endif /* CONFIG_MMU */
 }
 
 /*
  * This page is about to be returned from the page allocator
  */
-static void prep_new_page(struct page *page, int order)
+static int prep_new_page(struct page *page, int order, gfp_t gfp_flags)
 {
-       if (page->mapping || page_mapped(page) ||
-           (page->flags & (
+       if (unlikely(page_mapcount(page) |
+               (page->mapping != NULL)  |
+               (page_count(page) != 0)  |
+               (page->flags & (
+                       1 << PG_lru     |
                        1 << PG_private |
                        1 << PG_locked  |
-                       1 << PG_lru     |
                        1 << PG_active  |
                        1 << PG_dirty   |
                        1 << PG_reclaim |
-                       1 << PG_maplock |
-                       1 << PG_anon    |
+                       1 << PG_slab    |
                        1 << PG_swapcache |
-                       1 << PG_writeback )))
-               bad_page(__FUNCTION__, page);
+                       1 << PG_writeback |
+                       1 << PG_reserved |
+                       1 << PG_buddy ))))
+               bad_page(page);
+
+       /*
+        * For now, we report if PG_reserved was found set, but do not
+        * clear it, and do not allocate the page: as a safety net.
+        */
+       if (PageReserved(page))
+               return 1;
 
        page->flags &= ~(1 << PG_uptodate | 1 << PG_error |
                        1 << PG_referenced | 1 << PG_arch_1 |
                        1 << PG_checked | 1 << PG_mappedtodisk);
-       page->private = 0;
-       set_page_refs(page, order);
+       set_page_private(page, 0);
+       set_page_refcounted(page);
+       kernel_map_pages(page, 1 << order, 1);
+
+       if (gfp_flags & __GFP_ZERO)
+               prep_zero_page(page, order, gfp_flags);
+
+       if (order && (gfp_flags & __GFP_COMP))
+               prep_compound_page(page, order);
+
+       return 0;
 }
 
 /* 
@@ -362,7 +569,6 @@ static struct page *__rmqueue(struct zone *zone, unsigned int order)
        struct free_area * area;
        unsigned int current_order;
        struct page *page;
-       unsigned int index;
 
        for (current_order = order; current_order < MAX_ORDER; ++current_order) {
                area = zone->free_area + current_order;
@@ -371,11 +577,11 @@ static struct page *__rmqueue(struct zone *zone, unsigned int order)
 
                page = list_entry(area->free_list.next, struct page, lru);
                list_del(&page->lru);
-               index = page - zone->zone_mem_map;
-               if (current_order != MAX_ORDER-1)
-                       MARK_USED(index, current_order, area);
+               rmv_page_order(page);
+               area->nr_free--;
                zone->free_pages -= 1UL << order;
-               return expand(zone, page, index, order, current_order, area);
+               expand(zone, page, order, current_order, area);
+               return page;
        }
 
        return NULL;
@@ -389,65 +595,100 @@ static struct page *__rmqueue(struct zone *zone, unsigned int order)
 static int rmqueue_bulk(struct zone *zone, unsigned int order, 
                        unsigned long count, struct list_head *list)
 {
-       unsigned long flags;
        int i;
-       int allocated = 0;
-       struct page *page;
        
-       spin_lock_irqsave(&zone->lock, flags);
+       spin_lock(&zone->lock);
        for (i = 0; i < count; ++i) {
-               page = __rmqueue(zone, order);
-               if (page == NULL)
+               struct page *page = __rmqueue(zone, order);
+               if (unlikely(page == NULL))
                        break;
-               allocated++;
                list_add_tail(&page->lru, list);
        }
-       spin_unlock_irqrestore(&zone->lock, flags);
-       return allocated;
+       spin_unlock(&zone->lock);
+       return i;
+}
+
+#ifdef CONFIG_NUMA
+/*
+ * Called from the slab reaper to drain pagesets on a particular node that
+ * belong to the currently executing processor.
+ * Note that this function must be called with the thread pinned to
+ * a single processor.
+ */
+void drain_node_pages(int nodeid)
+{
+       int i, z;
+       unsigned long flags;
+
+       for (z = 0; z < MAX_NR_ZONES; z++) {
+               struct zone *zone = NODE_DATA(nodeid)->node_zones + z;
+               struct per_cpu_pageset *pset;
+
+               pset = zone_pcp(zone, smp_processor_id());
+               for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) {
+                       struct per_cpu_pages *pcp;
+
+                       pcp = &pset->pcp[i];
+                       if (pcp->count) {
+                               local_irq_save(flags);
+                               free_pages_bulk(zone, pcp->count, &pcp->list, 0);
+                               pcp->count = 0;
+                               local_irq_restore(flags);
+                       }
+               }
+       }
 }
+#endif
 
 #if defined(CONFIG_PM) || defined(CONFIG_HOTPLUG_CPU)
 static void __drain_pages(unsigned int cpu)
 {
+       unsigned long flags;
        struct zone *zone;
        int i;
 
        for_each_zone(zone) {
                struct per_cpu_pageset *pset;
 
-               pset = &zone->pageset[cpu];
+               pset = zone_pcp(zone, cpu);
                for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) {
                        struct per_cpu_pages *pcp;
 
                        pcp = &pset->pcp[i];
-                       pcp->count -= free_pages_bulk(zone, pcp->count,
-                                               &pcp->list, 0);
+                       local_irq_save(flags);
+                       free_pages_bulk(zone, pcp->count, &pcp->list, 0);
+                       pcp->count = 0;
+                       local_irq_restore(flags);
                }
        }
 }
 #endif /* CONFIG_PM || CONFIG_HOTPLUG_CPU */
 
 #ifdef CONFIG_PM
-int is_head_of_free_region(struct page *page)
+
+void mark_free_pages(struct zone *zone)
 {
-        struct zone *zone = page_zone(page);
-        unsigned long flags;
+       unsigned long zone_pfn, flags;
        int order;
        struct list_head *curr;
 
-       /*
-        * Should not matter as we need quiescent system for
-        * suspend anyway, but...
-        */
+       if (!zone->spanned_pages)
+               return;
+
        spin_lock_irqsave(&zone->lock, flags);
+       for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn)
+               ClearPageNosaveFree(pfn_to_page(zone_pfn + zone->zone_start_pfn));
+
        for (order = MAX_ORDER - 1; order >= 0; --order)
-               list_for_each(curr, &zone->free_area[order].free_list)
-                       if (page == list_entry(curr, struct page, lru)) {
-                               spin_unlock_irqrestore(&zone->lock, flags);
-                               return 1 << order;
-                       }
+               list_for_each(curr, &zone->free_area[order].free_list) {
+                       unsigned long start_pfn, i;
+
+                       start_pfn = page_to_pfn(list_entry(curr, struct page, lru));
+
+                       for (i=0; i < (1<<order); i++)
+                               SetPageNosaveFree(pfn_to_page(start_pfn+i));
+       }
        spin_unlock_irqrestore(&zone->lock, flags);
-        return 0;
 }
 
 /*
@@ -463,51 +704,59 @@ void drain_local_pages(void)
 }
 #endif /* CONFIG_PM */
 
-static void zone_statistics(struct zonelist *zonelist, struct zone *z)
+static void zone_statistics(struct zonelist *zonelist, struct zone *z, int cpu)
 {
 #ifdef CONFIG_NUMA
-       unsigned long flags;
-       int cpu;
        pg_data_t *pg = z->zone_pgdat;
        pg_data_t *orig = zonelist->zones[0]->zone_pgdat;
        struct per_cpu_pageset *p;
 
-       local_irq_save(flags);
-       cpu = smp_processor_id();
-       p = &z->pageset[cpu];
+       p = zone_pcp(z, cpu);
        if (pg == orig) {
-               z->pageset[cpu].numa_hit++;
+               p->numa_hit++;
        } else {
                p->numa_miss++;
-               zonelist->zones[0]->pageset[cpu].numa_foreign++;
+               zone_pcp(zonelist->zones[0], cpu)->numa_foreign++;
        }
        if (pg == NODE_DATA(numa_node_id()))
                p->local_node++;
        else
                p->other_node++;
-       local_irq_restore(flags);
 #endif
 }
 
 /*
  * Free a 0-order page
  */
-static void FASTCALL(free_hot_cold_page(struct page *page, int cold));
 static void fastcall free_hot_cold_page(struct page *page, int cold)
 {
        struct zone *zone = page_zone(page);
        struct per_cpu_pages *pcp;
        unsigned long flags;
 
+       arch_free_page(page, 0);
+
+       if (PageAnon(page))
+               page->mapping = NULL;
+       if (free_pages_check(page))
+               return;
+
        kernel_map_pages(page, 1, 0);
-       inc_page_state(pgfree);
-       free_pages_check(__FUNCTION__, page);
-       pcp = &zone->pageset[get_cpu()].pcp[cold];
+
+       pcp = &zone_pcp(zone, get_cpu())->pcp[cold];
        local_irq_save(flags);
-       if (pcp->count >= pcp->high)
-               pcp->count -= free_pages_bulk(zone, pcp->batch, &pcp->list, 0);
+       __inc_page_state(pgfree);
        list_add(&page->lru, &pcp->list);
        pcp->count++;
+       if (pcp->count >= pcp->high) {
+               free_pages_bulk(zone, pcp->batch, &pcp->list, 0);
+               pcp->count -= pcp->batch;
+       } else if (zone->all_unreclaimable) {
+               spin_lock(&zone->lock);
+               zone->all_unreclaimable = 0;
+               zone->pages_scanned = 0;
+               spin_unlock(&zone->lock);
+       }
        local_irq_restore(flags);
        put_cpu();
 }
@@ -522,150 +771,240 @@ void fastcall free_cold_page(struct page *page)
        free_hot_cold_page(page, 1);
 }
 
+/*
+ * split_page takes a non-compound higher-order page, and splits it into
+ * n (1<<order) sub-pages: page[0..n]
+ * Each sub-page must be freed individually.
+ *
+ * Note: this is probably too low level an operation for use in drivers.
+ * Please consult with lkml before using this in your driver.
+ */
+void split_page(struct page *page, unsigned int order)
+{
+       int i;
+
+       BUG_ON(PageCompound(page));
+       BUG_ON(!page_count(page));
+       for (i = 1; i < (1 << order); i++)
+               set_page_refcounted(page + i);
+}
+
 /*
  * Really, prep_compound_page() should be called from __rmqueue_bulk().  But
  * we cheat by calling it from here, in the order > 0 path.  Saves a branch
  * or two.
  */
-
-static struct page *
-buffered_rmqueue(struct zone *zone, int order, int gfp_flags)
+static struct page *buffered_rmqueue(struct zonelist *zonelist,
+                       struct zone *zone, int order, gfp_t gfp_flags)
 {
        unsigned long flags;
-       struct page *page = NULL;
+       struct page *page;
        int cold = !!(gfp_flags & __GFP_COLD);
+       int cpu;
 
-       if (order == 0) {
+again:
+       cpu  = get_cpu();
+       if (likely(order == 0)) {
                struct per_cpu_pages *pcp;
 
-               pcp = &zone->pageset[get_cpu()].pcp[cold];
+               pcp = &zone_pcp(zone, cpu)->pcp[cold];
                local_irq_save(flags);
-               if (pcp->count <= pcp->low)
+               if (!pcp->count) {
                        pcp->count += rmqueue_bulk(zone, 0,
                                                pcp->batch, &pcp->list);
-               if (pcp->count) {
-                       page = list_entry(pcp->list.next, struct page, lru);
-                       list_del(&page->lru);
-                       pcp->count--;
+                       if (unlikely(!pcp->count))
+                               goto failed;
                }
-               local_irq_restore(flags);
-               put_cpu();
-       }
-
-       if (page == NULL) {
+               page = list_entry(pcp->list.next, struct page, lru);
+               list_del(&page->lru);
+               pcp->count--;
+       } else {
                spin_lock_irqsave(&zone->lock, flags);
                page = __rmqueue(zone, order);
-               spin_unlock_irqrestore(&zone->lock, flags);
+               spin_unlock(&zone->lock);
+               if (!page)
+                       goto failed;
        }
 
-       if (page != NULL) {
-               BUG_ON(bad_range(zone, page));
-               mod_page_state_zone(zone, pgalloc, 1 << order);
-               prep_new_page(page, order);
-               if (order && (gfp_flags & __GFP_COMP))
-                       prep_compound_page(page, order);
+       __mod_page_state_zone(zone, pgalloc, 1 << order);
+       zone_statistics(zonelist, zone, cpu);
+       local_irq_restore(flags);
+       put_cpu();
+
+       BUG_ON(bad_range(zone, page));
+       if (prep_new_page(page, order, gfp_flags))
+               goto again;
+       return page;
+
+failed:
+       local_irq_restore(flags);
+       put_cpu();
+       return NULL;
+}
+
+#define ALLOC_NO_WATERMARKS    0x01 /* don't check watermarks at all */
+#define ALLOC_WMARK_MIN                0x02 /* use pages_min watermark */
+#define ALLOC_WMARK_LOW                0x04 /* use pages_low watermark */
+#define ALLOC_WMARK_HIGH       0x08 /* use pages_high watermark */
+#define ALLOC_HARDER           0x10 /* try to alloc harder */
+#define ALLOC_HIGH             0x20 /* __GFP_HIGH set */
+#define ALLOC_CPUSET           0x40 /* check for correct cpuset */
+
+/*
+ * Return 1 if free pages are above 'mark'. This takes into account the order
+ * of the allocation.
+ */
+int zone_watermark_ok(struct zone *z, int order, unsigned long mark,
+                     int classzone_idx, int alloc_flags)
+{
+       /* free_pages my go negative - that's OK */
+       long min = mark, free_pages = z->free_pages - (1 << order) + 1;
+       int o;
+
+       if (alloc_flags & ALLOC_HIGH)
+               min -= min / 2;
+       if (alloc_flags & ALLOC_HARDER)
+               min -= min / 4;
+
+       if (free_pages <= min + z->lowmem_reserve[classzone_idx])
+               return 0;
+       for (o = 0; o < order; o++) {
+               /* At the next order, this order's pages become unavailable */
+               free_pages -= z->free_area[o].nr_free << o;
+
+               /* Require fewer higher order pages to be free */
+               min >>= 1;
+
+               if (free_pages <= min)
+                       return 0;
        }
+       return 1;
+}
+
+/*
+ * get_page_from_freeliest goes through the zonelist trying to allocate
+ * a page.
+ */
+static struct page *
+get_page_from_freelist(gfp_t gfp_mask, unsigned int order,
+               struct zonelist *zonelist, int alloc_flags)
+{
+       struct zone **z = zonelist->zones;
+       struct page *page = NULL;
+       int classzone_idx = zone_idx(*z);
+
+       /*
+        * Go through the zonelist once, looking for a zone with enough free.
+        * See also cpuset_zone_allowed() comment in kernel/cpuset.c.
+        */
+       do {
+               if ((alloc_flags & ALLOC_CPUSET) &&
+                               !cpuset_zone_allowed(*z, gfp_mask))
+                       continue;
+
+               if (!(alloc_flags & ALLOC_NO_WATERMARKS)) {
+                       unsigned long mark;
+                       if (alloc_flags & ALLOC_WMARK_MIN)
+                               mark = (*z)->pages_min;
+                       else if (alloc_flags & ALLOC_WMARK_LOW)
+                               mark = (*z)->pages_low;
+                       else
+                               mark = (*z)->pages_high;
+                       if (!zone_watermark_ok(*z, order, mark,
+                                   classzone_idx, alloc_flags))
+                               if (!zone_reclaim_mode ||
+                                   !zone_reclaim(*z, gfp_mask, order))
+                                       continue;
+               }
+
+               page = buffered_rmqueue(zonelist, *z, order, gfp_mask);
+               if (page) {
+                       break;
+               }
+       } while (*(++z) != NULL);
        return page;
 }
 
 /*
  * This is the 'heart' of the zoned buddy allocator.
- *
- * Herein lies the mysterious "incremental min".  That's the
- *
- *     local_low = z->pages_low;
- *     min += local_low;
- *
- * thing.  The intent here is to provide additional protection to low zones for
- * allocation requests which _could_ use higher zones.  So a GFP_HIGHMEM
- * request is not allowed to dip as deeply into the normal zone as a GFP_KERNEL
- * request.  This preserves additional space in those lower zones for requests
- * which really do need memory from those zones.  It means that on a decent
- * sized machine, GFP_HIGHMEM and GFP_KERNEL requests basically leave the DMA
- * zone untouched.
  */
 struct page * fastcall
-__alloc_pages(unsigned int gfp_mask, unsigned int order,
+__alloc_pages(gfp_t gfp_mask, unsigned int order,
                struct zonelist *zonelist)
 {
-       const int wait = gfp_mask & __GFP_WAIT;
-       unsigned long min;
-       struct zone **zones;
+       const gfp_t wait = gfp_mask & __GFP_WAIT;
+       struct zone **z;
        struct page *page;
        struct reclaim_state reclaim_state;
        struct task_struct *p = current;
-       int i;
-       int alloc_type;
        int do_retry;
+       int alloc_flags;
+       int did_some_progress;
 
        might_sleep_if(wait);
 
-       zones = zonelist->zones;  /* the list of zones suitable for gfp_mask */
-       if (zones[0] == NULL)     /* no zones in the zonelist */
-               return NULL;
+restart:
+       z = zonelist->zones;  /* the list of zones suitable for gfp_mask */
 
-       alloc_type = zone_idx(zones[0]);
-
-       /* Go through the zonelist once, looking for a zone with enough free */
-       for (i = 0; zones[i] != NULL; i++) {
-               struct zone *z = zones[i];
-
-               min = (1<<order) + z->protection[alloc_type];
-
-               /*
-                * We let real-time tasks dip their real-time paws a little
-                * deeper into reserves.
-                */
-               if (rt_task(p))
-                       min -= z->pages_low >> 1;
-
-               if (z->free_pages >= min ||
-                               (!wait && z->free_pages >= z->pages_high)) {
-                       page = buffered_rmqueue(z, order, gfp_mask);
-                       if (page) {
-                               zone_statistics(zonelist, z);
-                               goto got_pg;
-                       }
-               }
+       if (unlikely(*z == NULL)) {
+               /* Should this ever happen?? */
+               return NULL;
        }
 
-       /* we're somewhat low on memory, failed to find what we needed */
-       for (i = 0; zones[i] != NULL; i++)
-               wakeup_kswapd(zones[i]);
+       page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, order,
+                               zonelist, ALLOC_WMARK_LOW|ALLOC_CPUSET);
+       if (page)
+               goto got_pg;
 
-       /* Go through the zonelist again, taking __GFP_HIGH into account */
-       for (i = 0; zones[i] != NULL; i++) {
-               struct zone *z = zones[i];
+       do {
+               if (cpuset_zone_allowed(*z, gfp_mask|__GFP_HARDWALL))
+                       wakeup_kswapd(*z, order);
+       } while (*(++z));
 
-               min = (1<<order) + z->protection[alloc_type];
-
-               if (gfp_mask & __GFP_HIGH)
-                       min -= z->pages_low >> 2;
-               if (rt_task(p))
-                       min -= z->pages_low >> 1;
-
-               if (z->free_pages >= min ||
-                               (!wait && z->free_pages >= z->pages_high)) {
-                       page = buffered_rmqueue(z, order, gfp_mask);
-                       if (page) {
-                               zone_statistics(zonelist, z);
-                               goto got_pg;
-                       }
-               }
-       }
-
-       /* here we're in the low on memory slow path */
+       /*
+        * OK, we're below the kswapd watermark and have kicked background
+        * reclaim. Now things get more complex, so set up alloc_flags according
+        * to how we want to proceed.
+        *
+        * The caller may dip into page reserves a bit more if the caller
+        * cannot run direct reclaim, or if the caller has realtime scheduling
+        * policy or is asking for __GFP_HIGH memory.  GFP_ATOMIC requests will
+        * set both ALLOC_HARDER (!wait) and ALLOC_HIGH (__GFP_HIGH).
+        */
+       alloc_flags = ALLOC_WMARK_MIN;
+       if ((unlikely(rt_task(p)) && !in_interrupt()) || !wait)
+               alloc_flags |= ALLOC_HARDER;
+       if (gfp_mask & __GFP_HIGH)
+               alloc_flags |= ALLOC_HIGH;
+       if (wait)
+               alloc_flags |= ALLOC_CPUSET;
 
-rebalance:
-       if ((p->flags & (PF_MEMALLOC | PF_MEMDIE)) && !in_interrupt()) {
-               /* go through the zonelist yet again, ignoring mins */
-               for (i = 0; zones[i] != NULL; i++) {
-                       struct zone *z = zones[i];
-
-                       page = buffered_rmqueue(z, order, gfp_mask);
-                       if (page) {
-                               zone_statistics(zonelist, z);
+       /*
+        * Go through the zonelist again. Let __GFP_HIGH and allocations
+        * coming from realtime tasks go deeper into reserves.
+        *
+        * This is the last chance, in general, before the goto nopage.
+        * Ignore cpuset if GFP_ATOMIC (!wait) rather than fail alloc.
+        * See also cpuset_zone_allowed() comment in kernel/cpuset.c.
+        */
+       page = get_page_from_freelist(gfp_mask, order, zonelist, alloc_flags);
+       if (page)
+               goto got_pg;
+
+       /* This allocation should allow future memory freeing. */
+
+       if (((p->flags & PF_MEMALLOC) || unlikely(test_thread_flag(TIF_MEMDIE)))
+                       && !in_interrupt()) {
+               if (!(gfp_mask & __GFP_NOMEMALLOC)) {
+nofail_alloc:
+                       /* go through the zonelist yet again, ignoring mins */
+                       page = get_page_from_freelist(gfp_mask, order,
+                               zonelist, ALLOC_NO_WATERMARKS);
+                       if (page)
                                goto got_pg;
+                       if (gfp_mask & __GFP_NOFAIL) {
+                               blk_congestion_wait(WRITE, HZ/50);
+                               goto nofail_alloc;
                        }
                }
                goto nopage;
@@ -675,37 +1014,49 @@ rebalance:
        if (!wait)
                goto nopage;
 
+rebalance:
+       cond_resched();
+
+       /* We now go into synchronous reclaim */
+       cpuset_memory_pressure_bump();
        p->flags |= PF_MEMALLOC;
        reclaim_state.reclaimed_slab = 0;
        p->reclaim_state = &reclaim_state;
 
-       try_to_free_pages(zones, gfp_mask, order);
+       did_some_progress = try_to_free_pages(zonelist->zones, gfp_mask);
 
        p->reclaim_state = NULL;
        p->flags &= ~PF_MEMALLOC;
 
-       /* go through the zonelist yet one more time */
-       for (i = 0; zones[i] != NULL; i++) {
-               struct zone *z = zones[i];
+       cond_resched();
 
-               min = (1UL << order) + z->protection[alloc_type];
+       if (likely(did_some_progress)) {
+               page = get_page_from_freelist(gfp_mask, order,
+                                               zonelist, alloc_flags);
+               if (page)
+                       goto got_pg;
+       } else if ((gfp_mask & __GFP_FS) && !(gfp_mask & __GFP_NORETRY)) {
+               /*
+                * Go through the zonelist yet one more time, keep
+                * very high watermark here, this is only to catch
+                * a parallel oom killing, we must fail if we're still
+                * under heavy pressure.
+                */
+               page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, order,
+                               zonelist, ALLOC_WMARK_HIGH|ALLOC_CPUSET);
+               if (page)
+                       goto got_pg;
 
-               if (z->free_pages >= min ||
-                               (!wait && z->free_pages >= z->pages_high)) {
-                       page = buffered_rmqueue(z, order, gfp_mask);
-                       if (page) {
-                               zone_statistics(zonelist, z);
-                               goto got_pg;
-                       }
-               }
+               out_of_memory(zonelist, gfp_mask, order);
+               goto restart;
        }
 
        /*
         * Don't let big-order allocations loop unless the caller explicitly
         * requests that.  Wait for some write requests to complete then retry.
         *
-        * In this implementation, __GFP_REPEAT means __GFP_NOFAIL, but that
-        * may not be true in other implementations.
+        * In this implementation, __GFP_REPEAT means __GFP_NOFAIL for order
+        * <= 3, but that may not be true in other implementations.
         */
        do_retry = 0;
        if (!(gfp_mask & __GFP_NORETRY)) {
@@ -725,62 +1076,20 @@ nopage:
                        " order:%d, mode:0x%x\n",
                        p->comm, order, gfp_mask);
                dump_stack();
+               show_mem();
        }
-       return NULL;
 got_pg:
-       kernel_map_pages(page, 1 << order, 1);
        return page;
 }
 
 EXPORT_SYMBOL(__alloc_pages);
 
-#ifdef CONFIG_NUMA
-/* Early boot: Everything is done by one cpu, but the data structures will be
- * used by all cpus - spread them on all nodes.
- */
-static __init unsigned long get_boot_pages(unsigned int gfp_mask, unsigned int order)
-{
-static int nodenr;
-       int i = nodenr;
-       struct page *page;
-
-       for (;;) {
-               if (i > nodenr + numnodes)
-                       return 0;
-               if (node_present_pages(i%numnodes)) {
-                       struct zone **z;
-                       /* The node contains memory. Check that there is
-                        * memory in the intended zonelist.
-                        */
-                       z = NODE_DATA(i%numnodes)->node_zonelists[gfp_mask & GFP_ZONEMASK].zones;
-                       while (*z) {
-                               if ( (*z)->free_pages > (1UL<<order))
-                                       goto found_node;
-                               z++;
-                       }
-               }
-               i++;
-       }
-found_node:
-       nodenr = i+1;
-       page = alloc_pages_node(i%numnodes, gfp_mask, order);
-       if (!page)
-               return 0;
-       return (unsigned long) page_address(page);
-}
-#endif
-
 /*
  * Common helper functions.
  */
-fastcall unsigned long __get_free_pages(unsigned int gfp_mask, unsigned int order)
+fastcall unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)
 {
        struct page * page;
-
-#ifdef CONFIG_NUMA
-       if (unlikely(system_state == SYSTEM_BOOTING))
-               return get_boot_pages(gfp_mask, order);
-#endif
        page = alloc_pages(gfp_mask, order);
        if (!page)
                return 0;
@@ -789,7 +1098,7 @@ fastcall unsigned long __get_free_pages(unsigned int gfp_mask, unsigned int orde
 
 EXPORT_SYMBOL(__get_free_pages);
 
-fastcall unsigned long get_zeroed_page(unsigned int gfp_mask)
+fastcall unsigned long get_zeroed_page(gfp_t gfp_mask)
 {
        struct page * page;
 
@@ -797,14 +1106,11 @@ fastcall unsigned long get_zeroed_page(unsigned int gfp_mask)
         * get_zeroed_page() returns a 32-bit address, which cannot represent
         * a highmem page
         */
-       BUG_ON(gfp_mask & __GFP_HIGHMEM);
+       BUG_ON((gfp_mask & __GFP_HIGHMEM) != 0);
 
-       page = alloc_pages(gfp_mask, 0);
-       if (page) {
-               void *address = page_address(page);
-               clear_page(address);
-               return (unsigned long) address;
-       }
+       page = alloc_pages(gfp_mask | __GFP_ZERO, 0);
+       if (page)
+               return (unsigned long) page_address(page);
        return 0;
 }
 
@@ -820,7 +1126,7 @@ void __pagevec_free(struct pagevec *pvec)
 
 fastcall void __free_pages(struct page *page, unsigned int order)
 {
-       if (!PageReserved(page) && put_page_testzero(page)) {
+       if (put_page_testzero(page)) {
                if (order == 0)
                        free_hot_page(page);
                else
@@ -833,8 +1139,8 @@ EXPORT_SYMBOL(__free_pages);
 fastcall void free_pages(unsigned long addr, unsigned int order)
 {
        if (addr != 0) {
-               BUG_ON(!virt_addr_valid(addr));
-               __free_pages(virt_to_page(addr), order);
+               BUG_ON(!virt_addr_valid((void *)addr));
+               __free_pages(virt_to_page((void *)addr), order);
        }
 }
 
@@ -856,17 +1162,6 @@ unsigned int nr_free_pages(void)
 
 EXPORT_SYMBOL(nr_free_pages);
 
-unsigned int nr_used_zone_pages(void)
-{
-       unsigned int pages = 0;
-       struct zone *zone;
-
-       for_each_zone(zone)
-               pages += zone->nr_active + zone->nr_inactive;
-
-       return pages;
-}
-
 #ifdef CONFIG_NUMA
 unsigned int nr_free_pages_pgdat(pg_data_t *pgdat)
 {
@@ -881,20 +1176,19 @@ unsigned int nr_free_pages_pgdat(pg_data_t *pgdat)
 
 static unsigned int nr_free_zone_pages(int offset)
 {
-       pg_data_t *pgdat;
+       /* Just pick one node, since fallback list is circular */
+       pg_data_t *pgdat = NODE_DATA(numa_node_id());
        unsigned int sum = 0;
 
-       for_each_pgdat(pgdat) {
-               struct zonelist *zonelist = pgdat->node_zonelists + offset;
-               struct zone **zonep = zonelist->zones;
-               struct zone *zone;
+       struct zonelist *zonelist = pgdat->node_zonelists + offset;
+       struct zone **zonep = zonelist->zones;
+       struct zone *zone;
 
-               for (zone = *zonep++; zone; zone = *zonep++) {
-                       unsigned long size = zone->present_pages;
-                       unsigned long high = zone->pages_high;
-                       if (size > high)
-                               sum += size - high;
-               }
+       for (zone = *zonep++; zone; zone = *zonep++) {
+               unsigned long size = zone->present_pages;
+               unsigned long high = zone->pages_high;
+               if (size > high)
+                       sum += size - high;
        }
 
        return sum;
@@ -905,7 +1199,7 @@ static unsigned int nr_free_zone_pages(int offset)
  */
 unsigned int nr_free_buffer_pages(void)
 {
-       return nr_free_zone_pages(GFP_USER & GFP_ZONEMASK);
+       return nr_free_zone_pages(gfp_zone(GFP_USER));
 }
 
 /*
@@ -913,7 +1207,7 @@ unsigned int nr_free_buffer_pages(void)
  */
 unsigned int nr_free_pagecache_pages(void)
 {
-       return nr_free_zone_pages(GFP_HIGHUSER & GFP_ZONEMASK);
+       return nr_free_zone_pages(gfp_zone(GFP_HIGHUSER));
 }
 
 #ifdef CONFIG_HIGHMEM
@@ -922,7 +1216,7 @@ unsigned int nr_free_highpages (void)
        pg_data_t *pgdat;
        unsigned int pages = 0;
 
-       for_each_pgdat(pgdat)
+       for_each_online_pgdat(pgdat)
                pages += pgdat->node_zones[ZONE_HIGHMEM].free_pages;
 
        return pages;
@@ -943,8 +1237,7 @@ static void show_node(struct zone *zone)
  * The result is unavoidably approximate - it can change
  * during and after execution of this function.
  */
-DEFINE_PER_CPU(struct page_state, page_states) = {0};
-EXPORT_PER_CPU_SYMBOL(page_states);
+static DEFINE_PER_CPU(struct page_state, page_states) = {0};
 
 atomic_t nr_pagecache = ATOMIC_INIT(0);
 EXPORT_SYMBOL(nr_pagecache);
@@ -952,73 +1245,125 @@ EXPORT_SYMBOL(nr_pagecache);
 DEFINE_PER_CPU(long, nr_pagecache_local) = 0;
 #endif
 
-void __get_page_state(struct page_state *ret, int nr)
+static void __get_page_state(struct page_state *ret, int nr, cpumask_t *cpumask)
 {
-       int cpu = 0;
+       unsigned cpu;
 
-       memset(ret, 0, sizeof(*ret));
-       while (cpu < NR_CPUS) {
-               unsigned long *in, *out, off;
+       memset(ret, 0, nr * sizeof(unsigned long));
+       cpus_and(*cpumask, *cpumask, cpu_online_map);
 
-               if (!cpu_possible(cpu)) {
-                       cpu++;
-                       continue;
-               }
+       for_each_cpu_mask(cpu, *cpumask) {
+               unsigned long *in;
+               unsigned long *out;
+               unsigned off;
+               unsigned next_cpu;
 
                in = (unsigned long *)&per_cpu(page_states, cpu);
-               cpu++;
-               if (cpu < NR_CPUS && cpu_possible(cpu))
-                       prefetch(&per_cpu(page_states, cpu));
+
+               next_cpu = next_cpu(cpu, *cpumask);
+               if (likely(next_cpu < NR_CPUS))
+                       prefetch(&per_cpu(page_states, next_cpu));
+
                out = (unsigned long *)ret;
                for (off = 0; off < nr; off++)
                        *out++ += *in++;
        }
 }
 
+void get_page_state_node(struct page_state *ret, int node)
+{
+       int nr;
+       cpumask_t mask = node_to_cpumask(node);
+
+       nr = offsetof(struct page_state, GET_PAGE_STATE_LAST);
+       nr /= sizeof(unsigned long);
+
+       __get_page_state(ret, nr+1, &mask);
+}
+
 void get_page_state(struct page_state *ret)
 {
        int nr;
+       cpumask_t mask = CPU_MASK_ALL;
 
        nr = offsetof(struct page_state, GET_PAGE_STATE_LAST);
        nr /= sizeof(unsigned long);
 
-       __get_page_state(ret, nr + 1);
+       __get_page_state(ret, nr + 1, &mask);
 }
 
 void get_full_page_state(struct page_state *ret)
 {
-       __get_page_state(ret, sizeof(*ret) / sizeof(unsigned long));
+       cpumask_t mask = CPU_MASK_ALL;
+
+       __get_page_state(ret, sizeof(*ret) / sizeof(unsigned long), &mask);
 }
 
-unsigned long __read_page_state(unsigned offset)
+unsigned long read_page_state_offset(unsigned long offset)
 {
        unsigned long ret = 0;
        int cpu;
 
-       for (cpu = 0; cpu < NR_CPUS; cpu++) {
+       for_each_online_cpu(cpu) {
                unsigned long in;
 
-               if (!cpu_possible(cpu))
-                       continue;
-
                in = (unsigned long)&per_cpu(page_states, cpu) + offset;
                ret += *((unsigned long *)in);
        }
        return ret;
 }
 
+void __mod_page_state_offset(unsigned long offset, unsigned long delta)
+{
+       void *ptr;
+
+       ptr = &__get_cpu_var(page_states);
+       *(unsigned long *)(ptr + offset) += delta;
+}
+EXPORT_SYMBOL(__mod_page_state_offset);
+
+void mod_page_state_offset(unsigned long offset, unsigned long delta)
+{
+       unsigned long flags;
+       void *ptr;
+
+       local_irq_save(flags);
+       ptr = &__get_cpu_var(page_states);
+       *(unsigned long *)(ptr + offset) += delta;
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL(mod_page_state_offset);
+
+void __get_zone_counts(unsigned long *active, unsigned long *inactive,
+                       unsigned long *free, struct pglist_data *pgdat)
+{
+       struct zone *zones = pgdat->node_zones;
+       int i;
+
+       *active = 0;
+       *inactive = 0;
+       *free = 0;
+       for (i = 0; i < MAX_NR_ZONES; i++) {
+               *active += zones[i].nr_active;
+               *inactive += zones[i].nr_inactive;
+               *free += zones[i].free_pages;
+       }
+}
+
 void get_zone_counts(unsigned long *active,
                unsigned long *inactive, unsigned long *free)
 {
-       struct zone *zone;
+       struct pglist_data *pgdat;
 
        *active = 0;
        *inactive = 0;
        *free = 0;
-       for_each_zone(zone) {
-               *active += zone->nr_active;
-               *inactive += zone->nr_inactive;
-               *free += zone->free_pages;
+       for_each_online_pgdat(pgdat) {
+               unsigned long l, m, n;
+               __get_zone_counts(&l, &m, &n, pgdat);
+               *active += l;
+               *inactive += m;
+               *free += n;
        }
 }
 
@@ -1052,6 +1397,8 @@ void si_meminfo_node(struct sysinfo *val, int nid)
        val->totalhigh = pgdat->node_zones[ZONE_HIGHMEM].present_pages;
        val->freehigh = pgdat->node_zones[ZONE_HIGHMEM].free_pages;
        val->mem_unit = PAGE_SIZE;
+       if (vx_flags(VXF_VIRT_MEM, 0))
+               vx_vsi_meminfo(val);
 }
 #endif
 
@@ -1075,34 +1422,31 @@ void show_free_areas(void)
                show_node(zone);
                printk("%s per-cpu:", zone->name);
 
-               if (!zone->present_pages) {
+               if (!populated_zone(zone)) {
                        printk(" empty\n");
                        continue;
                } else
                        printk("\n");
 
-               for (cpu = 0; cpu < NR_CPUS; ++cpu) {
+               for_each_online_cpu(cpu) {
                        struct per_cpu_pageset *pageset;
 
-                       if (!cpu_possible(cpu))
-                               continue;
-
-                       pageset = zone->pageset + cpu;
+                       pageset = zone_pcp(zone, cpu);
 
                        for (temperature = 0; temperature < 2; temperature++)
-                               printk("cpu %d %s: low %d, high %d, batch %d\n",
+                               printk("cpu %d %s: high %d, batch %d used:%d\n",
                                        cpu,
                                        temperature ? "cold" : "hot",
-                                       pageset->pcp[temperature].low,
                                        pageset->pcp[temperature].high,
-                                       pageset->pcp[temperature].batch);
+                                       pageset->pcp[temperature].batch,
+                                       pageset->pcp[temperature].count);
                }
        }
 
        get_page_state(&ps);
        get_zone_counts(&active, &inactive, &free);
 
-       printk("\nFree pages: %11ukB (%ukB HighMem)\n",
+       printk("Free pages: %11ukB (%ukB HighMem)\n",
                K(nr_free_pages()),
                K(nr_free_highpages()));
 
@@ -1130,6 +1474,8 @@ void show_free_areas(void)
                        " active:%lukB"
                        " inactive:%lukB"
                        " present:%lukB"
+                       " pages_scanned:%lu"
+                       " all_unreclaimable? %s"
                        "\n",
                        zone->name,
                        K(zone->free_pages),
@@ -1138,30 +1484,29 @@ void show_free_areas(void)
                        K(zone->pages_high),
                        K(zone->nr_active),
                        K(zone->nr_inactive),
-                       K(zone->present_pages)
+                       K(zone->present_pages),
+                       zone->pages_scanned,
+                       (zone->all_unreclaimable ? "yes" : "no")
                        );
-               printk("protections[]:");
+               printk("lowmem_reserve[]:");
                for (i = 0; i < MAX_NR_ZONES; i++)
-                       printk(" %lu", zone->protection[i]);
+                       printk(" %lu", zone->lowmem_reserve[i]);
                printk("\n");
        }
 
        for_each_zone(zone) {
-               struct list_head *elem;
                unsigned long nr, flags, order, total = 0;
 
                show_node(zone);
                printk("%s: ", zone->name);
-               if (!zone->present_pages) {
+               if (!populated_zone(zone)) {
                        printk("empty\n");
                        continue;
                }
 
                spin_lock_irqsave(&zone->lock, flags);
                for (order = 0; order < MAX_ORDER; order++) {
-                       nr = 0;
-                       list_for_each(elem, &zone->free_area[order].free_list)
-                               ++nr;
+                       nr = zone->free_area[order].nr_free;
                        total += nr << order;
                        printk("%lu*%lukB ", nr, K(1UL) << order);
                }
@@ -1174,42 +1519,50 @@ void show_free_areas(void)
 
 /*
  * Builds allocation fallback zone lists.
+ *
+ * Add all populated zones of a node to the zonelist.
  */
-static int __init build_zonelists_node(pg_data_t *pgdat, struct zonelist *zonelist, int j, int k)
-{
-       switch (k) {
-               struct zone *zone;
-       default:
-               BUG();
-       case ZONE_HIGHMEM:
-               zone = pgdat->node_zones + ZONE_HIGHMEM;
-               if (zone->present_pages) {
+static int __init build_zonelists_node(pg_data_t *pgdat,
+                       struct zonelist *zonelist, int nr_zones, int zone_type)
+{
+       struct zone *zone;
+
+       BUG_ON(zone_type > ZONE_HIGHMEM);
+
+       do {
+               zone = pgdat->node_zones + zone_type;
+               if (populated_zone(zone)) {
 #ifndef CONFIG_HIGHMEM
-                       BUG();
+                       BUG_ON(zone_type > ZONE_NORMAL);
 #endif
-                       zonelist->zones[j++] = zone;
+                       zonelist->zones[nr_zones++] = zone;
+                       check_highest_zone(zone_type);
                }
-       case ZONE_NORMAL:
-               zone = pgdat->node_zones + ZONE_NORMAL;
-               if (zone->present_pages)
-                       zonelist->zones[j++] = zone;
-       case ZONE_DMA:
-               zone = pgdat->node_zones + ZONE_DMA;
-               if (zone->present_pages)
-                       zonelist->zones[j++] = zone;
-       }
+               zone_type--;
 
-       return j;
+       } while (zone_type >= 0);
+       return nr_zones;
+}
+
+static inline int highest_zone(int zone_bits)
+{
+       int res = ZONE_NORMAL;
+       if (zone_bits & (__force int)__GFP_HIGHMEM)
+               res = ZONE_HIGHMEM;
+       if (zone_bits & (__force int)__GFP_DMA32)
+               res = ZONE_DMA32;
+       if (zone_bits & (__force int)__GFP_DMA)
+               res = ZONE_DMA;
+       return res;
 }
 
 #ifdef CONFIG_NUMA
-#define MAX_NODE_LOAD (numnodes)
+#define MAX_NODE_LOAD (num_online_nodes())
 static int __initdata node_load[MAX_NUMNODES];
 /**
- * find_next_best_node - find the next node that should appear in a given
- *    node's fallback list
+ * find_next_best_node - find the next node that should appear in a given node's fallback list
  * @node: node whose fallback list we're appending
- * @used_node_mask: pointer to the bitmap of already used nodes
+ * @used_node_mask: nodemask_t of already used nodes
  *
  * We use a number of factors to determine which is the next node that should
  * appear on a given node's fallback list.  The node should not have appeared
@@ -1220,25 +1573,31 @@ static int __initdata node_load[MAX_NUMNODES];
  * on them otherwise.
  * It returns -1 if no node is found.
  */
-static int __init find_next_best_node(int node, void *used_node_mask)
+static int __init find_next_best_node(int node, nodemask_t *used_node_mask)
 {
-       int i, n, val;
+       int n, val;
        int min_val = INT_MAX;
        int best_node = -1;
 
-       for (i = 0; i < numnodes; i++) {
-               cpumask_t tmp;
+       /* Use the local node if we haven't already */
+       if (!node_isset(node, *used_node_mask)) {
+               node_set(node, *used_node_mask);
+               return node;
+       }
 
-               /* Start from local node */
-               n = (node+i)%numnodes;
+       for_each_online_node(n) {
+               cpumask_t tmp;
 
                /* Don't want a node to appear more than once */
-               if (test_bit(n, used_node_mask))
+               if (node_isset(n, *used_node_mask))
                        continue;
 
                /* Use the distance array to find the distance */
                val = node_distance(node, n);
 
+               /* Penalize nodes under us ("prefer the next node") */
+               val += (n < node);
+
                /* Give preference to headless and unused nodes */
                tmp = node_to_cpumask(n);
                if (!cpus_empty(tmp))
@@ -1255,7 +1614,7 @@ static int __init find_next_best_node(int node, void *used_node_mask)
        }
 
        if (best_node >= 0)
-               set_bit(best_node, used_node_mask);
+               node_set(best_node, *used_node_mask);
 
        return best_node;
 }
@@ -1265,40 +1624,44 @@ static void __init build_zonelists(pg_data_t *pgdat)
        int i, j, k, node, local_node;
        int prev_node, load;
        struct zonelist *zonelist;
-       DECLARE_BITMAP(used_mask, MAX_NUMNODES);
+       nodemask_t used_mask;
 
        /* initialize zonelists */
-       for (i = 0; i < MAX_NR_ZONES; i++) {
+       for (i = 0; i < GFP_ZONETYPES; i++) {
                zonelist = pgdat->node_zonelists + i;
-               memset(zonelist, 0, sizeof(*zonelist));
                zonelist->zones[0] = NULL;
        }
 
        /* NUMA-aware ordering of nodes */
        local_node = pgdat->node_id;
-       load = numnodes;
+       load = num_online_nodes();
        prev_node = local_node;
-       bitmap_zero(used_mask, MAX_NUMNODES);
-       while ((node = find_next_best_node(local_node, used_mask)) >= 0) {
+       nodes_clear(used_mask);
+       while ((node = find_next_best_node(local_node, &used_mask)) >= 0) {
+               int distance = node_distance(local_node, node);
+
+               /*
+                * If another node is sufficiently far away then it is better
+                * to reclaim pages in a zone before going off node.
+                */
+               if (distance > RECLAIM_DISTANCE)
+                       zone_reclaim_mode = 1;
+
                /*
                 * We don't want to pressure a particular node.
                 * So adding penalty to the first node in same
                 * distance group to make it round-robin.
                 */
-               if (node_distance(local_node, node) !=
-                               node_distance(local_node, prev_node))
+
+               if (distance != node_distance(local_node, prev_node))
                        node_load[node] += load;
                prev_node = node;
                load--;
-               for (i = 0; i < MAX_NR_ZONES; i++) {
+               for (i = 0; i < GFP_ZONETYPES; i++) {
                        zonelist = pgdat->node_zonelists + i;
                        for (j = 0; zonelist->zones[j] != NULL; j++);
 
-                       k = ZONE_NORMAL;
-                       if (i & __GFP_HIGHMEM)
-                               k = ZONE_HIGHMEM;
-                       if (i & __GFP_DMA)
-                               k = ZONE_DMA;
+                       k = highest_zone(i);
 
                        j = build_zonelists_node(NODE_DATA(node), zonelist, j, k);
                        zonelist->zones[j] = NULL;
@@ -1313,19 +1676,13 @@ static void __init build_zonelists(pg_data_t *pgdat)
        int i, j, k, node, local_node;
 
        local_node = pgdat->node_id;
-       for (i = 0; i < MAX_NR_ZONES; i++) {
+       for (i = 0; i < GFP_ZONETYPES; i++) {
                struct zonelist *zonelist;
 
                zonelist = pgdat->node_zonelists + i;
-               memset(zonelist, 0, sizeof(*zonelist));
 
                j = 0;
-               k = ZONE_NORMAL;
-               if (i & __GFP_HIGHMEM)
-                       k = ZONE_HIGHMEM;
-               if (i & __GFP_DMA)
-                       k = ZONE_DMA;
-
+               k = highest_zone(i);
                j = build_zonelists_node(pgdat, zonelist, j, k);
                /*
                 * Now we build the zonelist so that it contains the zones
@@ -1335,117 +1692,381 @@ static void __init build_zonelists(pg_data_t *pgdat)
                 * zones coming right after the local ones are those from
                 * node N+1 (modulo N)
                 */
-               for (node = local_node + 1; node < numnodes; node++)
-                       j = build_zonelists_node(NODE_DATA(node), zonelist, j, k);
-               for (node = 0; node < local_node; node++)
-                       j = build_zonelists_node(NODE_DATA(node), zonelist, j, k);
+               for (node = local_node + 1; node < MAX_NUMNODES; node++) {
+                       if (!node_online(node))
+                               continue;
+                       j = build_zonelists_node(NODE_DATA(node), zonelist, j, k);
+               }
+               for (node = 0; node < local_node; node++) {
+                       if (!node_online(node))
+                               continue;
+                       j = build_zonelists_node(NODE_DATA(node), zonelist, j, k);
+               }
+
                zonelist->zones[j] = NULL;
        }
 }
 
-#endif /* CONFIG_NUMA */
-
-void __init build_all_zonelists(void)
+#endif /* CONFIG_NUMA */
+
+void __init build_all_zonelists(void)
+{
+       int i;
+
+       for_each_online_node(i)
+               build_zonelists(NODE_DATA(i));
+       printk("Built %i zonelists\n", num_online_nodes());
+       cpuset_init_current_mems_allowed();
+}
+
+/*
+ * Helper functions to size the waitqueue hash table.
+ * Essentially these want to choose hash table sizes sufficiently
+ * large so that collisions trying to wait on pages are rare.
+ * But in fact, the number of active page waitqueues on typical
+ * systems is ridiculously low, less than 200. So this is even
+ * conservative, even though it seems large.
+ *
+ * The constant PAGES_PER_WAITQUEUE specifies the ratio of pages to
+ * waitqueues, i.e. the size of the waitq table given the number of pages.
+ */
+#define PAGES_PER_WAITQUEUE    256
+
+static inline unsigned long wait_table_size(unsigned long pages)
+{
+       unsigned long size = 1;
+
+       pages /= PAGES_PER_WAITQUEUE;
+
+       while (size < pages)
+               size <<= 1;
+
+       /*
+        * Once we have dozens or even hundreds of threads sleeping
+        * on IO we've got bigger problems than wait queue collision.
+        * Limit the size of the wait table to a reasonable size.
+        */
+       size = min(size, 4096UL);
+
+       return max(size, 4UL);
+}
+
+/*
+ * This is an integer logarithm so that shifts can be used later
+ * to extract the more random high bits from the multiplicative
+ * hash function before the remainder is taken.
+ */
+static inline unsigned long wait_table_bits(unsigned long size)
+{
+       return ffz(~size);
+}
+
+#define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1))
+
+static void __init calculate_zone_totalpages(struct pglist_data *pgdat,
+               unsigned long *zones_size, unsigned long *zholes_size)
+{
+       unsigned long realtotalpages, totalpages = 0;
+       int i;
+
+       for (i = 0; i < MAX_NR_ZONES; i++)
+               totalpages += zones_size[i];
+       pgdat->node_spanned_pages = totalpages;
+
+       realtotalpages = totalpages;
+       if (zholes_size)
+               for (i = 0; i < MAX_NR_ZONES; i++)
+                       realtotalpages -= zholes_size[i];
+       pgdat->node_present_pages = realtotalpages;
+       printk(KERN_DEBUG "On node %d totalpages: %lu\n", pgdat->node_id, realtotalpages);
+}
+
+
+/*
+ * Initially all pages are reserved - free ones are freed
+ * up by free_all_bootmem() once the early boot process is
+ * done. Non-atomic initialization, single-pass.
+ */
+void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone,
+               unsigned long start_pfn)
+{
+       struct page *page;
+       unsigned long end_pfn = start_pfn + size;
+       unsigned long pfn;
+
+       for (pfn = start_pfn; pfn < end_pfn; pfn++) {
+               if (!early_pfn_valid(pfn))
+                       continue;
+               page = pfn_to_page(pfn);
+               set_page_links(page, zone, nid, pfn);
+               init_page_count(page);
+               reset_page_mapcount(page);
+               SetPageReserved(page);
+               INIT_LIST_HEAD(&page->lru);
+#ifdef WANT_PAGE_VIRTUAL
+               /* The shift won't overflow because ZONE_NORMAL is below 4G. */
+               if (!is_highmem_idx(zone))
+                       set_page_address(page, __va(pfn << PAGE_SHIFT));
+#endif
+       }
+}
+
+void zone_init_free_lists(struct pglist_data *pgdat, struct zone *zone,
+                               unsigned long size)
+{
+       int order;
+       for (order = 0; order < MAX_ORDER ; order++) {
+               INIT_LIST_HEAD(&zone->free_area[order].free_list);
+               zone->free_area[order].nr_free = 0;
+       }
+}
+
+#define ZONETABLE_INDEX(x, zone_nr)    ((x << ZONES_SHIFT) | zone_nr)
+void zonetable_add(struct zone *zone, int nid, int zid, unsigned long pfn,
+               unsigned long size)
+{
+       unsigned long snum = pfn_to_section_nr(pfn);
+       unsigned long end = pfn_to_section_nr(pfn + size);
+
+       if (FLAGS_HAS_NODE)
+               zone_table[ZONETABLE_INDEX(nid, zid)] = zone;
+       else
+               for (; snum <= end; snum++)
+                       zone_table[ZONETABLE_INDEX(snum, zid)] = zone;
+}
+
+#ifndef __HAVE_ARCH_MEMMAP_INIT
+#define memmap_init(size, nid, zone, start_pfn) \
+       memmap_init_zone((size), (nid), (zone), (start_pfn))
+#endif
+
+static int __cpuinit zone_batchsize(struct zone *zone)
+{
+       int batch;
+
+       /*
+        * The per-cpu-pages pools are set to around 1000th of the
+        * size of the zone.  But no more than 1/2 of a meg.
+        *
+        * OK, so we don't know how big the cache is.  So guess.
+        */
+       batch = zone->present_pages / 1024;
+       if (batch * PAGE_SIZE > 512 * 1024)
+               batch = (512 * 1024) / PAGE_SIZE;
+       batch /= 4;             /* We effectively *= 4 below */
+       if (batch < 1)
+               batch = 1;
+
+       /*
+        * Clamp the batch to a 2^n - 1 value. Having a power
+        * of 2 value was found to be more likely to have
+        * suboptimal cache aliasing properties in some cases.
+        *
+        * For example if 2 tasks are alternately allocating
+        * batches of pages, one task can end up with a lot
+        * of pages of one half of the possible page colors
+        * and the other with pages of the other colors.
+        */
+       batch = (1 << (fls(batch + batch/2)-1)) - 1;
+
+       return batch;
+}
+
+inline void setup_pageset(struct per_cpu_pageset *p, unsigned long batch)
+{
+       struct per_cpu_pages *pcp;
+
+       memset(p, 0, sizeof(*p));
+
+       pcp = &p->pcp[0];               /* hot */
+       pcp->count = 0;
+       pcp->high = 6 * batch;
+       pcp->batch = max(1UL, 1 * batch);
+       INIT_LIST_HEAD(&pcp->list);
+
+       pcp = &p->pcp[1];               /* cold*/
+       pcp->count = 0;
+       pcp->high = 2 * batch;
+       pcp->batch = max(1UL, batch/2);
+       INIT_LIST_HEAD(&pcp->list);
+}
+
+/*
+ * setup_pagelist_highmark() sets the high water mark for hot per_cpu_pagelist
+ * to the value high for the pageset p.
+ */
+
+static void setup_pagelist_highmark(struct per_cpu_pageset *p,
+                               unsigned long high)
+{
+       struct per_cpu_pages *pcp;
+
+       pcp = &p->pcp[0]; /* hot list */
+       pcp->high = high;
+       pcp->batch = max(1UL, high/4);
+       if ((high/4) > (PAGE_SHIFT * 8))
+               pcp->batch = PAGE_SHIFT * 8;
+}
+
+
+#ifdef CONFIG_NUMA
+/*
+ * Boot pageset table. One per cpu which is going to be used for all
+ * zones and all nodes. The parameters will be set in such a way
+ * that an item put on a list will immediately be handed over to
+ * the buddy list. This is safe since pageset manipulation is done
+ * with interrupts disabled.
+ *
+ * Some NUMA counter updates may also be caught by the boot pagesets.
+ *
+ * The boot_pagesets must be kept even after bootup is complete for
+ * unused processors and/or zones. They do play a role for bootstrapping
+ * hotplugged processors.
+ *
+ * zoneinfo_show() and maybe other functions do
+ * not check if the processor is online before following the pageset pointer.
+ * Other parts of the kernel may not check if the zone is available.
+ */
+static struct per_cpu_pageset boot_pageset[NR_CPUS];
+
+/*
+ * Dynamically allocate memory for the
+ * per cpu pageset array in struct zone.
+ */
+static int __cpuinit process_zones(int cpu)
+{
+       struct zone *zone, *dzone;
+
+       for_each_zone(zone) {
+
+               zone_pcp(zone, cpu) = kmalloc_node(sizeof(struct per_cpu_pageset),
+                                        GFP_KERNEL, cpu_to_node(cpu));
+               if (!zone_pcp(zone, cpu))
+                       goto bad;
+
+               setup_pageset(zone_pcp(zone, cpu), zone_batchsize(zone));
+
+               if (percpu_pagelist_fraction)
+                       setup_pagelist_highmark(zone_pcp(zone, cpu),
+                               (zone->present_pages / percpu_pagelist_fraction));
+       }
+
+       return 0;
+bad:
+       for_each_zone(dzone) {
+               if (dzone == zone)
+                       break;
+               kfree(zone_pcp(dzone, cpu));
+               zone_pcp(dzone, cpu) = NULL;
+       }
+       return -ENOMEM;
+}
+
+static inline void free_zone_pagesets(int cpu)
 {
-       int i;
+       struct zone *zone;
 
-       for(i = 0 ; i < numnodes ; i++)
-               build_zonelists(NODE_DATA(i));
-       printk("Built %i zonelists\n", numnodes);
-}
+       for_each_zone(zone) {
+               struct per_cpu_pageset *pset = zone_pcp(zone, cpu);
 
-/*
- * Helper functions to size the waitqueue hash table.
- * Essentially these want to choose hash table sizes sufficiently
- * large so that collisions trying to wait on pages are rare.
- * But in fact, the number of active page waitqueues on typical
- * systems is ridiculously low, less than 200. So this is even
- * conservative, even though it seems large.
- *
- * The constant PAGES_PER_WAITQUEUE specifies the ratio of pages to
- * waitqueues, i.e. the size of the waitq table given the number of pages.
- */
-#define PAGES_PER_WAITQUEUE    256
+               zone_pcp(zone, cpu) = NULL;
+               kfree(pset);
+       }
+}
 
-static inline unsigned long wait_table_size(unsigned long pages)
+static int pageset_cpuup_callback(struct notifier_block *nfb,
+               unsigned long action,
+               void *hcpu)
 {
-       unsigned long size = 1;
-
-       pages /= PAGES_PER_WAITQUEUE;
-
-       while (size < pages)
-               size <<= 1;
-
-       /*
-        * Once we have dozens or even hundreds of threads sleeping
-        * on IO we've got bigger problems than wait queue collision.
-        * Limit the size of the wait table to a reasonable size.
-        */
-       size = min(size, 4096UL);
+       int cpu = (long)hcpu;
+       int ret = NOTIFY_OK;
 
-       return max(size, 4UL);
+       switch (action) {
+               case CPU_UP_PREPARE:
+                       if (process_zones(cpu))
+                               ret = NOTIFY_BAD;
+                       break;
+               case CPU_UP_CANCELED:
+               case CPU_DEAD:
+                       free_zone_pagesets(cpu);
+                       break;
+               default:
+                       break;
+       }
+       return ret;
 }
 
-/*
- * This is an integer logarithm so that shifts can be used later
- * to extract the more random high bits from the multiplicative
- * hash function before the remainder is taken.
- */
-static inline unsigned long wait_table_bits(unsigned long size)
+static struct notifier_block pageset_notifier =
+       { &pageset_cpuup_callback, NULL, 0 };
+
+void __init setup_per_cpu_pageset(void)
 {
-       return ffz(~size);
+       int err;
+
+       /* Initialize per_cpu_pageset for cpu 0.
+        * A cpuup callback will do this for every cpu
+        * as it comes online
+        */
+       err = process_zones(smp_processor_id());
+       BUG_ON(err);
+       register_cpu_notifier(&pageset_notifier);
 }
 
-#define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1))
+#endif
 
-static void __init calculate_zone_totalpages(struct pglist_data *pgdat,
-               unsigned long *zones_size, unsigned long *zholes_size)
+static __meminit
+void zone_wait_table_init(struct zone *zone, unsigned long zone_size_pages)
 {
-       unsigned long realtotalpages, totalpages = 0;
        int i;
+       struct pglist_data *pgdat = zone->zone_pgdat;
 
-       for (i = 0; i < MAX_NR_ZONES; i++)
-               totalpages += zones_size[i];
-       pgdat->node_spanned_pages = totalpages;
+       /*
+        * The per-page waitqueue mechanism uses hashed waitqueues
+        * per zone.
+        */
+       zone->wait_table_size = wait_table_size(zone_size_pages);
+       zone->wait_table_bits = wait_table_bits(zone->wait_table_size);
+       zone->wait_table = (wait_queue_head_t *)
+               alloc_bootmem_node(pgdat, zone->wait_table_size
+                                       * sizeof(wait_queue_head_t));
 
-       realtotalpages = totalpages;
-       if (zholes_size)
-               for (i = 0; i < MAX_NR_ZONES; i++)
-                       realtotalpages -= zholes_size[i];
-       pgdat->node_present_pages = realtotalpages;
-       printk("On node %d totalpages: %lu\n", pgdat->node_id, realtotalpages);
+       for(i = 0; i < zone->wait_table_size; ++i)
+               init_waitqueue_head(zone->wait_table + i);
 }
 
-
-/*
- * Initially all pages are reserved - free ones are freed
- * up by free_all_bootmem() once the early boot process is
- * done. Non-atomic initialization, single-pass.
- */
-void __init memmap_init_zone(struct page *start, unsigned long size, int nid,
-               unsigned long zone, unsigned long start_pfn)
+static __meminit void zone_pcp_init(struct zone *zone)
 {
-       struct page *page;
+       int cpu;
+       unsigned long batch = zone_batchsize(zone);
 
-       for (page = start; page < (start + size); page++) {
-               set_page_zone(page, NODEZONE(nid, zone));
-               set_page_count(page, 0);
-               SetPageReserved(page);
-               INIT_LIST_HEAD(&page->lru);
-#ifdef WANT_PAGE_VIRTUAL
-               /* The shift won't overflow because ZONE_NORMAL is below 4G. */
-               if (zone != ZONE_HIGHMEM)
-                       set_page_address(page, __va(start_pfn << PAGE_SHIFT));
+       for (cpu = 0; cpu < NR_CPUS; cpu++) {
+#ifdef CONFIG_NUMA
+               /* Early boot. Slab allocator not functional yet */
+               zone_pcp(zone, cpu) = &boot_pageset[cpu];
+               setup_pageset(&boot_pageset[cpu],0);
+#else
+               setup_pageset(zone_pcp(zone,cpu), batch);
 #endif
-               start_pfn++;
        }
+       if (zone->present_pages)
+               printk(KERN_DEBUG "  %s zone: %lu pages, LIFO batch:%lu\n",
+                       zone->name, zone->present_pages, batch);
 }
 
-#ifndef __HAVE_ARCH_MEMMAP_INIT
-#define memmap_init(start, size, nid, zone, start_pfn) \
-       memmap_init_zone((start), (size), (nid), (zone), (start_pfn))
-#endif
+static __meminit void init_currently_empty_zone(struct zone *zone,
+               unsigned long zone_start_pfn, unsigned long size)
+{
+       struct pglist_data *pgdat = zone->zone_pgdat;
+
+       zone_wait_table_init(zone, size);
+       pgdat->nr_zones = zone_idx(zone) + 1;
+
+       zone->zone_start_pfn = zone_start_pfn;
+
+       memmap_init(size, pgdat->node_id, zone_idx(zone), zone_start_pfn);
+
+       zone_init_free_lists(pgdat, zone, zone->spanned_pages);
+}
 
 /*
  * Set up the zone data structures:
@@ -1456,175 +2077,116 @@ void __init memmap_init_zone(struct page *start, unsigned long size, int nid,
 static void __init free_area_init_core(struct pglist_data *pgdat,
                unsigned long *zones_size, unsigned long *zholes_size)
 {
-       unsigned long i, j;
-       const unsigned long zone_required_alignment = 1UL << (MAX_ORDER-1);
-       int cpu, nid = pgdat->node_id;
-       struct page *lmem_map = pgdat->node_mem_map;
+       unsigned long j;
+       int nid = pgdat->node_id;
        unsigned long zone_start_pfn = pgdat->node_start_pfn;
 
+       pgdat_resize_init(pgdat);
        pgdat->nr_zones = 0;
        init_waitqueue_head(&pgdat->kswapd_wait);
+       pgdat->kswapd_max_order = 0;
        
        for (j = 0; j < MAX_NR_ZONES; j++) {
                struct zone *zone = pgdat->node_zones + j;
                unsigned long size, realsize;
-               unsigned long batch;
 
-               zone_table[NODEZONE(nid, j)] = zone;
                realsize = size = zones_size[j];
                if (zholes_size)
                        realsize -= zholes_size[j];
 
+               if (j < ZONE_HIGHMEM)
+                       nr_kernel_pages += realsize;
+               nr_all_pages += realsize;
+
                zone->spanned_pages = size;
                zone->present_pages = realsize;
                zone->name = zone_names[j];
                spin_lock_init(&zone->lock);
                spin_lock_init(&zone->lru_lock);
+               zone_seqlock_init(zone);
                zone->zone_pgdat = pgdat;
                zone->free_pages = 0;
 
                zone->temp_priority = zone->prev_priority = DEF_PRIORITY;
 
-               /*
-                * The per-cpu-pages pools are set to around 1000th of the
-                * size of the zone.  But no more than 1/4 of a meg - there's
-                * no point in going beyond the size of L2 cache.
-                *
-                * OK, so we don't know how big the cache is.  So guess.
-                */
-               batch = zone->present_pages / 1024;
-               if (batch * PAGE_SIZE > 256 * 1024)
-                       batch = (256 * 1024) / PAGE_SIZE;
-               batch /= 4;             /* We effectively *= 4 below */
-               if (batch < 1)
-                       batch = 1;
-
-               for (cpu = 0; cpu < NR_CPUS; cpu++) {
-                       struct per_cpu_pages *pcp;
-
-                       pcp = &zone->pageset[cpu].pcp[0];       /* hot */
-                       pcp->count = 0;
-                       pcp->low = 2 * batch;
-                       pcp->high = 6 * batch;
-                       pcp->batch = 1 * batch;
-                       INIT_LIST_HEAD(&pcp->list);
-
-                       pcp = &zone->pageset[cpu].pcp[1];       /* cold */
-                       pcp->count = 0;
-                       pcp->low = 0;
-                       pcp->high = 2 * batch;
-                       pcp->batch = 1 * batch;
-                       INIT_LIST_HEAD(&pcp->list);
-               }
-               printk("  %s zone: %lu pages, LIFO batch:%lu\n",
-                               zone_names[j], realsize, batch);
+               zone_pcp_init(zone);
                INIT_LIST_HEAD(&zone->active_list);
                INIT_LIST_HEAD(&zone->inactive_list);
-               atomic_set(&zone->nr_scan_active, 0);
-               atomic_set(&zone->nr_scan_inactive, 0);
+               zone->nr_scan_active = 0;
+               zone->nr_scan_inactive = 0;
                zone->nr_active = 0;
                zone->nr_inactive = 0;
+               atomic_set(&zone->reclaim_in_progress, 0);
                if (!size)
                        continue;
 
-               /*
-                * The per-page waitqueue mechanism uses hashed waitqueues
-                * per zone.
-                */
-               zone->wait_table_size = wait_table_size(size);
-               zone->wait_table_bits =
-                       wait_table_bits(zone->wait_table_size);
-               zone->wait_table = (wait_queue_head_t *)
-                       alloc_bootmem_node(pgdat, zone->wait_table_size
-                                               * sizeof(wait_queue_head_t));
-
-               for(i = 0; i < zone->wait_table_size; ++i)
-                       init_waitqueue_head(zone->wait_table + i);
-
-               pgdat->nr_zones = j+1;
-
-               zone->zone_mem_map = lmem_map;
-               zone->zone_start_pfn = zone_start_pfn;
-
-               if ((zone_start_pfn) & (zone_required_alignment-1))
-                       printk("BUG: wrong zone alignment, it will crash\n");
-
-               memmap_init(lmem_map, size, nid, j, zone_start_pfn);
-
+               zonetable_add(zone, nid, j, zone_start_pfn, size);
+               init_currently_empty_zone(zone, zone_start_pfn, size);
                zone_start_pfn += size;
-               lmem_map += size;
+       }
+}
 
-               for (i = 0; ; i++) {
-                       unsigned long bitmap_size;
+static void __init alloc_node_mem_map(struct pglist_data *pgdat)
+{
+       /* Skip empty nodes */
+       if (!pgdat->node_spanned_pages)
+               return;
 
-                       INIT_LIST_HEAD(&zone->free_area[i].free_list);
-                       if (i == MAX_ORDER-1) {
-                               zone->free_area[i].map = NULL;
-                               break;
-                       }
+#ifdef CONFIG_FLAT_NODE_MEM_MAP
+       /* ia64 gets its own node_mem_map, before this, without bootmem */
+       if (!pgdat->node_mem_map) {
+               unsigned long size, start, end;
+               struct page *map;
 
-                       /*
-                        * Page buddy system uses "index >> (i+1)",
-                        * where "index" is at most "size-1".
-                        *
-                        * The extra "+3" is to round down to byte
-                        * size (8 bits per byte assumption). Thus
-                        * we get "(size-1) >> (i+4)" as the last byte
-                        * we can access.
-                        *
-                        * The "+1" is because we want to round the
-                        * byte allocation up rather than down. So
-                        * we should have had a "+7" before we shifted
-                        * down by three. Also, we have to add one as
-                        * we actually _use_ the last bit (it's [0,n]
-                        * inclusive, not [0,n[).
-                        *
-                        * So we actually had +7+1 before we shift
-                        * down by 3. But (n+8) >> 3 == (n >> 3) + 1
-                        * (modulo overflows, which we do not have).
-                        *
-                        * Finally, we LONG_ALIGN because all bitmap
-                        * operations are on longs.
-                        */
-                       bitmap_size = (size-1) >> (i+4);
-                       bitmap_size = LONG_ALIGN(bitmap_size+1);
-                       zone->free_area[i].map = 
-                         (unsigned long *) alloc_bootmem_node(pgdat, bitmap_size);
-               }
+               /*
+                * The zone's endpoints aren't required to be MAX_ORDER
+                * aligned but the node_mem_map endpoints must be in order
+                * for the buddy allocator to function correctly.
+                */
+               start = pgdat->node_start_pfn & ~(MAX_ORDER_NR_PAGES - 1);
+               end = pgdat->node_start_pfn + pgdat->node_spanned_pages;
+               end = ALIGN(end, MAX_ORDER_NR_PAGES);
+               size =  (end - start) * sizeof(struct page);
+               map = alloc_remap(pgdat->node_id, size);
+               if (!map)
+                       map = alloc_bootmem_node(pgdat, size);
+               pgdat->node_mem_map = map + (pgdat->node_start_pfn - start);
        }
+#ifdef CONFIG_FLATMEM
+       /*
+        * With no DISCONTIG, the global mem_map is just set as node 0's
+        */
+       if (pgdat == NODE_DATA(0))
+               mem_map = NODE_DATA(0)->node_mem_map;
+#endif
+#endif /* CONFIG_FLAT_NODE_MEM_MAP */
 }
 
 void __init free_area_init_node(int nid, struct pglist_data *pgdat,
-               struct page *node_mem_map, unsigned long *zones_size,
-               unsigned long node_start_pfn, unsigned long *zholes_size)
+               unsigned long *zones_size, unsigned long node_start_pfn,
+               unsigned long *zholes_size)
 {
-       unsigned long size;
-
        pgdat->node_id = nid;
        pgdat->node_start_pfn = node_start_pfn;
        calculate_zone_totalpages(pgdat, zones_size, zholes_size);
-       if (!node_mem_map) {
-               size = (pgdat->node_spanned_pages + 1) * sizeof(struct page);
-               node_mem_map = alloc_bootmem_node(pgdat, size);
-       }
-       pgdat->node_mem_map = node_mem_map;
+
+       alloc_node_mem_map(pgdat);
 
        free_area_init_core(pgdat, zones_size, zholes_size);
 }
 
-#ifndef CONFIG_DISCONTIGMEM
+#ifndef CONFIG_NEED_MULTIPLE_NODES
 static bootmem_data_t contig_bootmem_data;
 struct pglist_data contig_page_data = { .bdata = &contig_bootmem_data };
 
 EXPORT_SYMBOL(contig_page_data);
+#endif
 
 void __init free_area_init(unsigned long *zones_size)
 {
-       free_area_init_node(0, &contig_page_data, NULL, zones_size,
+       free_area_init_node(0, NODE_DATA(0), zones_size,
                        __pa(PAGE_OFFSET) >> PAGE_SHIFT, NULL);
-       mem_map = contig_page_data.node_mem_map;
 }
-#endif
 
 #ifdef CONFIG_PROC_FS
 
@@ -1634,8 +2196,9 @@ static void *frag_start(struct seq_file *m, loff_t *pos)
 {
        pg_data_t *pgdat;
        loff_t node = *pos;
-
-       for (pgdat = pgdat_list; pgdat && node; pgdat = pgdat->pgdat_next)
+       for (pgdat = first_online_pgdat();
+            pgdat && node;
+            pgdat = next_online_pgdat(pgdat))
                --node;
 
        return pgdat;
@@ -1646,7 +2209,7 @@ static void *frag_next(struct seq_file *m, void *arg, loff_t *pos)
        pg_data_t *pgdat = (pg_data_t *)arg;
 
        (*pos)++;
-       return pgdat->pgdat_next;
+       return next_online_pgdat(pgdat);
 }
 
 static void frag_stop(struct seq_file *m, void *arg)
@@ -1654,8 +2217,7 @@ static void frag_stop(struct seq_file *m, void *arg)
 }
 
 /* 
- * This walks the freelist for each zone. Whilst this is slow, I'd rather 
- * be slow here than slow down the fast path by keeping stats - mjbligh
+ * This walks the free areas for each zone.
  */
 static int frag_show(struct seq_file *m, void *arg)
 {
@@ -1666,19 +2228,13 @@ static int frag_show(struct seq_file *m, void *arg)
        int order;
 
        for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; ++zone) {
-               if (!zone->present_pages)
+               if (!populated_zone(zone))
                        continue;
 
                spin_lock_irqsave(&zone->lock, flags);
                seq_printf(m, "Node %d, zone %8s ", pgdat->node_id, zone->name);
-               for (order = 0; order < MAX_ORDER; ++order) {
-                       unsigned long nr_bufs = 0;
-                       struct list_head *elem;
-
-                       list_for_each(elem, &(zone->free_area[order].free_list))
-                               ++nr_bufs;
-                       seq_printf(m, "%6lu ", nr_bufs);
-               }
+               for (order = 0; order < MAX_ORDER; ++order)
+                       seq_printf(m, "%6lu ", zone->free_area[order].nr_free);
                spin_unlock_irqrestore(&zone->lock, flags);
                seq_putc(m, '\n');
        }
@@ -1692,6 +2248,113 @@ struct seq_operations fragmentation_op = {
        .show   = frag_show,
 };
 
+/*
+ * Output information about zones in @pgdat.
+ */
+static int zoneinfo_show(struct seq_file *m, void *arg)
+{
+       pg_data_t *pgdat = arg;
+       struct zone *zone;
+       struct zone *node_zones = pgdat->node_zones;
+       unsigned long flags;
+
+       for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; zone++) {
+               int i;
+
+               if (!populated_zone(zone))
+                       continue;
+
+               spin_lock_irqsave(&zone->lock, flags);
+               seq_printf(m, "Node %d, zone %8s", pgdat->node_id, zone->name);
+               seq_printf(m,
+                          "\n  pages free     %lu"
+                          "\n        min      %lu"
+                          "\n        low      %lu"
+                          "\n        high     %lu"
+                          "\n        active   %lu"
+                          "\n        inactive %lu"
+                          "\n        scanned  %lu (a: %lu i: %lu)"
+                          "\n        spanned  %lu"
+                          "\n        present  %lu",
+                          zone->free_pages,
+                          zone->pages_min,
+                          zone->pages_low,
+                          zone->pages_high,
+                          zone->nr_active,
+                          zone->nr_inactive,
+                          zone->pages_scanned,
+                          zone->nr_scan_active, zone->nr_scan_inactive,
+                          zone->spanned_pages,
+                          zone->present_pages);
+               seq_printf(m,
+                          "\n        protection: (%lu",
+                          zone->lowmem_reserve[0]);
+               for (i = 1; i < ARRAY_SIZE(zone->lowmem_reserve); i++)
+                       seq_printf(m, ", %lu", zone->lowmem_reserve[i]);
+               seq_printf(m,
+                          ")"
+                          "\n  pagesets");
+               for_each_online_cpu(i) {
+                       struct per_cpu_pageset *pageset;
+                       int j;
+
+                       pageset = zone_pcp(zone, i);
+                       for (j = 0; j < ARRAY_SIZE(pageset->pcp); j++) {
+                               if (pageset->pcp[j].count)
+                                       break;
+                       }
+                       if (j == ARRAY_SIZE(pageset->pcp))
+                               continue;
+                       for (j = 0; j < ARRAY_SIZE(pageset->pcp); j++) {
+                               seq_printf(m,
+                                          "\n    cpu: %i pcp: %i"
+                                          "\n              count: %i"
+                                          "\n              high:  %i"
+                                          "\n              batch: %i",
+                                          i, j,
+                                          pageset->pcp[j].count,
+                                          pageset->pcp[j].high,
+                                          pageset->pcp[j].batch);
+                       }
+#ifdef CONFIG_NUMA
+                       seq_printf(m,
+                                  "\n            numa_hit:       %lu"
+                                  "\n            numa_miss:      %lu"
+                                  "\n            numa_foreign:   %lu"
+                                  "\n            interleave_hit: %lu"
+                                  "\n            local_node:     %lu"
+                                  "\n            other_node:     %lu",
+                                  pageset->numa_hit,
+                                  pageset->numa_miss,
+                                  pageset->numa_foreign,
+                                  pageset->interleave_hit,
+                                  pageset->local_node,
+                                  pageset->other_node);
+#endif
+               }
+               seq_printf(m,
+                          "\n  all_unreclaimable: %u"
+                          "\n  prev_priority:     %i"
+                          "\n  temp_priority:     %i"
+                          "\n  start_pfn:         %lu",
+                          zone->all_unreclaimable,
+                          zone->prev_priority,
+                          zone->temp_priority,
+                          zone->zone_start_pfn);
+               spin_unlock_irqrestore(&zone->lock, flags);
+               seq_putc(m, '\n');
+       }
+       return 0;
+}
+
+struct seq_operations zoneinfo_op = {
+       .start  = frag_start, /* iterate over all zones. The same as in
+                              * fragmentation. */
+       .next   = frag_next,
+       .stop   = frag_stop,
+       .show   = zoneinfo_show,
+};
+
 static char *vmstat_text[] = {
        "nr_dirty",
        "nr_writeback",
@@ -1704,32 +2367,40 @@ static char *vmstat_text[] = {
        "pgpgout",
        "pswpin",
        "pswpout",
-       "pgalloc_high",
 
+       "pgalloc_high",
        "pgalloc_normal",
+       "pgalloc_dma32",
        "pgalloc_dma",
+
        "pgfree",
        "pgactivate",
        "pgdeactivate",
 
        "pgfault",
        "pgmajfault",
+
        "pgrefill_high",
        "pgrefill_normal",
+       "pgrefill_dma32",
        "pgrefill_dma",
 
        "pgsteal_high",
        "pgsteal_normal",
+       "pgsteal_dma32",
        "pgsteal_dma",
+
        "pgscan_kswapd_high",
        "pgscan_kswapd_normal",
-
+       "pgscan_kswapd_dma32",
        "pgscan_kswapd_dma",
+
        "pgscan_direct_high",
        "pgscan_direct_normal",
+       "pgscan_direct_dma32",
        "pgscan_direct_dma",
-       "pginodesteal",
 
+       "pginodesteal",
        "slabs_scanned",
        "kswapd_steal",
        "kswapd_inodesteal",
@@ -1737,6 +2408,7 @@ static char *vmstat_text[] = {
        "allocstall",
 
        "pgrotated",
+       "nr_bounce",
 };
 
 static void *vmstat_start(struct seq_file *m, loff_t *pos)
@@ -1794,14 +2466,28 @@ static int page_alloc_cpu_notify(struct notifier_block *self,
 {
        int cpu = (unsigned long)hcpu;
        long *count;
+       unsigned long *src, *dest;
 
        if (action == CPU_DEAD) {
+               int i;
+
                /* Drain local pagecache count. */
                count = &per_cpu(nr_pagecache_local, cpu);
                atomic_add(*count, &nr_pagecache);
                *count = 0;
                local_irq_disable();
                __drain_pages(cpu);
+
+               /* Add dead cpu's page_states to our own. */
+               dest = (unsigned long *)&__get_cpu_var(page_states);
+               src = (unsigned long *)&per_cpu(page_states, cpu);
+
+               for (i = 0; i < sizeof(struct page_state)/sizeof(unsigned long);
+                               i++) {
+                       dest[i] += src[i];
+                       src[i] = 0;
+               }
+
                local_irq_enable();
        }
        return NOTIFY_OK;
@@ -1813,91 +2499,72 @@ void __init page_alloc_init(void)
        hotcpu_notifier(page_alloc_cpu_notify, 0);
 }
 
-static unsigned long higherzone_val(struct zone *z, int max_zone,
-                                       int alloc_type)
+/*
+ * calculate_totalreserve_pages - called when sysctl_lower_zone_reserve_ratio
+ *     or min_free_kbytes changes.
+ */
+static void calculate_totalreserve_pages(void)
 {
-       int z_idx = zone_idx(z);
-       struct zone *higherzone;
-       unsigned long pages;
-
-       /* there is no higher zone to get a contribution from */
-       if (z_idx == MAX_NR_ZONES-1)
-               return 0;
+       struct pglist_data *pgdat;
+       unsigned long reserve_pages = 0;
+       int i, j;
 
-       higherzone = &z->zone_pgdat->node_zones[z_idx+1];
+       for_each_online_pgdat(pgdat) {
+               for (i = 0; i < MAX_NR_ZONES; i++) {
+                       struct zone *zone = pgdat->node_zones + i;
+                       unsigned long max = 0;
 
-       /* We always start with the higher zone's protection value */
-       pages = higherzone->protection[alloc_type];
+                       /* Find valid and maximum lowmem_reserve in the zone */
+                       for (j = i; j < MAX_NR_ZONES; j++) {
+                               if (zone->lowmem_reserve[j] > max)
+                                       max = zone->lowmem_reserve[j];
+                       }
 
-       /*
-        * We get a lower-zone-protection contribution only if there are
-        * pages in the higher zone and if we're not the highest zone
-        * in the current zonelist.  e.g., never happens for GFP_DMA. Happens
-        * only for ZONE_DMA in a GFP_KERNEL allocation and happens for ZONE_DMA
-        * and ZONE_NORMAL for a GFP_HIGHMEM allocation.
-        */
-       if (higherzone->present_pages && z_idx < alloc_type)
-               pages += higherzone->pages_low * sysctl_lower_zone_protection;
+                       /* we treat pages_high as reserved pages. */
+                       max += zone->pages_high;
 
-       return pages;
+                       if (max > zone->present_pages)
+                               max = zone->present_pages;
+                       reserve_pages += max;
+               }
+       }
+       totalreserve_pages = reserve_pages;
 }
 
 /*
- * setup_per_zone_protection - called whenver min_free_kbytes or
- *     sysctl_lower_zone_protection changes.  Ensures that each zone
- *     has a correct pages_protected value, so an adequate number of
+ * setup_per_zone_lowmem_reserve - called whenever
+ *     sysctl_lower_zone_reserve_ratio changes.  Ensures that each zone
+ *     has a correct pages reserved value, so an adequate number of
  *     pages are left in the zone after a successful __alloc_pages().
- *
- *     This algorithm is way confusing.  I tries to keep the same behavior
- *     as we had with the incremental min iterative algorithm.
  */
-static void setup_per_zone_protection(void)
+static void setup_per_zone_lowmem_reserve(void)
 {
        struct pglist_data *pgdat;
-       struct zone *zones, *zone;
-       int max_zone;
-       int i, j;
+       int j, idx;
 
-       for_each_pgdat(pgdat) {
-               zones = pgdat->node_zones;
+       for_each_online_pgdat(pgdat) {
+               for (j = 0; j < MAX_NR_ZONES; j++) {
+                       struct zone *zone = pgdat->node_zones + j;
+                       unsigned long present_pages = zone->present_pages;
 
-               for (i = 0, max_zone = 0; i < MAX_NR_ZONES; i++)
-                       if (zones[i].present_pages)
-                               max_zone = i;
+                       zone->lowmem_reserve[j] = 0;
 
-               /*
-                * For each of the different allocation types:
-                * GFP_DMA -> GFP_KERNEL -> GFP_HIGHMEM
-                */
-               for (i = 0; i < MAX_NR_ZONES; i++) {
-                       /*
-                        * For each of the zones:
-                        * ZONE_HIGHMEM -> ZONE_NORMAL -> ZONE_DMA
-                        */
-                       for (j = MAX_NR_ZONES-1; j >= 0; j--) {
-                               zone = &zones[j];
-
-                               /*
-                                * We never protect zones that don't have memory
-                                * in them (j>max_zone) or zones that aren't in
-                                * the zonelists for a certain type of
-                                * allocation (j>i).  We have to assign these to
-                                * zero because the lower zones take
-                                * contributions from the higher zones.
-                                */
-                               if (j > max_zone || j > i) {
-                                       zone->protection[i] = 0;
-                                       continue;
-                               }
-                               /*
-                                * The contribution of the next higher zone
-                                */
-                               zone->protection[i] = higherzone_val(zone,
-                                                               max_zone, i);
-                               zone->protection[i] += zone->pages_low;
+                       for (idx = j-1; idx >= 0; idx--) {
+                               struct zone *lower_zone;
+
+                               if (sysctl_lowmem_reserve_ratio[idx] < 1)
+                                       sysctl_lowmem_reserve_ratio[idx] = 1;
+
+                               lower_zone = pgdat->node_zones + idx;
+                               lower_zone->lowmem_reserve[j] = present_pages /
+                                       sysctl_lowmem_reserve_ratio[idx];
+                               present_pages += lower_zone->present_pages;
                        }
                }
        }
+
+       /* update totalreserve_pages */
+       calculate_totalreserve_pages();
 }
 
 /*
@@ -1905,7 +2572,7 @@ static void setup_per_zone_protection(void)
  *     that the pages_{min,low,high} values for each zone are set correctly 
  *     with respect to min_free_kbytes.
  */
-static void setup_per_zone_pages_min(void)
+void setup_per_zone_pages_min(void)
 {
        unsigned long pages_min = min_free_kbytes >> (PAGE_SHIFT - 10);
        unsigned long lowmem_pages = 0;
@@ -1919,13 +2586,20 @@ static void setup_per_zone_pages_min(void)
        }
 
        for_each_zone(zone) {
+               u64 tmp;
+
                spin_lock_irqsave(&zone->lru_lock, flags);
+               tmp = (u64)pages_min * zone->present_pages;
+               do_div(tmp, lowmem_pages);
                if (is_highmem(zone)) {
                        /*
-                        * Often, highmem doesn't need to reserve any pages.
-                        * But the pages_min/low/high values are also used for
-                        * batching up page reclaim activity so we need a
-                        * decent value here.
+                        * __GFP_HIGH and PF_MEMALLOC allocations usually don't
+                        * need highmem pages, so cap pages_min to a small
+                        * value here.
+                        *
+                        * The (pages_high-pages_low) and (pages_low-pages_min)
+                        * deltas controls asynch page reclaim, and so should
+                        * not be capped for highmem.
                         */
                        int min_pages;
 
@@ -1936,41 +2610,45 @@ static void setup_per_zone_pages_min(void)
                                min_pages = 128;
                        zone->pages_min = min_pages;
                } else {
-                       /* if it's a lowmem zone, reserve a number of pages 
+                       /*
+                        * If it's a lowmem zone, reserve a number of pages
                         * proportionate to the zone's size.
                         */
-                       zone->pages_min = (pages_min * zone->present_pages) / 
-                                          lowmem_pages;
+                       zone->pages_min = tmp;
                }
 
-               zone->pages_low = zone->pages_min * 2;
-               zone->pages_high = zone->pages_min * 3;
+               zone->pages_low   = zone->pages_min + (tmp >> 2);
+               zone->pages_high  = zone->pages_min + (tmp >> 1);
                spin_unlock_irqrestore(&zone->lru_lock, flags);
        }
+
+       /* update totalreserve_pages */
+       calculate_totalreserve_pages();
 }
 
 /*
  * Initialise min_free_kbytes.
  *
  * For small machines we want it small (128k min).  For large machines
- * we want it large (16MB max).  But it is not linear, because network
+ * we want it large (64MB max).  But it is not linear, because network
  * bandwidth does not increase linearly with machine size.  We use
  *
- *     min_free_kbytes = sqrt(lowmem_kbytes)
+ *     min_free_kbytes = 4 * sqrt(lowmem_kbytes), for better accuracy:
+ *     min_free_kbytes = sqrt(lowmem_kbytes * 16)
  *
  * which yields
  *
- * 16MB:       128k
- * 32MB:       181k
- * 64MB:       256k
- * 128MB:      362k
- * 256MB:      512k
- * 512MB:      724k
- * 1024MB:     1024k
- * 2048MB:     1448k
- * 4096MB:     2048k
- * 8192MB:     2896k
- * 16384MB:    4096k
+ * 16MB:       512k
+ * 32MB:       724k
+ * 64MB:       1024k
+ * 128MB:      1448k
+ * 256MB:      2048k
+ * 512MB:      2896k
+ * 1024MB:     4096k
+ * 2048MB:     5792k
+ * 4096MB:     8192k
+ * 8192MB:     11584k
+ * 16384MB:    16384k
  */
 static int __init init_per_zone_pages_min(void)
 {
@@ -1978,13 +2656,13 @@ static int __init init_per_zone_pages_min(void)
 
        lowmem_kbytes = nr_free_buffer_pages() * (PAGE_SIZE >> 10);
 
-       min_free_kbytes = int_sqrt(lowmem_kbytes);
+       min_free_kbytes = int_sqrt(lowmem_kbytes * 16);
        if (min_free_kbytes < 128)
                min_free_kbytes = 128;
-       if (min_free_kbytes > 16384)
-               min_free_kbytes = 16384;
+       if (min_free_kbytes > 65536)
+               min_free_kbytes = 65536;
        setup_per_zone_pages_min();
-       setup_per_zone_protection();
+       setup_per_zone_lowmem_reserve();
        return 0;
 }
 module_init(init_per_zone_pages_min)
@@ -1995,23 +2673,183 @@ module_init(init_per_zone_pages_min)
  *     changes.
  */
 int min_free_kbytes_sysctl_handler(ctl_table *table, int write, 
-               struct file *file, void __user *buffer, size_t *length)
+       struct file *file, void __user *buffer, size_t *length, loff_t *ppos)
 {
-       proc_dointvec(table, write, file, buffer, length);
+       proc_dointvec(table, write, file, buffer, length, ppos);
        setup_per_zone_pages_min();
-       setup_per_zone_protection();
        return 0;
 }
 
 /*
- * lower_zone_protection_sysctl_handler - just a wrapper around
- *     proc_dointvec() so that we can call setup_per_zone_protection()
- *     whenever sysctl_lower_zone_protection changes.
+ * lowmem_reserve_ratio_sysctl_handler - just a wrapper around
+ *     proc_dointvec() so that we can call setup_per_zone_lowmem_reserve()
+ *     whenever sysctl_lowmem_reserve_ratio changes.
+ *
+ * The reserve ratio obviously has absolutely no relation with the
+ * pages_min watermarks. The lowmem reserve ratio can only make sense
+ * if in function of the boot time zone sizes.
+ */
+int lowmem_reserve_ratio_sysctl_handler(ctl_table *table, int write,
+       struct file *file, void __user *buffer, size_t *length, loff_t *ppos)
+{
+       proc_dointvec_minmax(table, write, file, buffer, length, ppos);
+       setup_per_zone_lowmem_reserve();
+       return 0;
+}
+
+/*
+ * percpu_pagelist_fraction - changes the pcp->high for each zone on each
+ * cpu.  It is the fraction of total pages in each zone that a hot per cpu pagelist
+ * can have before it gets flushed back to buddy allocator.
  */
-int lower_zone_protection_sysctl_handler(ctl_table *table, int write,
-                struct file *file, void __user *buffer, size_t *length)
+
+int percpu_pagelist_fraction_sysctl_handler(ctl_table *table, int write,
+       struct file *file, void __user *buffer, size_t *length, loff_t *ppos)
 {
-       proc_dointvec_minmax(table, write, file, buffer, length);
-       setup_per_zone_protection();
+       struct zone *zone;
+       unsigned int cpu;
+       int ret;
+
+       ret = proc_dointvec_minmax(table, write, file, buffer, length, ppos);
+       if (!write || (ret == -EINVAL))
+               return ret;
+       for_each_zone(zone) {
+               for_each_online_cpu(cpu) {
+                       unsigned long  high;
+                       high = zone->present_pages / percpu_pagelist_fraction;
+                       setup_pagelist_highmark(zone_pcp(zone, cpu), high);
+               }
+       }
        return 0;
 }
+
+__initdata int hashdist = HASHDIST_DEFAULT;
+
+#ifdef CONFIG_NUMA
+static int __init set_hashdist(char *str)
+{
+       if (!str)
+               return 0;
+       hashdist = simple_strtoul(str, &str, 0);
+       return 1;
+}
+__setup("hashdist=", set_hashdist);
+#endif
+
+/*
+ * allocate a large system hash table from bootmem
+ * - it is assumed that the hash table must contain an exact power-of-2
+ *   quantity of entries
+ * - limit is the number of hash buckets, not the total allocation size
+ */
+void *__init alloc_large_system_hash(const char *tablename,
+                                    unsigned long bucketsize,
+                                    unsigned long numentries,
+                                    int scale,
+                                    int flags,
+                                    unsigned int *_hash_shift,
+                                    unsigned int *_hash_mask,
+                                    unsigned long limit)
+{
+       unsigned long long max = limit;
+       unsigned long log2qty, size;
+       void *table = NULL;
+
+       /* allow the kernel cmdline to have a say */
+       if (!numentries) {
+               /* round applicable memory size up to nearest megabyte */
+               numentries = (flags & HASH_HIGHMEM) ? nr_all_pages : nr_kernel_pages;
+               numentries += (1UL << (20 - PAGE_SHIFT)) - 1;
+               numentries >>= 20 - PAGE_SHIFT;
+               numentries <<= 20 - PAGE_SHIFT;
+
+               /* limit to 1 bucket per 2^scale bytes of low memory */
+               if (scale > PAGE_SHIFT)
+                       numentries >>= (scale - PAGE_SHIFT);
+               else
+                       numentries <<= (PAGE_SHIFT - scale);
+       }
+       numentries = roundup_pow_of_two(numentries);
+
+       /* limit allocation size to 1/16 total memory by default */
+       if (max == 0) {
+               max = ((unsigned long long)nr_all_pages << PAGE_SHIFT) >> 4;
+               do_div(max, bucketsize);
+       }
+
+       if (numentries > max)
+               numentries = max;
+
+       log2qty = long_log2(numentries);
+
+       do {
+               size = bucketsize << log2qty;
+               if (flags & HASH_EARLY)
+                       table = alloc_bootmem(size);
+               else if (hashdist)
+                       table = __vmalloc(size, GFP_ATOMIC, PAGE_KERNEL);
+               else {
+                       unsigned long order;
+                       for (order = 0; ((1UL << order) << PAGE_SHIFT) < size; order++)
+                               ;
+                       table = (void*) __get_free_pages(GFP_ATOMIC, order);
+               }
+       } while (!table && size > PAGE_SIZE && --log2qty);
+
+       if (!table)
+               panic("Failed to allocate %s hash table\n", tablename);
+
+       printk("%s hash table entries: %d (order: %d, %lu bytes)\n",
+              tablename,
+              (1U << log2qty),
+              long_log2(size) - PAGE_SHIFT,
+              size);
+
+       if (_hash_shift)
+               *_hash_shift = log2qty;
+       if (_hash_mask)
+               *_hash_mask = (1 << log2qty) - 1;
+
+       return table;
+}
+
+#ifdef CONFIG_OUT_OF_LINE_PFN_TO_PAGE
+/*
+ * pfn <-> page translation. out-of-line version.
+ * (see asm-generic/memory_model.h)
+ */
+#if defined(CONFIG_FLATMEM)
+struct page *pfn_to_page(unsigned long pfn)
+{
+       return mem_map + (pfn - ARCH_PFN_OFFSET);
+}
+unsigned long page_to_pfn(struct page *page)
+{
+       return (page - mem_map) + ARCH_PFN_OFFSET;
+}
+#elif defined(CONFIG_DISCONTIGMEM)
+struct page *pfn_to_page(unsigned long pfn)
+{
+       int nid = arch_pfn_to_nid(pfn);
+       return NODE_DATA(nid)->node_mem_map + arch_local_page_offset(pfn,nid);
+}
+unsigned long page_to_pfn(struct page *page)
+{
+       struct pglist_data *pgdat = NODE_DATA(page_to_nid(page));
+       return (page - pgdat->node_mem_map) + pgdat->node_start_pfn;
+}
+#elif defined(CONFIG_SPARSEMEM)
+struct page *pfn_to_page(unsigned long pfn)
+{
+       return __section_mem_map_addr(__pfn_to_section(pfn)) + pfn;
+}
+
+unsigned long page_to_pfn(struct page *page)
+{
+       long section_id = page_to_section(page);
+       return page - __section_mem_map_addr(__nr_to_section(section_id));
+}
+#endif /* CONFIG_FLATMEM/DISCONTIGMME/SPARSEMEM */
+EXPORT_SYMBOL(pfn_to_page);
+EXPORT_SYMBOL(page_to_pfn);
+#endif /* CONFIG_OUT_OF_LINE_PFN_TO_PAGE */