Commit d883c6cf authored by Joonsoo Kim's avatar Joonsoo Kim Committed by Linus Torvalds

Revert "mm/cma: manage the memory of the CMA area by using the ZONE_MOVABLE"

This reverts the following commits that change CMA design in MM.

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

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

 bad8c6c0 ("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: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Acked-by: default avatarLaura Abbott <labbott@redhat.com>
Acked-by: default avatarMichal Hocko <mhocko@suse.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarJoonsoo Kim <iamjoonsoo.kim@lge.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 577e75e0
...@@ -466,12 +466,6 @@ void __init dma_contiguous_early_fixup(phys_addr_t base, unsigned long size) ...@@ -466,12 +466,6 @@ void __init dma_contiguous_early_fixup(phys_addr_t base, unsigned long size)
void __init dma_contiguous_remap(void) void __init dma_contiguous_remap(void)
{ {
int i; 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++) { for (i = 0; i < dma_mmu_remap_num; i++) {
phys_addr_t start = dma_mmu_remap[i].base; phys_addr_t start = dma_mmu_remap[i].base;
phys_addr_t end = start + dma_mmu_remap[i].size; phys_addr_t end = start + dma_mmu_remap[i].size;
...@@ -504,15 +498,7 @@ void __init dma_contiguous_remap(void) ...@@ -504,15 +498,7 @@ void __init dma_contiguous_remap(void)
flush_tlb_kernel_range(__phys_to_virt(start), flush_tlb_kernel_range(__phys_to_virt(start),
__phys_to_virt(end)); __phys_to_virt(end));
/* iotable_init(&map, 1);
* 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);
} }
} }
......
...@@ -216,6 +216,9 @@ void put_online_mems(void); ...@@ -216,6 +216,9 @@ void put_online_mems(void);
void mem_hotplug_begin(void); void mem_hotplug_begin(void);
void mem_hotplug_done(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 */ #else /* ! CONFIG_MEMORY_HOTPLUG */
#define pfn_to_online_page(pfn) \ #define pfn_to_online_page(pfn) \
({ \ ({ \
......
...@@ -2109,7 +2109,6 @@ extern void setup_per_cpu_pageset(void); ...@@ -2109,7 +2109,6 @@ extern void setup_per_cpu_pageset(void);
extern void zone_pcp_update(struct zone *zone); extern void zone_pcp_update(struct zone *zone);
extern void zone_pcp_reset(struct zone *zone); extern void zone_pcp_reset(struct zone *zone);
extern void setup_zone_pageset(struct zone *zone);
/* page_alloc.c */ /* page_alloc.c */
extern int min_free_kbytes; extern int min_free_kbytes;
......
...@@ -39,7 +39,6 @@ ...@@ -39,7 +39,6 @@
#include <trace/events/cma.h> #include <trace/events/cma.h>
#include "cma.h" #include "cma.h"
#include "internal.h"
struct cma cma_areas[MAX_CMA_AREAS]; struct cma cma_areas[MAX_CMA_AREAS];
unsigned cma_area_count; unsigned cma_area_count;
...@@ -110,25 +109,23 @@ static int __init cma_activate_area(struct cma *cma) ...@@ -110,25 +109,23 @@ static int __init cma_activate_area(struct cma *cma)
if (!cma->bitmap) if (!cma->bitmap)
return -ENOMEM; return -ENOMEM;
WARN_ON_ONCE(!pfn_valid(pfn));
zone = page_zone(pfn_to_page(pfn));
do { do {
unsigned j; unsigned j;
base_pfn = pfn; 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++) { for (j = pageblock_nr_pages; j; --j, pfn++) {
if (!pfn_valid(pfn)) WARN_ON_ONCE(!pfn_valid(pfn));
goto err;
/* /*
* In init_cma_reserved_pageblock(), present_pages * alloc_contig_range requires the pfn range
* is adjusted with assumption that all pages in * specified to be in the same zone. Make this
* the pageblock come from a single zone. * simple by forcing the entire CMA resv range
* to be in the same zone.
*/ */
if (page_zone(pfn_to_page(pfn)) != zone) if (page_zone(pfn_to_page(pfn)) != zone)
goto err; goto not_in_zone;
} }
init_cma_reserved_pageblock(pfn_to_page(base_pfn)); init_cma_reserved_pageblock(pfn_to_page(base_pfn));
} while (--i); } while (--i);
...@@ -142,7 +139,7 @@ static int __init cma_activate_area(struct cma *cma) ...@@ -142,7 +139,7 @@ static int __init cma_activate_area(struct cma *cma)
return 0; return 0;
err: not_in_zone:
pr_err("CMA area %s could not be activated\n", cma->name); pr_err("CMA area %s could not be activated\n", cma->name);
kfree(cma->bitmap); kfree(cma->bitmap);
cma->count = 0; cma->count = 0;
...@@ -152,41 +149,6 @@ static int __init cma_activate_area(struct cma *cma) ...@@ -152,41 +149,6 @@ static int __init cma_activate_area(struct cma *cma)
static int __init cma_init_reserved_areas(void) static int __init cma_init_reserved_areas(void)
{ {
int i; 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++) { for (i = 0; i < cma_area_count; i++) {
int ret = cma_activate_area(&cma_areas[i]); int ret = cma_activate_area(&cma_areas[i]);
...@@ -195,32 +157,9 @@ static int __init cma_init_reserved_areas(void) ...@@ -195,32 +157,9 @@ static int __init cma_init_reserved_areas(void)
return ret; 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; 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 * cma_init_reserved_mem() - create custom contiguous area from reserved memory
......
...@@ -1450,12 +1450,14 @@ static enum compact_result __compaction_suitable(struct zone *zone, int order, ...@@ -1450,12 +1450,14 @@ static enum compact_result __compaction_suitable(struct zone *zone, int order,
* if compaction succeeds. * if compaction succeeds.
* For costly orders, we require low watermark instead of min for * For costly orders, we require low watermark instead of min for
* compaction to proceed to increase its chances. * 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) ? watermark = (order > PAGE_ALLOC_COSTLY_ORDER) ?
low_wmark_pages(zone) : min_wmark_pages(zone); low_wmark_pages(zone) : min_wmark_pages(zone);
watermark += compact_gap(order); watermark += compact_gap(order);
if (!__zone_watermark_ok(zone, 0, watermark, classzone_idx, if (!__zone_watermark_ok(zone, 0, watermark, classzone_idx,
0, wmark_target)) ALLOC_CMA, wmark_target))
return COMPACT_SKIPPED; return COMPACT_SKIPPED;
return COMPACT_CONTINUE; return COMPACT_CONTINUE;
......
...@@ -168,9 +168,6 @@ extern void post_alloc_hook(struct page *page, unsigned int order, ...@@ -168,9 +168,6 @@ extern void post_alloc_hook(struct page *page, unsigned int order,
gfp_t gfp_flags); gfp_t gfp_flags);
extern int user_min_free_kbytes; 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 #if defined CONFIG_COMPACTION || defined CONFIG_CMA
/* /*
...@@ -498,6 +495,7 @@ unsigned long reclaim_clean_pages_from_list(struct zone *zone, ...@@ -498,6 +495,7 @@ unsigned long reclaim_clean_pages_from_list(struct zone *zone,
#define ALLOC_HARDER 0x10 /* try to alloc harder */ #define ALLOC_HARDER 0x10 /* try to alloc harder */
#define ALLOC_HIGH 0x20 /* __GFP_HIGH set */ #define ALLOC_HIGH 0x20 /* __GFP_HIGH set */
#define ALLOC_CPUSET 0x40 /* check for correct cpuset */ #define ALLOC_CPUSET 0x40 /* check for correct cpuset */
#define ALLOC_CMA 0x80 /* allow allocations from CMA areas */
enum ttu_flags; enum ttu_flags;
struct tlbflush_unmap_batch; struct tlbflush_unmap_batch;
......
...@@ -1743,38 +1743,16 @@ void __init page_alloc_init_late(void) ...@@ -1743,38 +1743,16 @@ void __init page_alloc_init_late(void)
} }
#ifdef CONFIG_CMA #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. */ /* Free whole pageblock and set its migration type to MIGRATE_CMA. */
void __init init_cma_reserved_pageblock(struct page *page) void __init init_cma_reserved_pageblock(struct page *page)
{ {
unsigned i = pageblock_nr_pages; unsigned i = pageblock_nr_pages;
unsigned long pfn = page_to_pfn(page);
struct page *p = 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 { do {
__ClearPageReserved(p); __ClearPageReserved(p);
set_page_count(p, 0); set_page_count(p, 0);
} while (++p, --i);
/* 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);
set_pageblock_migratetype(page, MIGRATE_CMA); set_pageblock_migratetype(page, MIGRATE_CMA);
...@@ -2889,7 +2867,7 @@ int __isolate_free_page(struct page *page, unsigned int order) ...@@ -2889,7 +2867,7 @@ int __isolate_free_page(struct page *page, unsigned int order)
* exists. * exists.
*/ */
watermark = min_wmark_pages(zone) + (1UL << order); 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; return 0;
__mod_zone_freepage_state(zone, -(1UL << order), mt); __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, ...@@ -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 * Check watermarks for an order-0 allocation request. If these
* are not met, then a high-order request also cannot go ahead * 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, ...@@ -3191,8 +3175,10 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark,
} }
#ifdef CONFIG_CMA #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; return true;
}
#endif #endif
if (alloc_harder && if (alloc_harder &&
!list_empty(&area->free_list[MIGRATE_HIGHATOMIC])) !list_empty(&area->free_list[MIGRATE_HIGHATOMIC]))
...@@ -3212,6 +3198,13 @@ static inline bool zone_watermark_fast(struct zone *z, unsigned int order, ...@@ -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) unsigned long mark, int classzone_idx, unsigned int alloc_flags)
{ {
long free_pages = zone_page_state(z, NR_FREE_PAGES); 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 * 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, ...@@ -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 * the caller is !atomic then it'll uselessly search the free
* list. That corner case is then slower but it is harmless. * 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 true;
return __zone_watermark_ok(z, order, mark, classzone_idx, alloc_flags, return __zone_watermark_ok(z, order, mark, classzone_idx, alloc_flags,
...@@ -3856,6 +3849,10 @@ gfp_to_alloc_flags(gfp_t gfp_mask) ...@@ -3856,6 +3849,10 @@ gfp_to_alloc_flags(gfp_t gfp_mask)
} else if (unlikely(rt_task(current)) && !in_interrupt()) } else if (unlikely(rt_task(current)) && !in_interrupt())
alloc_flags |= ALLOC_HARDER; alloc_flags |= ALLOC_HARDER;
#ifdef CONFIG_CMA
if (gfpflags_to_migratetype(gfp_mask) == MIGRATE_MOVABLE)
alloc_flags |= ALLOC_CMA;
#endif
return alloc_flags; return alloc_flags;
} }
...@@ -4322,6 +4319,9 @@ static inline bool prepare_alloc_pages(gfp_t gfp_mask, unsigned int order, ...@@ -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)) if (should_fail_alloc_page(gfp_mask, order))
return false; return false;
if (IS_ENABLED(CONFIG_CMA) && ac->migratetype == MIGRATE_MOVABLE)
*alloc_flags |= ALLOC_CMA;
return true; return true;
} }
...@@ -6204,7 +6204,6 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat) ...@@ -6204,7 +6204,6 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat)
{ {
enum zone_type j; enum zone_type j;
int nid = pgdat->node_id; int nid = pgdat->node_id;
unsigned long node_end_pfn = 0;
pgdat_resize_init(pgdat); pgdat_resize_init(pgdat);
#ifdef CONFIG_NUMA_BALANCING #ifdef CONFIG_NUMA_BALANCING
...@@ -6232,13 +6231,9 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat) ...@@ -6232,13 +6231,9 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat)
struct zone *zone = pgdat->node_zones + j; struct zone *zone = pgdat->node_zones + j;
unsigned long size, realsize, freesize, memmap_pages; unsigned long size, realsize, freesize, memmap_pages;
unsigned long zone_start_pfn = zone->zone_start_pfn; unsigned long zone_start_pfn = zone->zone_start_pfn;
unsigned long movable_size = 0;
size = zone->spanned_pages; size = zone->spanned_pages;
realsize = freesize = zone->present_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 * 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) ...@@ -6287,30 +6282,12 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat)
zone_seqlock_init(zone); zone_seqlock_init(zone);
zone_pcp_init(zone); zone_pcp_init(zone);
/* if (!size)
* 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)
continue; continue;
set_pageblock_order(); set_pageblock_order();
if (movable_size) { setup_usemap(pgdat, zone, zone_start_pfn, size);
zone->zone_start_pfn = pgdat->node_start_pfn; init_currently_empty_zone(zone, zone_start_pfn, size);
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);
}
memmap_init(size, nid, j, zone_start_pfn); memmap_init(size, nid, j, zone_start_pfn);
} }
} }
...@@ -7951,7 +7928,7 @@ void free_contig_range(unsigned long pfn, unsigned nr_pages) ...@@ -7951,7 +7928,7 @@ void free_contig_range(unsigned long pfn, unsigned nr_pages)
} }
#endif #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 * The zone indicated has a new number of managed_pages; batch sizes and percpu
* page high values need to be recalulated. * page high values need to be recalulated.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment