Merge tag 'dm-3.7-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/agk/linux-dm
[cascardo/linux.git] / mm / page_alloc.c
index 82f0b2f..bb90971 100644 (file)
@@ -598,17 +598,6 @@ out:
        zone->free_area[order].nr_free++;
 }
 
-/*
- * free_page_mlock() -- clean up attempts to free and mlocked() page.
- * Page should not be on lru, so no need to fix that up.
- * free_pages_check() will verify...
- */
-static inline void free_page_mlock(struct page *page)
-{
-       __dec_zone_page_state(page, NR_MLOCK);
-       __count_vm_event(UNEVICTABLE_MLOCKFREED);
-}
-
 static inline int free_pages_check(struct page *page)
 {
        if (unlikely(page_mapcount(page) |
@@ -728,15 +717,12 @@ static bool free_pages_prepare(struct page *page, unsigned int order)
 static void __free_pages_ok(struct page *page, unsigned int order)
 {
        unsigned long flags;
-       int wasMlocked = __TestClearPageMlocked(page);
        int migratetype;
 
        if (!free_pages_prepare(page, order))
                return;
 
        local_irq_save(flags);
-       if (unlikely(wasMlocked))
-               free_page_mlock(page);
        __count_vm_events(PGFREE, 1 << order);
        migratetype = get_pageblock_migratetype(page);
        set_freepage_migratetype(page, migratetype);
@@ -1310,7 +1296,6 @@ void free_hot_cold_page(struct page *page, int cold)
        struct per_cpu_pages *pcp;
        unsigned long flags;
        int migratetype;
-       int wasMlocked = __TestClearPageMlocked(page);
 
        if (!free_pages_prepare(page, 0))
                return;
@@ -1318,8 +1303,6 @@ void free_hot_cold_page(struct page *page, int cold)
        migratetype = get_pageblock_migratetype(page);
        set_freepage_migratetype(page, migratetype);
        local_irq_save(flags);
-       if (unlikely(wasMlocked))
-               free_page_mlock(page);
        __count_vm_event(PGFREE);
 
        /*
@@ -1816,6 +1799,22 @@ static void zlc_clear_zones_full(struct zonelist *zonelist)
        bitmap_zero(zlc->fullzones, MAX_ZONES_PER_ZONELIST);
 }
 
+static bool zone_allows_reclaim(struct zone *local_zone, struct zone *zone)
+{
+       return node_isset(local_zone->node, zone->zone_pgdat->reclaim_nodes);
+}
+
+static void __paginginit init_zone_allows_reclaim(int nid)
+{
+       int i;
+
+       for_each_online_node(i)
+               if (node_distance(nid, i) <= RECLAIM_DISTANCE) {
+                       node_set(i, NODE_DATA(nid)->reclaim_nodes);
+                       zone_reclaim_mode = 1;
+               }
+}
+
 #else  /* CONFIG_NUMA */
 
 static nodemask_t *zlc_setup(struct zonelist *zonelist, int alloc_flags)
@@ -1836,6 +1835,15 @@ static void zlc_mark_zone_full(struct zonelist *zonelist, struct zoneref *z)
 static void zlc_clear_zones_full(struct zonelist *zonelist)
 {
 }
+
+static bool zone_allows_reclaim(struct zone *local_zone, struct zone *zone)
+{
+       return true;
+}
+
+static inline void init_zone_allows_reclaim(int nid)
+{
+}
 #endif /* CONFIG_NUMA */
 
 /*
@@ -1920,7 +1928,8 @@ zonelist_scan:
                                did_zlc_setup = 1;
                        }
 
-                       if (zone_reclaim_mode == 0)
+                       if (zone_reclaim_mode == 0 ||
+                           !zone_allows_reclaim(preferred_zone, zone))
                                goto this_zone_full;
 
                        /*
@@ -2172,6 +2181,7 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
                                preferred_zone, migratetype);
                if (page) {
 got_page:
+                       preferred_zone->compact_blockskip_flush = false;
                        preferred_zone->compact_considered = 0;
                        preferred_zone->compact_defer_shift = 0;
                        if (order >= preferred_zone->compact_order_failed)
@@ -3380,21 +3390,13 @@ static void build_zonelists(pg_data_t *pgdat)
        j = 0;
 
        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 (distance != node_distance(local_node, prev_node))
+               if (node_distance(local_node, node) !=
+                   node_distance(local_node, prev_node))
                        node_load[node] = load;
 
                prev_node = node;
@@ -4490,11 +4492,6 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat,
 
                zone->spanned_pages = size;
                zone->present_pages = realsize;
-#if defined CONFIG_COMPACTION || defined CONFIG_CMA
-               zone->compact_cached_free_pfn = zone->zone_start_pfn +
-                                               zone->spanned_pages;
-               zone->compact_cached_free_pfn &= ~(pageblock_nr_pages-1);
-#endif
 #ifdef CONFIG_NUMA
                zone->node = nid;
                zone->min_unmapped_pages = (realsize*sysctl_min_unmapped_ratio)
@@ -4573,6 +4570,7 @@ void __paginginit free_area_init_node(int nid, unsigned long *zones_size,
 
        pgdat->node_id = nid;
        pgdat->node_start_pfn = node_start_pfn;
+       init_zone_allows_reclaim(nid);
        calculate_node_totalpages(pgdat, zones_size, zholes_size);
 
        alloc_node_mem_map(pgdat);
@@ -4931,7 +4929,7 @@ void __init free_area_init_nodes(unsigned long *max_zone_pfn)
                               zone_movable_pfn[i] << PAGE_SHIFT);
        }
 
-       /* Print out the early_node_map[] */
+       /* Print out the early node map */
        printk("Early memory node ranges\n");
        for_each_mem_pfn_range(i, MAX_NUMNODES, &start_pfn, &end_pfn, &nid)
                printk("  node %3d: [mem %#010lx-%#010lx]\n", nid,
@@ -5671,47 +5669,28 @@ static unsigned long pfn_max_align_up(unsigned long pfn)
                                pageblock_nr_pages));
 }
 
-static struct page *
-__alloc_contig_migrate_alloc(struct page *page, unsigned long private,
-                            int **resultp)
-{
-       gfp_t gfp_mask = GFP_USER | __GFP_MOVABLE;
-
-       if (PageHighMem(page))
-               gfp_mask |= __GFP_HIGHMEM;
-
-       return alloc_page(gfp_mask);
-}
-
 /* [start, end) must belong to a single zone. */
-static int __alloc_contig_migrate_range(unsigned long start, unsigned long end)
+static int __alloc_contig_migrate_range(struct compact_control *cc,
+                                       unsigned long start, unsigned long end)
 {
        /* This function is based on compact_zone() from compaction.c. */
-
+       unsigned long nr_reclaimed;
        unsigned long pfn = start;
        unsigned int tries = 0;
        int ret = 0;
 
-       struct compact_control cc = {
-               .nr_migratepages = 0,
-               .order = -1,
-               .zone = page_zone(pfn_to_page(start)),
-               .sync = true,
-       };
-       INIT_LIST_HEAD(&cc.migratepages);
-
        migrate_prep_local();
 
-       while (pfn < end || !list_empty(&cc.migratepages)) {
+       while (pfn < end || !list_empty(&cc->migratepages)) {
                if (fatal_signal_pending(current)) {
                        ret = -EINTR;
                        break;
                }
 
-               if (list_empty(&cc.migratepages)) {
-                       cc.nr_migratepages = 0;
-                       pfn = isolate_migratepages_range(cc.zone, &cc,
-                                                        pfn, end);
+               if (list_empty(&cc->migratepages)) {
+                       cc->nr_migratepages = 0;
+                       pfn = isolate_migratepages_range(cc->zone, cc,
+                                                        pfn, end, true);
                        if (!pfn) {
                                ret = -EINTR;
                                break;
@@ -5722,14 +5701,16 @@ static int __alloc_contig_migrate_range(unsigned long start, unsigned long end)
                        break;
                }
 
-               reclaim_clean_pages_from_list(cc.zone, &cc.migratepages);
+               nr_reclaimed = reclaim_clean_pages_from_list(cc->zone,
+                                                       &cc->migratepages);
+               cc->nr_migratepages -= nr_reclaimed;
 
-               ret = migrate_pages(&cc.migratepages,
-                                   __alloc_contig_migrate_alloc,
+               ret = migrate_pages(&cc->migratepages,
+                                   alloc_migrate_target,
                                    0, false, MIGRATE_SYNC);
        }
 
-       putback_lru_pages(&cc.migratepages);
+       putback_lru_pages(&cc->migratepages);
        return ret > 0 ? 0 : ret;
 }
 
@@ -5808,6 +5789,15 @@ int alloc_contig_range(unsigned long start, unsigned long end,
        unsigned long outer_start, outer_end;
        int ret = 0, order;
 
+       struct compact_control cc = {
+               .nr_migratepages = 0,
+               .order = -1,
+               .zone = page_zone(pfn_to_page(start)),
+               .sync = true,
+               .ignore_skip_hint = true,
+       };
+       INIT_LIST_HEAD(&cc.migratepages);
+
        /*
         * What we do here is we mark all pageblocks in range as
         * MIGRATE_ISOLATE.  Because pageblock and max order pages may
@@ -5837,7 +5827,7 @@ int alloc_contig_range(unsigned long start, unsigned long end,
        if (ret)
                goto done;
 
-       ret = __alloc_contig_migrate_range(start, end);
+       ret = __alloc_contig_migrate_range(&cc, start, end);
        if (ret)
                goto done;
 
@@ -5886,7 +5876,7 @@ int alloc_contig_range(unsigned long start, unsigned long end,
        __reclaim_pages(zone, GFP_HIGHUSER_MOVABLE, end-start);
 
        /* Grab isolated pages from freelists. */
-       outer_end = isolate_freepages_range(outer_start, end);
+       outer_end = isolate_freepages_range(&cc, outer_start, end);
        if (!outer_end) {
                ret = -EBUSY;
                goto done;
@@ -5928,6 +5918,7 @@ static int __meminit __zone_pcp_update(void *data)
                local_irq_save(flags);
                if (pcp->count > 0)
                        free_pcppages_bulk(zone, pcp->count, pcp);
+               drain_zonestat(zone, pset);
                setup_pageset(pset, batch);
                local_irq_restore(flags);
        }
@@ -5944,10 +5935,16 @@ void __meminit zone_pcp_update(struct zone *zone)
 void zone_pcp_reset(struct zone *zone)
 {
        unsigned long flags;
+       int cpu;
+       struct per_cpu_pageset *pset;
 
        /* avoid races with drain_pages()  */
        local_irq_save(flags);
        if (zone->pageset != &boot_pageset) {
+               for_each_online_cpu(cpu) {
+                       pset = per_cpu_ptr(zone->pageset, cpu);
+                       drain_zonestat(zone, pset);
+               }
                free_percpu(zone->pageset);
                zone->pageset = &boot_pageset;
        }
@@ -6101,3 +6098,37 @@ void dump_page(struct page *page)
        dump_page_flags(page->flags);
        mem_cgroup_print_bad_page(page);
 }
+
+/* reset zone->present_pages */
+void reset_zone_present_pages(void)
+{
+       struct zone *z;
+       int i, nid;
+
+       for_each_node_state(nid, N_HIGH_MEMORY) {
+               for (i = 0; i < MAX_NR_ZONES; i++) {
+                       z = NODE_DATA(nid)->node_zones + i;
+                       z->present_pages = 0;
+               }
+       }
+}
+
+/* calculate zone's present pages in buddy system */
+void fixup_zone_present_pages(int nid, unsigned long start_pfn,
+                               unsigned long end_pfn)
+{
+       struct zone *z;
+       unsigned long zone_start_pfn, zone_end_pfn;
+       int i;
+
+       for (i = 0; i < MAX_NR_ZONES; i++) {
+               z = NODE_DATA(nid)->node_zones + i;
+               zone_start_pfn = z->zone_start_pfn;
+               zone_end_pfn = zone_start_pfn + z->spanned_pages;
+
+               /* if the two regions intersect */
+               if (!(zone_start_pfn >= end_pfn || zone_end_pfn <= start_pfn))
+                       z->present_pages += min(end_pfn, zone_end_pfn) -
+                                           max(start_pfn, zone_start_pfn);
+       }
+}