xfs: factor out xfs_dir2_leaf_find_stale
[pandora-kernel.git] / mm / page_alloc.c
index 9d5498e..4e8985a 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/pagevec.h>
 #include <linux/blkdev.h>
 #include <linux/slab.h>
+#include <linux/ratelimit.h>
 #include <linux/oom.h>
 #include <linux/notifier.h>
 #include <linux/topology.h>
@@ -39,6 +40,7 @@
 #include <linux/memory_hotplug.h>
 #include <linux/nodemask.h>
 #include <linux/vmalloc.h>
+#include <linux/vmstat.h>
 #include <linux/mempolicy.h>
 #include <linux/stop_machine.h>
 #include <linux/sort.h>
@@ -1735,6 +1737,45 @@ static inline bool should_suppress_show_mem(void)
        return ret;
 }
 
+static DEFINE_RATELIMIT_STATE(nopage_rs,
+               DEFAULT_RATELIMIT_INTERVAL,
+               DEFAULT_RATELIMIT_BURST);
+
+void warn_alloc_failed(gfp_t gfp_mask, int order, const char *fmt, ...)
+{
+       va_list args;
+       unsigned int filter = SHOW_MEM_FILTER_NODES;
+
+       if ((gfp_mask & __GFP_NOWARN) || !__ratelimit(&nopage_rs))
+               return;
+
+       /*
+        * This documents exceptions given to allocations in certain
+        * contexts that are allowed to allocate outside current's set
+        * of allowed nodes.
+        */
+       if (!(gfp_mask & __GFP_NOMEMALLOC))
+               if (test_thread_flag(TIF_MEMDIE) ||
+                   (current->flags & (PF_MEMALLOC | PF_EXITING)))
+                       filter &= ~SHOW_MEM_FILTER_NODES;
+       if (in_interrupt() || !(gfp_mask & __GFP_WAIT))
+               filter &= ~SHOW_MEM_FILTER_NODES;
+
+       if (fmt) {
+               printk(KERN_WARNING);
+               va_start(args, fmt);
+               vprintk(fmt, args);
+               va_end(args);
+       }
+
+       pr_warning("%s: page allocation failure: order:%d, mode:0x%x\n",
+                  current->comm, order, gfp_mask);
+
+       dump_stack();
+       if (!should_suppress_show_mem())
+               show_mem(filter);
+}
+
 static inline int
 should_alloc_retry(gfp_t gfp_mask, unsigned int order,
                                unsigned long pages_reclaimed)
@@ -2065,6 +2106,7 @@ restart:
                first_zones_zonelist(zonelist, high_zoneidx, NULL,
                                        &preferred_zone);
 
+rebalance:
        /* This is the last chance, in general, before the goto nopage. */
        page = get_page_from_freelist(gfp_mask, nodemask, order, zonelist,
                        high_zoneidx, alloc_flags & ~ALLOC_NO_WATERMARKS,
@@ -2072,7 +2114,6 @@ restart:
        if (page)
                goto got_pg;
 
-rebalance:
        /* Allocate without watermarks if the context allows */
        if (alloc_flags & ALLOC_NO_WATERMARKS) {
                page = __alloc_pages_high_priority(gfp_mask, order,
@@ -2106,7 +2147,7 @@ rebalance:
                                        sync_migration);
        if (page)
                goto got_pg;
-       sync_migration = !(gfp_mask & __GFP_NO_KSWAPD);
+       sync_migration = true;
 
        /* Try direct reclaim and then allocating */
        page = __alloc_pages_direct_reclaim(gfp_mask, order,
@@ -2177,27 +2218,7 @@ rebalance:
        }
 
 nopage:
-       if (!(gfp_mask & __GFP_NOWARN) && printk_ratelimit()) {
-               unsigned int filter = SHOW_MEM_FILTER_NODES;
-
-               /*
-                * This documents exceptions given to allocations in certain
-                * contexts that are allowed to allocate outside current's set
-                * of allowed nodes.
-                */
-               if (!(gfp_mask & __GFP_NOMEMALLOC))
-                       if (test_thread_flag(TIF_MEMDIE) ||
-                           (current->flags & (PF_MEMALLOC | PF_EXITING)))
-                               filter &= ~SHOW_MEM_FILTER_NODES;
-               if (in_interrupt() || !wait)
-                       filter &= ~SHOW_MEM_FILTER_NODES;
-
-               pr_warning("%s: page allocation failure. order:%d, mode:0x%x\n",
-                       current->comm, order, gfp_mask);
-               dump_stack();
-               if (!should_suppress_show_mem())
-                       show_mem(filter);
-       }
+       warn_alloc_failed(gfp_mask, order, NULL);
        return page;
 got_pg:
        if (kmemcheck_enabled)
@@ -2473,10 +2494,10 @@ void si_meminfo_node(struct sysinfo *val, int nid)
 #endif
 
 /*
- * Determine whether the zone's node should be displayed or not, depending on
- * whether SHOW_MEM_FILTER_NODES was passed to __show_free_areas().
+ * Determine whether the node should be displayed or not, depending on whether
+ * SHOW_MEM_FILTER_NODES was passed to show_free_areas().
  */
-static bool skip_free_areas_zone(unsigned int flags, const struct zone *zone)
+bool skip_free_areas_node(unsigned int flags, int nid)
 {
        bool ret = false;
 
@@ -2484,8 +2505,7 @@ static bool skip_free_areas_zone(unsigned int flags, const struct zone *zone)
                goto out;
 
        get_mems_allowed();
-       ret = !node_isset(zone->zone_pgdat->node_id,
-                               cpuset_current_mems_allowed);
+       ret = !node_isset(nid, cpuset_current_mems_allowed);
        put_mems_allowed();
 out:
        return ret;
@@ -2500,13 +2520,13 @@ out:
  * Suppresses nodes that are not allowed by current's cpuset if
  * SHOW_MEM_FILTER_NODES is passed.
  */
-void __show_free_areas(unsigned int filter)
+void show_free_areas(unsigned int filter)
 {
        int cpu;
        struct zone *zone;
 
        for_each_populated_zone(zone) {
-               if (skip_free_areas_zone(filter, zone))
+               if (skip_free_areas_node(filter, zone_to_nid(zone)))
                        continue;
                show_node(zone);
                printk("%s per-cpu:\n", zone->name);
@@ -2549,7 +2569,7 @@ void __show_free_areas(unsigned int filter)
        for_each_populated_zone(zone) {
                int i;
 
-               if (skip_free_areas_zone(filter, zone))
+               if (skip_free_areas_node(filter, zone_to_nid(zone)))
                        continue;
                show_node(zone);
                printk("%s"
@@ -2618,7 +2638,7 @@ void __show_free_areas(unsigned int filter)
        for_each_populated_zone(zone) {
                unsigned long nr[MAX_ORDER], flags, order, total = 0;
 
-               if (skip_free_areas_zone(filter, zone))
+               if (skip_free_areas_node(filter, zone_to_nid(zone)))
                        continue;
                show_node(zone);
                printk("%s: ", zone->name);
@@ -2639,11 +2659,6 @@ void __show_free_areas(unsigned int filter)
        show_swap_cache_info();
 }
 
-void show_free_areas(void)
-{
-       __show_free_areas(0);
-}
-
 static void zoneref_set_zone(struct zone *zone, struct zoneref *zoneref)
 {
        zoneref->zone = zone;
@@ -3313,6 +3328,20 @@ static inline unsigned long wait_table_bits(unsigned long size)
 
 #define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1))
 
+/*
+ * Check if a pageblock contains reserved pages
+ */
+static int pageblock_is_reserved(unsigned long start_pfn, unsigned long end_pfn)
+{
+       unsigned long pfn;
+
+       for (pfn = start_pfn; pfn < end_pfn; pfn++) {
+               if (!pfn_valid_within(pfn) || PageReserved(pfn_to_page(pfn)))
+                       return 1;
+       }
+       return 0;
+}
+
 /*
  * Mark a number of pageblocks as MIGRATE_RESERVE. The number
  * of blocks reserved is based on min_wmark_pages(zone). The memory within
@@ -3322,7 +3351,7 @@ static inline unsigned long wait_table_bits(unsigned long size)
  */
 static void setup_zone_migrate_reserve(struct zone *zone)
 {
-       unsigned long start_pfn, pfn, end_pfn;
+       unsigned long start_pfn, pfn, end_pfn, block_end_pfn;
        struct page *page;
        unsigned long block_migratetype;
        int reserve;
@@ -3352,7 +3381,8 @@ static void setup_zone_migrate_reserve(struct zone *zone)
                        continue;
 
                /* Blocks with reserved pages will never free, skip them. */
-               if (PageReserved(page))
+               block_end_pfn = min(pfn + pageblock_nr_pages, end_pfn);
+               if (pageblock_is_reserved(pfn, block_end_pfn))
                        continue;
 
                block_migratetype = get_pageblock_migratetype(page);
@@ -4289,10 +4319,8 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat,
                zone->zone_pgdat = pgdat;
 
                zone_pcp_init(zone);
-               for_each_lru(l) {
+               for_each_lru(l)
                        INIT_LIST_HEAD(&zone->lru[l].list);
-                       zone->reclaim_stat.nr_saved_scan[l] = 0;
-               }
                zone->reclaim_stat.recent_rotated[0] = 0;
                zone->reclaim_stat.recent_rotated[1] = 0;
                zone->reclaim_stat.recent_scanned[0] = 0;
@@ -5100,7 +5128,7 @@ void setup_per_zone_wmarks(void)
  *    1TB     101        10GB
  *   10TB     320        32GB
  */
-void calculate_zone_inactive_ratio(struct zone *zone)
+static void __meminit calculate_zone_inactive_ratio(struct zone *zone)
 {
        unsigned int gb, ratio;
 
@@ -5114,7 +5142,7 @@ void calculate_zone_inactive_ratio(struct zone *zone)
        zone->inactive_ratio = ratio;
 }
 
-static void __init setup_per_zone_inactive_ratio(void)
+static void __meminit setup_per_zone_inactive_ratio(void)
 {
        struct zone *zone;
 
@@ -5146,7 +5174,7 @@ static void __init setup_per_zone_inactive_ratio(void)
  * 8192MB:     11584k
  * 16384MB:    16384k
  */
-static int __init init_per_zone_wmark_min(void)
+int __meminit init_per_zone_wmark_min(void)
 {
        unsigned long lowmem_kbytes;
 
@@ -5158,6 +5186,7 @@ static int __init init_per_zone_wmark_min(void)
        if (min_free_kbytes > 65536)
                min_free_kbytes = 65536;
        setup_per_zone_wmarks();
+       refresh_zone_stat_thresholds();
        setup_per_zone_lowmem_reserve();
        setup_per_zone_inactive_ratio();
        return 0;
@@ -5508,10 +5537,8 @@ int set_migratetype_isolate(struct page *page)
        struct memory_isolate_notify arg;
        int notifier_ret;
        int ret = -EBUSY;
-       int zone_idx;
 
        zone = page_zone(page);
-       zone_idx = zone_idx(zone);
 
        spin_lock_irqsave(&zone->lock, flags);