From c5d41d116208522809ea391c3d89203d4470bc4c Mon Sep 17 00:00:00 2001 From: Liam Mark Date: Wed, 23 May 2018 10:56:12 -0700 Subject: [PATCH] mm, oom: Try to online memory block before killing Before killing a process first try to see if there are any offlined memory blocks, if there are try to online one of them. Change-Id: Ie97c8b69f0ba173c202a891a38a5c914869ddaae Signed-off-by: Liam Mark [isaacm@codeaurora.org: Update walk_memory_range to walk_memory_blocks] Signed-off-by: Isaac J. Manjarres --- include/linux/memory_hotplug.h | 6 ++++++ mm/memory_hotplug.c | 34 ++++++++++++++++++++++++++++++++++ mm/oom_kill.c | 7 +++++++ 3 files changed, 47 insertions(+) diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h index f46ea71b4ffd..fc1819b467b3 100644 --- a/include/linux/memory_hotplug.h +++ b/include/linux/memory_hotplug.h @@ -110,6 +110,7 @@ extern void __online_page_increment_counters(struct page *page); extern void __online_page_free(struct page *page); extern int try_online_node(int nid); +extern bool try_online_one_block(int nid); extern int arch_add_memory(int nid, u64 start, u64 size, struct mhp_restrictions *restrictions); @@ -269,6 +270,11 @@ static inline int try_online_node(int nid) return 0; } +static inline bool try_online_one_block(int nid) +{ + return false; +} + static inline void get_online_mems(void) {} static inline void put_online_mems(void) {} diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 3b287f3ba11c..fadddfdc6f9c 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -999,6 +999,40 @@ int try_online_node(int nid) return ret; } +static int online_memory_one_block(struct memory_block *mem, void *arg) +{ + bool *onlined_block = (bool *)arg; + int ret; + + if (*onlined_block || !is_memblock_offlined(mem)) + return 0; + + ret = device_online(&mem->dev); + if (!ret) + *onlined_block = true; + + return 0; +} + +bool try_online_one_block(int nid) +{ + struct zone *zone = &NODE_DATA(nid)->node_zones[ZONE_MOVABLE]; + unsigned long zone_start, zone_size; + bool onlined_block = false; + int ret = lock_device_hotplug_sysfs(); + + if (ret) + return false; + + zone_start = PFN_PHYS(zone->zone_start_pfn); + zone_size = zone->spanned_pages << PAGE_SHIFT; + walk_memory_blocks(zone_start, zone_size, &onlined_block, + online_memory_one_block); + + unlock_device_hotplug(); + return onlined_block; +} + static int check_hotplug_memory_range(u64 start, u64 size) { /* memory range must be block size aligned */ diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 6993791a517b..087e0c1b2fdf 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include "internal.h" @@ -1066,6 +1067,12 @@ bool out_of_memory(struct oom_control *oc) if (oom_killer_disabled) return false; + if (try_online_one_block(numa_node_id())) { + /* Got some memory back */ + WARN(1, "OOM killer had to online a memory block\n"); + return true; + } + if (!is_memcg_oom(oc)) { blocking_notifier_call_chain(&oom_notify_list, 0, &freed); if (freed > 0)