vserver 1.9.3
[linux-2.6.git] / mm / page_alloc.c
index 8d3f6f4..8bcef68 100644 (file)
@@ -31,6 +31,8 @@
 #include <linux/topology.h>
 #include <linux/sysctl.h>
 #include <linux/cpu.h>
+#include <linux/vs_base.h>
+#include <linux/vs_limit.h>
 
 #include <asm/tlbflush.h>
 
@@ -38,7 +40,7 @@ DECLARE_BITMAP(node_online_map, MAX_NUMNODES);
 struct pglist_data *pgdat_list;
 unsigned long totalram_pages;
 unsigned long totalhigh_pages;
-int nr_swap_pages;
+long nr_swap_pages;
 int numnodes = 1;
 int sysctl_lower_zone_protection = 0;
 
@@ -55,6 +57,9 @@ EXPORT_SYMBOL(zone_table);
 static char *zone_names[MAX_NR_ZONES] = { "DMA", "Normal", "HighMem" };
 int min_free_kbytes = 1024;
 
+unsigned long __initdata nr_kernel_pages;
+unsigned long __initdata nr_all_pages;
+
 /*
  * Temporary debugging check for pages not lying within a given zone.
  */
@@ -73,9 +78,9 @@ static void bad_page(const char *function, 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 mapped:%d count:%d\n",
-               (unsigned long)page->flags, page->mapping,
-               page_mapped(page), page_count(page));
+       printk(KERN_EMERG "flags:0x%0*lx mapping:%p mapcount:%d count:%d\n",
+               (int)(2*sizeof(page_flags_t)), (unsigned long)page->flags,
+               page->mapping, page_mapcount(page), page_count(page));
        printk(KERN_EMERG "Backtrace:\n");
        dump_stack();
        printk(KERN_EMERG "Trying to fix it up, but a reboot is needed\n");
@@ -84,11 +89,10 @@ static void bad_page(const char *function, struct page *page)
                        1 << PG_lru     |
                        1 << PG_active  |
                        1 << PG_dirty   |
-                       1 << PG_maplock |
-                       1 << PG_anon    |
                        1 << PG_swapcache |
                        1 << PG_writeback);
        set_page_count(page, 0);
+       reset_page_mapcount(page);
        page->mapping = NULL;
 }
 
@@ -118,7 +122,7 @@ static void prep_compound_page(struct page *page, unsigned long order)
        int i;
        int nr_pages = 1 << order;
 
-       page[1].mapping = 0;
+       page[1].mapping = NULL;
        page[1].index = order;
        for (i = 0; i < nr_pages; i++) {
                struct page *p = page + i;
@@ -175,20 +179,20 @@ static void destroy_compound_page(struct page *page, unsigned long order)
  */
 
 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)
+               struct zone *zone, struct free_area *area, unsigned int order)
 {
-       unsigned long page_idx, index;
+       unsigned long page_idx, index, mask;
 
        if (order)
                destroy_compound_page(page, order);
+       mask = (~0UL) << 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))) {
+       zone->free_pages += 1 << order;
+       while (order < MAX_ORDER-1) {
                struct page *buddy1, *buddy2;
 
                BUG_ON(area >= zone->free_area + MAX_ORDER);
@@ -197,17 +201,15 @@ static inline void __free_pages_bulk (struct page *page, struct page *base,
                         * 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);
+
+               /* Move the buddy up one level. */
+               buddy1 = base + (page_idx ^ (1 << order));
                buddy2 = base + page_idx;
                BUG_ON(bad_range(zone, buddy1));
                BUG_ON(bad_range(zone, buddy2));
                list_del(&buddy1->lru);
                mask <<= 1;
+               order++;
                area++;
                index >>= 1;
                page_idx &= mask;
@@ -227,8 +229,6 @@ 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);
@@ -251,12 +251,11 @@ static int
 free_pages_bulk(struct zone *zone, int count,
                struct list_head *list, unsigned int order)
 {
-       unsigned long mask, flags;
+       unsigned long 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);
@@ -266,7 +265,7 @@ free_pages_bulk(struct zone *zone, int count,
                page = list_entry(list->prev, struct page, lru);
                /* have to delete it as __free_pages_bulk list manipulates */
                list_del(&page->lru);
-               __free_pages_bulk(page, base, zone, area, mask, order);
+               __free_pages_bulk(page, base, zone, area, order);
                ret++;
        }
        spin_unlock_irqrestore(&zone->lock, flags);
@@ -278,6 +277,8 @@ void __free_pages_ok(struct page *page, unsigned int order)
        LIST_HEAD(list);
        int i;
 
+       arch_free_page(page, order);
+
        mod_page_state(pgfree, 1 << order);
        for (i = 0 ; i < (1 << order) ; ++i)
                free_pages_check(__FUNCTION__, page + i);
@@ -289,6 +290,20 @@ void __free_pages_ok(struct page *page, unsigned int order)
 #define MARK_USED(index, order, area) \
        __change_bit((index) >> (1+(order)), (area)->map)
 
+/*
+ * 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 struct page *
 expand(struct zone *zone, struct page *page,
         unsigned long index, int low, int high, struct free_area *area)
@@ -296,14 +311,12 @@ expand(struct zone *zone, struct page *page,
        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);
+               MARK_USED(index + size, high, area);
        }
        return page;
 }
@@ -337,8 +350,6 @@ static void prep_new_page(struct page *page, int order)
                        1 << PG_active  |
                        1 << PG_dirty   |
                        1 << PG_reclaim |
-                       1 << PG_maplock |
-                       1 << PG_anon    |
                        1 << PG_swapcache |
                        1 << PG_writeback )))
                bad_page(__FUNCTION__, page);
@@ -460,6 +471,32 @@ void drain_local_pages(void)
 }
 #endif /* CONFIG_PM */
 
+static void zone_statistics(struct zonelist *zonelist, struct zone *z)
+{
+#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];
+       if (pg == orig) {
+               z->pageset[cpu].numa_hit++;
+       } else {
+               p->numa_miss++;
+               zonelist->zones[0]->pageset[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
  */
@@ -470,8 +507,12 @@ static void fastcall free_hot_cold_page(struct page *page, int cold)
        struct per_cpu_pages *pcp;
        unsigned long flags;
 
+       arch_free_page(page, 0);
+
        kernel_map_pages(page, 1, 0);
        inc_page_state(pgfree);
+       if (PageAnon(page))
+               page->mapping = NULL;
        free_pages_check(__FUNCTION__, page);
        pcp = &zone->pageset[get_cpu()].pcp[cold];
        local_irq_save(flags);
@@ -561,74 +602,72 @@ __alloc_pages(unsigned int gfp_mask, unsigned int order,
 {
        const int wait = gfp_mask & __GFP_WAIT;
        unsigned long min;
-       struct zone **zones;
+       struct zone **zones, *z;
        struct page *page;
        struct reclaim_state reclaim_state;
        struct task_struct *p = current;
        int i;
        int alloc_type;
        int do_retry;
+       int can_try_harder;
 
        might_sleep_if(wait);
 
+       /*
+        * The caller may dip into page reserves a bit more if the caller
+        * cannot run direct reclaim, or is the caller has realtime scheduling
+        * policy
+        */
+       can_try_harder = (unlikely(rt_task(p)) && !in_interrupt()) || !wait;
+
        zones = zonelist->zones;  /* the list of zones suitable for gfp_mask */
-       if (zones[0] == NULL)     /* no zones in the zonelist */
+
+       if (unlikely(zones[0] == NULL)) {
+               /* Should this ever happen?? */
                return NULL;
+       }
 
        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];
+       for (i = 0; (z = zones[i]) != NULL; i++) {
+               min = z->pages_low + (1<<order) + z->protection[alloc_type];
 
-               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)
+                       continue;
 
-               if (z->free_pages >= min ||
-                               (!wait && z->free_pages >= z->pages_high)) {
-                       page = buffered_rmqueue(z, order, gfp_mask);
-                       if (page)
-                               goto got_pg;
-               }
+               page = buffered_rmqueue(z, order, gfp_mask);
+               if (page)
+                       goto got_pg;
        }
 
-       /* we're somewhat low on memory, failed to find what we needed */
-       for (i = 0; zones[i] != NULL; i++)
-               wakeup_kswapd(zones[i]);
-
-       /* Go through the zonelist again, taking __GFP_HIGH into account */
-       for (i = 0; zones[i] != NULL; i++) {
-               struct zone *z = zones[i];
-
-               min = (1<<order) + z->protection[alloc_type];
+       for (i = 0; (z = zones[i]) != NULL; i++)
+               wakeup_kswapd(z);
 
+       /*
+        * Go through the zonelist again. Let __GFP_HIGH and allocations
+        * coming from realtime tasks to go deeper into reserves
+        */
+       for (i = 0; (z = zones[i]) != NULL; i++) {
+               min = z->pages_min;
                if (gfp_mask & __GFP_HIGH)
-                       min -= z->pages_low >> 2;
-               if (rt_task(p))
-                       min -= z->pages_low >> 1;
+                       min /= 2;
+               if (can_try_harder)
+                       min -= min / 4;
+               min += (1<<order) + z->protection[alloc_type];
 
-               if (z->free_pages >= min ||
-                               (!wait && z->free_pages >= z->pages_high)) {
-                       page = buffered_rmqueue(z, order, gfp_mask);
-                       if (page)
-                               goto got_pg;
-               }
-       }
+               if (z->free_pages < min)
+                       continue;
 
-       /* here we're in the low on memory slow path */
+               page = buffered_rmqueue(z, order, gfp_mask);
+               if (page)
+                       goto got_pg;
+       }
 
-rebalance:
+       /* This allocation should allow future memory freeing. */
        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];
-
+               for (i = 0; (z = zones[i]) != NULL; i++) {
                        page = buffered_rmqueue(z, order, gfp_mask);
                        if (page)
                                goto got_pg;
@@ -640,6 +679,8 @@ rebalance:
        if (!wait)
                goto nopage;
 
+rebalance:
+       /* We now go into synchronous reclaim */
        p->flags |= PF_MEMALLOC;
        reclaim_state.reclaimed_slab = 0;
        p->reclaim_state = &reclaim_state;
@@ -650,25 +691,28 @@ rebalance:
        p->flags &= ~PF_MEMALLOC;
 
        /* go through the zonelist yet one more time */
-       for (i = 0; zones[i] != NULL; i++) {
-               struct zone *z = zones[i];
+       for (i = 0; (z = zones[i]) != NULL; i++) {
+               min = z->pages_min;
+               if (gfp_mask & __GFP_HIGH)
+                       min /= 2;
+               if (can_try_harder)
+                       min -= min / 4;
+               min += (1<<order) + z->protection[alloc_type];
 
-               min = (1UL << order) + z->protection[alloc_type];
+               if (z->free_pages < min)
+                       continue;
 
-               if (z->free_pages >= min ||
-                               (!wait && z->free_pages >= z->pages_high)) {
-                       page = buffered_rmqueue(z, order, gfp_mask);
-                       if (page)
-                               goto got_pg;
-               }
+               page = buffered_rmqueue(z, order, gfp_mask);
+               if (page)
+                       goto got_pg;
        }
 
        /*
         * 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)) {
@@ -691,59 +735,19 @@ nopage:
        }
        return NULL;
 got_pg:
+       zone_statistics(zonelist, z);
        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)
 {
        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;
@@ -796,8 +800,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);
        }
 }
 
@@ -819,17 +823,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)
 {
@@ -953,18 +946,53 @@ void get_full_page_state(struct page_state *ret)
        __get_page_state(ret, sizeof(*ret) / sizeof(unsigned long));
 }
 
+unsigned long __read_page_state(unsigned offset)
+{
+       unsigned long ret = 0;
+       int cpu;
+
+       for (cpu = 0; cpu < NR_CPUS; 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 __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_pgdat(pgdat) {
+               unsigned long l, m, n;
+               __get_zone_counts(&l, &m, &n, pgdat);
+               *active += l;
+               *inactive += m;
+               *free += n;
        }
 }
 
@@ -982,6 +1010,8 @@ void si_meminfo(struct sysinfo *val)
        val->freehigh = 0;
 #endif
        val->mem_unit = PAGE_SIZE;
+       if (vx_flags(VXF_VIRT_MEM, 0))
+               vx_vsi_meminfo(val);
 }
 
 EXPORT_SYMBOL(si_meminfo);
@@ -1212,7 +1242,7 @@ static void __init build_zonelists(pg_data_t *pgdat)
        DECLARE_BITMAP(used_mask, MAX_NUMNODES);
 
        /* 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;
@@ -1234,7 +1264,7 @@ static void __init build_zonelists(pg_data_t *pgdat)
                        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++);
 
@@ -1257,7 +1287,7 @@ 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;
@@ -1284,7 +1314,7 @@ static void __init build_zonelists(pg_data_t *pgdat)
                for (node = 0; node < local_node; node++)
                        j = build_zonelists_node(NODE_DATA(node), zonelist, j, k);
  
-               zonelist->zones[j++] = NULL;
+               zonelist->zones[j] = NULL;
        }
 }
 
@@ -1358,7 +1388,7 @@ static void __init calculate_zone_totalpages(struct pglist_data *pgdat,
                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);
+       printk(KERN_DEBUG "On node %d totalpages: %lu\n", pgdat->node_id, realtotalpages);
 }
 
 
@@ -1367,28 +1397,76 @@ static void __init calculate_zone_totalpages(struct pglist_data *pgdat,
  * 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)
+void __init memmap_init_zone(unsigned long size, int nid, unsigned long zone,
+               unsigned long start_pfn)
 {
+       struct page *start = pfn_to_page(start_pfn);
        struct page *page;
 
        for (page = start; page < (start + size); page++) {
                set_page_zone(page, NODEZONE(nid, zone));
                set_page_count(page, 0);
+               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 (zone != ZONE_HIGHMEM)
+               if (!is_highmem_idx(zone))
                        set_page_address(page, __va(start_pfn << PAGE_SHIFT));
 #endif
                start_pfn++;
        }
 }
 
+/*
+ * 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.
+ */
+unsigned long pages_to_bitmap_size(unsigned long order, unsigned long nr_pages)
+{
+       unsigned long bitmap_size;
+
+       bitmap_size = (nr_pages-1) >> (order+4);
+       bitmap_size = LONG_ALIGN(bitmap_size+1);
+
+       return bitmap_size;
+}
+
+void zone_init_free_lists(struct pglist_data *pgdat, struct zone *zone, unsigned long size)
+{
+       int order;
+       for (order = 0; ; order++) {
+               unsigned long bitmap_size;
+
+               INIT_LIST_HEAD(&zone->free_area[order].free_list);
+               if (order == MAX_ORDER-1) {
+                       zone->free_area[order].map = NULL;
+                       break;
+               }
+
+               bitmap_size = pages_to_bitmap_size(order, size);
+               zone->free_area[order].map =
+                 (unsigned long *) alloc_bootmem_node(pgdat, bitmap_size);
+       }
+}
+
 #ifndef __HAVE_ARCH_MEMMAP_INIT
-#define memmap_init(start, size, nid, zone, start_pfn) \
-       memmap_init_zone((start), (size), (nid), (zone), (start_pfn))
+#define memmap_init(size, nid, zone, start_pfn) \
+       memmap_init_zone((size), (nid), (zone), (start_pfn))
 #endif
 
 /*
@@ -1403,7 +1481,6 @@ static void __init free_area_init_core(struct pglist_data *pgdat,
        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 zone_start_pfn = pgdat->node_start_pfn;
 
        pgdat->nr_zones = 0;
@@ -1419,6 +1496,10 @@ static void __init free_area_init_core(struct pglist_data *pgdat,
                if (zholes_size)
                        realsize -= zholes_size[j];
 
+               if (j == ZONE_DMA || j == ZONE_NORMAL)
+                       nr_kernel_pages += realsize;
+               nr_all_pages += realsize;
+
                zone->spanned_pages = size;
                zone->present_pages = realsize;
                zone->name = zone_names[j];
@@ -1460,12 +1541,12 @@ static void __init free_area_init_core(struct pglist_data *pgdat,
                        pcp->batch = 1 * batch;
                        INIT_LIST_HEAD(&pcp->list);
                }
-               printk("  %s zone: %lu pages, LIFO batch:%lu\n",
+               printk(KERN_DEBUG "  %s zone: %lu pages, LIFO batch:%lu\n",
                                zone_names[j], realsize, batch);
                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;
                if (!size)
@@ -1487,71 +1568,41 @@ static void __init free_area_init_core(struct pglist_data *pgdat,
 
                pgdat->nr_zones = j+1;
 
-               zone->zone_mem_map = lmem_map;
+               zone->zone_mem_map = pfn_to_page(zone_start_pfn);
                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);
+               memmap_init(size, nid, j, zone_start_pfn);
 
                zone_start_pfn += size;
-               lmem_map += size;
-
-               for (i = 0; ; i++) {
-                       unsigned long bitmap_size;
 
-                       INIT_LIST_HEAD(&zone->free_area[i].free_list);
-                       if (i == MAX_ORDER-1) {
-                               zone->free_area[i].map = NULL;
-                               break;
-                       }
-
-                       /*
-                        * 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);
-               }
+               zone_init_free_lists(pgdat, zone, zone->spanned_pages);
        }
 }
 
-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)
+void __init node_alloc_mem_map(struct pglist_data *pgdat)
 {
        unsigned long size;
 
+       size = (pgdat->node_spanned_pages + 1) * sizeof(struct page);
+       pgdat->node_mem_map = alloc_bootmem_node(pgdat, size);
+#ifndef CONFIG_DISCONTIGMEM
+       mem_map = contig_page_data.node_mem_map;
+#endif
+}
+
+void __init free_area_init_node(int nid, struct pglist_data *pgdat,
+               unsigned long *zones_size, unsigned long node_start_pfn,
+               unsigned long *zholes_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;
+
+       if (!pfn_to_page(node_start_pfn))
+               node_alloc_mem_map(pgdat);
 
        free_area_init_core(pgdat, zones_size, zholes_size);
 }
@@ -1564,9 +1615,8 @@ EXPORT_SYMBOL(contig_page_data);
 
 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, &contig_page_data, zones_size,
                        __pa(PAGE_OFFSET) >> PAGE_SHIFT, NULL);
-       mem_map = contig_page_data.node_mem_map;
 }
 #endif
 
@@ -1813,7 +1863,7 @@ static void setup_per_zone_protection(void)
                 * For each of the different allocation types:
                 * GFP_DMA -> GFP_KERNEL -> GFP_HIGHMEM
                 */
-               for (i = 0; i < MAX_NR_ZONES; i++) {
+               for (i = 0; i < GFP_ZONETYPES; i++) {
                        /*
                         * For each of the zones:
                         * ZONE_HIGHMEM -> ZONE_NORMAL -> ZONE_DMA
@@ -1825,11 +1875,11 @@ static void setup_per_zone_protection(void)
                                 * 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
+                                * 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) {
+                               if (j > max_zone || j >= i) {
                                        zone->protection[i] = 0;
                                        continue;
                                }
@@ -1838,7 +1888,6 @@ static void setup_per_zone_protection(void)
                                 */
                                zone->protection[i] = higherzone_val(zone,
                                                                max_zone, i);
-                               zone->protection[i] += zone->pages_low;
                        }
                }
        }
@@ -1939,9 +1988,9 @@ 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;
@@ -1953,9 +2002,74 @@ int min_free_kbytes_sysctl_handler(ctl_table *table, int write,
  *     whenever sysctl_lower_zone_protection changes.
  */
 int lower_zone_protection_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_minmax(table, write, file, buffer, length);
+       proc_dointvec_minmax(table, write, file, buffer, length, ppos);
        setup_per_zone_protection();
        return 0;
 }
+
+/*
+ * 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
+ */
+void *__init alloc_large_system_hash(const char *tablename,
+                                    unsigned long bucketsize,
+                                    unsigned long numentries,
+                                    int scale,
+                                    int consider_highmem,
+                                    unsigned int *_hash_shift,
+                                    unsigned int *_hash_mask)
+{
+       unsigned long long max;
+       unsigned long log2qty, size;
+       void *table;
+
+       /* allow the kernel cmdline to have a say */
+       if (!numentries) {
+               /* round applicable memory size up to nearest megabyte */
+               numentries = consider_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);
+       }
+       /* rounded up to nearest power of 2 in size */
+       numentries = 1UL << (long_log2(numentries) + 1);
+
+       /* limit allocation size to 1/16 total memory */
+       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;
+               table = alloc_bootmem(size);
+       } 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;
+}