hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/ID4X9G ---------------------------------------- During memory preonline, add_memory_resource() iterates all memory blocks to preonline. However, the result isn't returned to caller. So some memory blocks may be offlined in numa_remote_undo_fake_online(). Skip it if there exists offlined memory block. Fixes: 8e27b94c109c ("mm/numa_remote: introduce pre-online mode to support hotplug unready memory") Signed-off-by: Jinjiang Tu <tujinjiang@huawei.com> --- drivers/base/memory.c | 8 ++++++++ drivers/base/numa_remote.c | 7 ++++++- include/linux/memory.h | 1 + 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 2d6ba0b423e4..32a7bbc00599 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -936,6 +936,7 @@ void remove_memory_block_devices(unsigned long start, unsigned long size) enum check_state_type { CHECK_NID, CHECK_PREONLINE, + CHECK_ONLINE, }; static inline bool check_memory_block_state(unsigned long start, unsigned long size, @@ -956,6 +957,8 @@ static inline bool check_memory_block_state(unsigned long start, unsigned long s check_res = (mem->nid == check_val); else if (type == CHECK_PREONLINE) check_res = (mem->pre_online == check_val); + else if (type == CHECK_ONLINE) + check_res = (mem->state == check_val); put_device(&mem->dev); if (!check_res) return false; @@ -974,6 +977,11 @@ bool check_memory_block_pre_online(unsigned long start, unsigned long size, return check_memory_block_state(start, size, CHECK_PREONLINE, pre_online); } +bool check_memory_block_online(unsigned long start, unsigned long size) +{ + return check_memory_block_state(start, size, CHECK_ONLINE, MEM_ONLINE); +} + void set_memory_block_pre_online(unsigned long start, unsigned long size, bool pre_online) { diff --git a/drivers/base/numa_remote.c b/drivers/base/numa_remote.c index 0336c7c574bc..d31c5858977d 100644 --- a/drivers/base/numa_remote.c +++ b/drivers/base/numa_remote.c @@ -300,6 +300,11 @@ static int __ref numa_remote_undo_fake_online(u64 start, u64 size) goto out; } + if (!check_memory_block_online(start, size)) { + ret = -EINVAL; + goto out; + } + zone = page_zone(phys_to_page(start)); nid = zone_to_nid(zone); if (!check_memory_block_nid(start, size, nid)) { @@ -317,12 +322,12 @@ static int __ref numa_remote_undo_fake_online(u64 start, u64 size) atomic_long_add(-nr_pages, &pre_online_pages_node[nid]); atomic_long_add(-nr_pages, &pre_online_pages); numa_remote_online_pages(start_pfn, end_pfn); - atomic_long_add(-nr_pages, &undo_fake_online_pages_node[nid]); init_per_zone_wmark_min(); writeback_set_ratelimit(); out: + atomic_long_add(-nr_pages, &undo_fake_online_pages_node[nid]); mem_hotplug_done(); return ret; } diff --git a/include/linux/memory.h b/include/linux/memory.h index 9d7431ff1282..be51c078c497 100644 --- a/include/linux/memory.h +++ b/include/linux/memory.h @@ -155,6 +155,7 @@ bool check_memory_block_pre_online(unsigned long start, unsigned long size, bool pre_online); void set_memory_block_pre_online(unsigned long start, unsigned long size, bool pre_online); +bool check_memory_block_online(unsigned long start, unsigned long size); static inline bool memory_block_is_pre_online(struct memory_block *mem) { return mem->pre_online; -- 2.43.0