Revert "mm/cma: manage the memory of the CMA area by using the ZONE_MOVABLE"
authorJoonsoo Kim <iamjoonsoo.kim@lge.com>
Wed, 23 May 2018 01:18:21 +0000 (10:18 +0900)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 24 May 2018 17:07:50 +0000 (10:07 -0700)
This reverts the following commits that change CMA design in MM.

 3d2054ad8c2d ("ARM: CMA: avoid double mapping to the CMA area if CONFIG_HIGHMEM=y")

 1d47a3ec09b5 ("mm/cma: remove ALLOC_CMA")

 bad8c6c0b114 ("mm/cma: manage the memory of the CMA area by using the ZONE_MOVABLE")

Ville reported a following error on i386.

  Inode-cache hash table entries: 65536 (order: 6, 262144 bytes)
  microcode: microcode updated early to revision 0x4, date = 2013-06-28
  Initializing CPU#0
  Initializing HighMem for node 0 (000377fe:00118000)
  Initializing Movable for node 0 (00000001:00118000)
  BUG: Bad page state in process swapper  pfn:377fe
  page:f53effc0 count:0 mapcount:-127 mapping:00000000 index:0x0
  flags: 0x80000000()
  raw: 80000000 00000000 00000000 ffffff80 00000000 00000100 00000200 00000001
  page dumped because: nonzero mapcount
  Modules linked in:
  CPU: 0 PID: 0 Comm: swapper Not tainted 4.17.0-rc5-elk+ #145
  Hardware name: Dell Inc. Latitude E5410/03VXMC, BIOS A15 07/11/2013
  Call Trace:
   dump_stack+0x60/0x96
   bad_page+0x9a/0x100
   free_pages_check_bad+0x3f/0x60
   free_pcppages_bulk+0x29d/0x5b0
   free_unref_page_commit+0x84/0xb0
   free_unref_page+0x3e/0x70
   __free_pages+0x1d/0x20
   free_highmem_page+0x19/0x40
   add_highpages_with_active_regions+0xab/0xeb
   set_highmem_pages_init+0x66/0x73
   mem_init+0x1b/0x1d7
   start_kernel+0x17a/0x363
   i386_start_kernel+0x95/0x99
   startup_32_smp+0x164/0x168

The reason for this error is that the span of MOVABLE_ZONE is extended
to whole node span for future CMA initialization, and, normal memory is
wrongly freed here.  I submitted the fix and it seems to work, but,
another problem happened.

It's so late time to fix the later problem so I decide to reverting the
series.

Reported-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Acked-by: Laura Abbott <labbott@redhat.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
arch/arm/mm/dma-mapping.c
include/linux/memory_hotplug.h
include/linux/mm.h
mm/cma.c
mm/compaction.c
mm/internal.h
mm/page_alloc.c

index 8c398fedbbb6af30b461fb09cabd89b04cc09648..ada8eb206a90b6824427d24c5019100895d225f2 100644 (file)
@@ -466,12 +466,6 @@ void __init dma_contiguous_early_fixup(phys_addr_t base, unsigned long size)
 void __init dma_contiguous_remap(void)
 {
        int i;
-
-       if (!dma_mmu_remap_num)
-               return;
-
-       /* call flush_cache_all() since CMA area would be large enough */
-       flush_cache_all();
        for (i = 0; i < dma_mmu_remap_num; i++) {
                phys_addr_t start = dma_mmu_remap[i].base;
                phys_addr_t end = start + dma_mmu_remap[i].size;
@@ -504,15 +498,7 @@ void __init dma_contiguous_remap(void)
                flush_tlb_kernel_range(__phys_to_virt(start),
                                       __phys_to_virt(end));
 
-               /*
-                * All the memory in CMA region will be on ZONE_MOVABLE.
-                * If that zone is considered as highmem, the memory in CMA
-                * region is also considered as highmem even if it's
-                * physical address belong to lowmem. In this case,
-                * re-mapping isn't required.
-                */
-               if (!is_highmem_idx(ZONE_MOVABLE))
-                       iotable_init(&map, 1);
+               iotable_init(&map, 1);
        }
 }
 
index e0e49b5b1ee138344185e6e1ae5796fc4ecf4fdf..2b0265265c286b9fffb53e290039bf0686046908 100644 (file)
@@ -216,6 +216,9 @@ void put_online_mems(void);
 void mem_hotplug_begin(void);
 void mem_hotplug_done(void);
 
+extern void set_zone_contiguous(struct zone *zone);
+extern void clear_zone_contiguous(struct zone *zone);
+
 #else /* ! CONFIG_MEMORY_HOTPLUG */
 #define pfn_to_online_page(pfn)                        \
 ({                                             \
index c6fa9a255dbf63a9ec938c5c6be3f926917bd502..02a616e2f17d0ff653a5fa1b0f9721423266cf59 100644 (file)
@@ -2109,7 +2109,6 @@ extern void setup_per_cpu_pageset(void);
 
 extern void zone_pcp_update(struct zone *zone);
 extern void zone_pcp_reset(struct zone *zone);
-extern void setup_zone_pageset(struct zone *zone);
 
 /* page_alloc.c */
 extern int min_free_kbytes;
index aa40e6c7b042e95f5fb30a24cb05014c55ce9152..5809bbe360d7fb724a435309e6e693a98f9efbfb 100644 (file)
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -39,7 +39,6 @@
 #include <trace/events/cma.h>
 
 #include "cma.h"
-#include "internal.h"
 
 struct cma cma_areas[MAX_CMA_AREAS];
 unsigned cma_area_count;
@@ -110,25 +109,23 @@ static int __init cma_activate_area(struct cma *cma)
        if (!cma->bitmap)
                return -ENOMEM;
 
+       WARN_ON_ONCE(!pfn_valid(pfn));
+       zone = page_zone(pfn_to_page(pfn));
+
        do {
                unsigned j;
 
                base_pfn = pfn;
-               if (!pfn_valid(base_pfn))
-                       goto err;
-
-               zone = page_zone(pfn_to_page(base_pfn));
                for (j = pageblock_nr_pages; j; --j, pfn++) {
-                       if (!pfn_valid(pfn))
-                               goto err;
-
+                       WARN_ON_ONCE(!pfn_valid(pfn));
                        /*
-                        * In init_cma_reserved_pageblock(), present_pages
-                        * is adjusted with assumption that all pages in
-                        * the pageblock come from a single zone.
+                        * alloc_contig_range requires the pfn range
+                        * specified to be in the same zone. Make this
+                        * simple by forcing the entire CMA resv range
+                        * to be in the same zone.
                         */
                        if (page_zone(pfn_to_page(pfn)) != zone)
-                               goto err;
+                               goto not_in_zone;
                }
                init_cma_reserved_pageblock(pfn_to_page(base_pfn));
        } while (--i);
@@ -142,7 +139,7 @@ static int __init cma_activate_area(struct cma *cma)
 
        return 0;
 
-err:
+not_in_zone:
        pr_err("CMA area %s could not be activated\n", cma->name);
        kfree(cma->bitmap);
        cma->count = 0;
@@ -152,41 +149,6 @@ err:
 static int __init cma_init_reserved_areas(void)
 {
        int i;
-       struct zone *zone;
-       pg_data_t *pgdat;
-
-       if (!cma_area_count)
-               return 0;
-
-       for_each_online_pgdat(pgdat) {
-               unsigned long start_pfn = UINT_MAX, end_pfn = 0;
-
-               zone = &pgdat->node_zones[ZONE_MOVABLE];
-
-               /*
-                * In this case, we cannot adjust the zone range
-                * since it is now maximum node span and we don't
-                * know original zone range.
-                */
-               if (populated_zone(zone))
-                       continue;
-
-               for (i = 0; i < cma_area_count; i++) {
-                       if (pfn_to_nid(cma_areas[i].base_pfn) !=
-                               pgdat->node_id)
-                               continue;
-
-                       start_pfn = min(start_pfn, cma_areas[i].base_pfn);
-                       end_pfn = max(end_pfn, cma_areas[i].base_pfn +
-                                               cma_areas[i].count);
-               }
-
-               if (!end_pfn)
-                       continue;
-
-               zone->zone_start_pfn = start_pfn;
-               zone->spanned_pages = end_pfn - start_pfn;
-       }
 
        for (i = 0; i < cma_area_count; i++) {
                int ret = cma_activate_area(&cma_areas[i]);
@@ -195,32 +157,9 @@ static int __init cma_init_reserved_areas(void)
                        return ret;
        }
 
-       /*
-        * Reserved pages for ZONE_MOVABLE are now activated and
-        * this would change ZONE_MOVABLE's managed page counter and
-        * the other zones' present counter. We need to re-calculate
-        * various zone information that depends on this initialization.
-        */
-       build_all_zonelists(NULL);
-       for_each_populated_zone(zone) {
-               if (zone_idx(zone) == ZONE_MOVABLE) {
-                       zone_pcp_reset(zone);
-                       setup_zone_pageset(zone);
-               } else
-                       zone_pcp_update(zone);
-
-               set_zone_contiguous(zone);
-       }
-
-       /*
-        * We need to re-init per zone wmark by calling
-        * init_per_zone_wmark_min() but doesn't call here because it is
-        * registered on core_initcall and it will be called later than us.
-        */
-
        return 0;
 }
-pure_initcall(cma_init_reserved_areas);
+core_initcall(cma_init_reserved_areas);
 
 /**
  * cma_init_reserved_mem() - create custom contiguous area from reserved memory
index 028b7210a669636bf9ce58bdd67bde71cf23bc6c..29bd1df18b98aff1d4a2a59c9253d5734c32bb20 100644 (file)
@@ -1450,12 +1450,14 @@ static enum compact_result __compaction_suitable(struct zone *zone, int order,
         * if compaction succeeds.
         * For costly orders, we require low watermark instead of min for
         * compaction to proceed to increase its chances.
+        * ALLOC_CMA is used, as pages in CMA pageblocks are considered
+        * suitable migration targets
         */
        watermark = (order > PAGE_ALLOC_COSTLY_ORDER) ?
                                low_wmark_pages(zone) : min_wmark_pages(zone);
        watermark += compact_gap(order);
        if (!__zone_watermark_ok(zone, 0, watermark, classzone_idx,
-                                               0, wmark_target))
+                                               ALLOC_CMA, wmark_target))
                return COMPACT_SKIPPED;
 
        return COMPACT_CONTINUE;
index 62d8c34e63d54dbf45c2d0d4c3fd215d92933e2c..502d141897945dcfc41d346faf5b44daddc49878 100644 (file)
@@ -168,9 +168,6 @@ extern void post_alloc_hook(struct page *page, unsigned int order,
                                        gfp_t gfp_flags);
 extern int user_min_free_kbytes;
 
-extern void set_zone_contiguous(struct zone *zone);
-extern void clear_zone_contiguous(struct zone *zone);
-
 #if defined CONFIG_COMPACTION || defined CONFIG_CMA
 
 /*
@@ -498,6 +495,7 @@ unsigned long reclaim_clean_pages_from_list(struct zone *zone,
 #define ALLOC_HARDER           0x10 /* try to alloc harder */
 #define ALLOC_HIGH             0x20 /* __GFP_HIGH set */
 #define ALLOC_CPUSET           0x40 /* check for correct cpuset */
+#define ALLOC_CMA              0x80 /* allow allocations from CMA areas */
 
 enum ttu_flags;
 struct tlbflush_unmap_batch;
index 905db9d7962fcb1776c0e7ffb1618fb6e4084a75..511a7124d7f9029a110df3b4582a1b457831884f 100644 (file)
@@ -1743,38 +1743,16 @@ void __init page_alloc_init_late(void)
 }
 
 #ifdef CONFIG_CMA
-static void __init adjust_present_page_count(struct page *page, long count)
-{
-       struct zone *zone = page_zone(page);
-
-       /* We don't need to hold a lock since it is boot-up process */
-       zone->present_pages += count;
-}
-
 /* Free whole pageblock and set its migration type to MIGRATE_CMA. */
 void __init init_cma_reserved_pageblock(struct page *page)
 {
        unsigned i = pageblock_nr_pages;
-       unsigned long pfn = page_to_pfn(page);
        struct page *p = page;
-       int nid = page_to_nid(page);
-
-       /*
-        * ZONE_MOVABLE will steal present pages from other zones by
-        * changing page links so page_zone() is changed. Before that,
-        * we need to adjust previous zone's page count first.
-        */
-       adjust_present_page_count(page, -pageblock_nr_pages);
 
        do {
                __ClearPageReserved(p);
                set_page_count(p, 0);
-
-               /* Steal pages from other zones */
-               set_page_links(p, ZONE_MOVABLE, nid, pfn);
-       } while (++p, ++pfn, --i);
-
-       adjust_present_page_count(page, pageblock_nr_pages);
+       } while (++p, --i);
 
        set_pageblock_migratetype(page, MIGRATE_CMA);
 
@@ -2889,7 +2867,7 @@ int __isolate_free_page(struct page *page, unsigned int order)
                 * exists.
                 */
                watermark = min_wmark_pages(zone) + (1UL << order);
-               if (!zone_watermark_ok(zone, 0, watermark, 0, 0))
+               if (!zone_watermark_ok(zone, 0, watermark, 0, ALLOC_CMA))
                        return 0;
 
                __mod_zone_freepage_state(zone, -(1UL << order), mt);
@@ -3165,6 +3143,12 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark,
        }
 
 
+#ifdef CONFIG_CMA
+       /* If allocation can't use CMA areas don't use free CMA pages */
+       if (!(alloc_flags & ALLOC_CMA))
+               free_pages -= zone_page_state(z, NR_FREE_CMA_PAGES);
+#endif
+
        /*
         * Check watermarks for an order-0 allocation request. If these
         * are not met, then a high-order request also cannot go ahead
@@ -3191,8 +3175,10 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark,
                }
 
 #ifdef CONFIG_CMA
-               if (!list_empty(&area->free_list[MIGRATE_CMA]))
+               if ((alloc_flags & ALLOC_CMA) &&
+                   !list_empty(&area->free_list[MIGRATE_CMA])) {
                        return true;
+               }
 #endif
                if (alloc_harder &&
                        !list_empty(&area->free_list[MIGRATE_HIGHATOMIC]))
@@ -3212,6 +3198,13 @@ static inline bool zone_watermark_fast(struct zone *z, unsigned int order,
                unsigned long mark, int classzone_idx, unsigned int alloc_flags)
 {
        long free_pages = zone_page_state(z, NR_FREE_PAGES);
+       long cma_pages = 0;
+
+#ifdef CONFIG_CMA
+       /* If allocation can't use CMA areas don't use free CMA pages */
+       if (!(alloc_flags & ALLOC_CMA))
+               cma_pages = zone_page_state(z, NR_FREE_CMA_PAGES);
+#endif
 
        /*
         * Fast check for order-0 only. If this fails then the reserves
@@ -3220,7 +3213,7 @@ static inline bool zone_watermark_fast(struct zone *z, unsigned int order,
         * the caller is !atomic then it'll uselessly search the free
         * list. That corner case is then slower but it is harmless.
         */
-       if (!order && free_pages > mark + z->lowmem_reserve[classzone_idx])
+       if (!order && (free_pages - cma_pages) > mark + z->lowmem_reserve[classzone_idx])
                return true;
 
        return __zone_watermark_ok(z, order, mark, classzone_idx, alloc_flags,
@@ -3856,6 +3849,10 @@ gfp_to_alloc_flags(gfp_t gfp_mask)
        } else if (unlikely(rt_task(current)) && !in_interrupt())
                alloc_flags |= ALLOC_HARDER;
 
+#ifdef CONFIG_CMA
+       if (gfpflags_to_migratetype(gfp_mask) == MIGRATE_MOVABLE)
+               alloc_flags |= ALLOC_CMA;
+#endif
        return alloc_flags;
 }
 
@@ -4322,6 +4319,9 @@ static inline bool prepare_alloc_pages(gfp_t gfp_mask, unsigned int order,
        if (should_fail_alloc_page(gfp_mask, order))
                return false;
 
+       if (IS_ENABLED(CONFIG_CMA) && ac->migratetype == MIGRATE_MOVABLE)
+               *alloc_flags |= ALLOC_CMA;
+
        return true;
 }
 
@@ -6204,7 +6204,6 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat)
 {
        enum zone_type j;
        int nid = pgdat->node_id;
-       unsigned long node_end_pfn = 0;
 
        pgdat_resize_init(pgdat);
 #ifdef CONFIG_NUMA_BALANCING
@@ -6232,13 +6231,9 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat)
                struct zone *zone = pgdat->node_zones + j;
                unsigned long size, realsize, freesize, memmap_pages;
                unsigned long zone_start_pfn = zone->zone_start_pfn;
-               unsigned long movable_size = 0;
 
                size = zone->spanned_pages;
                realsize = freesize = zone->present_pages;
-               if (zone_end_pfn(zone) > node_end_pfn)
-                       node_end_pfn = zone_end_pfn(zone);
-
 
                /*
                 * Adjust freesize so that it accounts for how much memory
@@ -6287,30 +6282,12 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat)
                zone_seqlock_init(zone);
                zone_pcp_init(zone);
 
-               /*
-                * The size of the CMA area is unknown now so we need to
-                * prepare the memory for the usemap at maximum.
-                */
-               if (IS_ENABLED(CONFIG_CMA) && j == ZONE_MOVABLE &&
-                       pgdat->node_spanned_pages) {
-                       movable_size = node_end_pfn - pgdat->node_start_pfn;
-               }
-
-               if (!size && !movable_size)
+               if (!size)
                        continue;
 
                set_pageblock_order();
-               if (movable_size) {
-                       zone->zone_start_pfn = pgdat->node_start_pfn;
-                       zone->spanned_pages = movable_size;
-                       setup_usemap(pgdat, zone,
-                               pgdat->node_start_pfn, movable_size);
-                       init_currently_empty_zone(zone,
-                               pgdat->node_start_pfn, movable_size);
-               } else {
-                       setup_usemap(pgdat, zone, zone_start_pfn, size);
-                       init_currently_empty_zone(zone, zone_start_pfn, size);
-               }
+               setup_usemap(pgdat, zone, zone_start_pfn, size);
+               init_currently_empty_zone(zone, zone_start_pfn, size);
                memmap_init(size, nid, j, zone_start_pfn);
        }
 }
@@ -7951,7 +7928,7 @@ void free_contig_range(unsigned long pfn, unsigned nr_pages)
 }
 #endif
 
-#if defined CONFIG_MEMORY_HOTPLUG || defined CONFIG_CMA
+#ifdef CONFIG_MEMORY_HOTPLUG
 /*
  * The zone indicated has a new number of managed_pages; batch sizes and percpu
  * page high values need to be recalulated.