]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
UBUNTU: SAUCE: mm: fix memory hotplug in ZONE_HIGHMEM
authorSeth Forshee <seth.forshee@canonical.com>
Mon, 4 Dec 2017 13:14:41 +0000 (07:14 -0600)
committerSeth Forshee <seth.forshee@canonical.com>
Mon, 29 Jan 2018 13:45:00 +0000 (07:45 -0600)
BugLink: http://bugs.launchpad.net/bugs/1732463
Prior to f1dd2cd13c4b "mm, memory_hotplug: do not associate
hotadded memory to zones until online" 32-bit x86 with
CONFIG_HIGHMEM=y would default to ZONE_HIGHMEM for hotplugged
memory. That commit changed this to ZONE_NORMAL and made it
impossible for hotplugged memory to be added to ZONE_HIGHMEM,
resulting in oopses whenever the kernel tries to use hotplugged
memory that should have been placed in ZONE_HIGHMEM.

This has been reported upstream, but as a temporary fix make the
following changes:

 - If CONFIG_HIGHMEM=y, also look in ZONE_HIGHMEM when searching
   for a matching zone for memory being onlined.

 - Allow the arch to specify the default zone to be used if no
   matching zone is found.

 - Change 32-bit x86 to set the default zone to ZONE_HIGHMEM if
   CONFIG_HIGHMEM=y.

Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
arch/x86/mm/init_32.c
include/linux/memory_hotplug.h
mm/memory_hotplug.c

index 135c9a7898c7da908f1340f9750774b4327e63b3..d247f3c43c84ce0e7481594d174b4fbcc6a2db74 100644 (file)
@@ -758,6 +758,9 @@ void __init mem_init(void)
         * important here.
         */
        set_highmem_pages_init();
+#ifdef CONFIG_HIGHMEM
+       set_default_mem_hotplug_zone(ZONE_HIGHMEM);
+#endif
 
        /* this will put all low memory onto the freelists */
        free_all_bootmem();
index 58e110aee7ab4d68a954ad850fd626d71ed28b55..21cbde4af0db544292c81c71113a4033250c4044 100644 (file)
@@ -231,6 +231,8 @@ void put_online_mems(void);
 void mem_hotplug_begin(void);
 void mem_hotplug_done(void);
 
+void set_default_mem_hotplug_zone(enum zone_type zone);
+
 extern void set_zone_contiguous(struct zone *zone);
 extern void clear_zone_contiguous(struct zone *zone);
 
@@ -284,6 +286,8 @@ static inline void put_online_mems(void) {}
 static inline void mem_hotplug_begin(void) {}
 static inline void mem_hotplug_done(void) {}
 
+static inline void set_default_mem_hotplug_zone(enum zone_type zone) {}
+
 static inline bool movable_node_is_enabled(void)
 {
        return false;
index c52aa05b106c76dd5b469bc66e0227348d7524e5..d397bacc14fdd57ccbf4afa2b13696ac18ba9856 100644 (file)
@@ -54,6 +54,8 @@ static DEFINE_MUTEX(online_page_callback_lock);
 
 DEFINE_STATIC_PERCPU_RWSEM(mem_hotplug_lock);
 
+static int default_kernel_zone = ZONE_NORMAL;
+
 void get_online_mems(void)
 {
        percpu_down_read(&mem_hotplug_lock);
@@ -833,10 +835,21 @@ void __ref move_pfn_range_to_zone(struct zone *zone,
        set_zone_contiguous(zone);
 }
 
+void set_default_mem_hotplug_zone(enum zone_type zone)
+{
+       default_kernel_zone = zone;
+}
+
+#ifdef CONFIG_HIGHMEM
+#define MAX_KERNEL_ZONE ZONE_HIGHMEM
+#else
+#define MAX_KERNEL_ZONE ZONE_NORMAL
+#endif
+
 /*
  * Returns a default kernel memory zone for the given pfn range.
  * If no kernel zone covers this pfn range it will automatically go
- * to the ZONE_NORMAL.
+ * to the MAX_KERNEL_ZONE.
  */
 static struct zone *default_kernel_zone_for_pfn(int nid, unsigned long start_pfn,
                unsigned long nr_pages)
@@ -844,14 +857,14 @@ static struct zone *default_kernel_zone_for_pfn(int nid, unsigned long start_pfn
        struct pglist_data *pgdat = NODE_DATA(nid);
        int zid;
 
-       for (zid = 0; zid <= ZONE_NORMAL; zid++) {
+       for (zid = 0; zid <= MAX_KERNEL_ZONE; zid++) {
                struct zone *zone = &pgdat->node_zones[zid];
 
                if (zone_intersects(zone, start_pfn, nr_pages))
                        return zone;
        }
 
-       return &pgdat->node_zones[ZONE_NORMAL];
+       return &pgdat->node_zones[default_kernel_zone];
 }
 
 static inline struct zone *default_zone_for_pfn(int nid, unsigned long start_pfn,