]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - mm/cma.c
Merge tag 'media/v4.17-4' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[linux.git] / mm / cma.c
index 5809bbe360d7fb724a435309e6e693a98f9efbfb..aa40e6c7b042e95f5fb30a24cb05014c55ce9152 100644 (file)
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -39,6 +39,7 @@
 #include <trace/events/cma.h>
 
 #include "cma.h"
+#include "internal.h"
 
 struct cma cma_areas[MAX_CMA_AREAS];
 unsigned cma_area_count;
@@ -109,23 +110,25 @@ 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++) {
-                       WARN_ON_ONCE(!pfn_valid(pfn));
+                       if (!pfn_valid(pfn))
+                               goto err;
+
                        /*
-                        * 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.
+                        * In init_cma_reserved_pageblock(), present_pages
+                        * is adjusted with assumption that all pages in
+                        * the pageblock come from a single zone.
                         */
                        if (page_zone(pfn_to_page(pfn)) != zone)
-                               goto not_in_zone;
+                               goto err;
                }
                init_cma_reserved_pageblock(pfn_to_page(base_pfn));
        } while (--i);
@@ -139,7 +142,7 @@ static int __init cma_activate_area(struct cma *cma)
 
        return 0;
 
-not_in_zone:
+err:
        pr_err("CMA area %s could not be activated\n", cma->name);
        kfree(cma->bitmap);
        cma->count = 0;
@@ -149,6 +152,41 @@ static int __init cma_activate_area(struct cma *cma)
 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]);
@@ -157,9 +195,32 @@ 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;
 }
-core_initcall(cma_init_reserved_areas);
+pure_initcall(cma_init_reserved_areas);
 
 /**
  * cma_init_reserved_mem() - create custom contiguous area from reserved memory