未验证 提交 50281a29 编写于 作者: O openeuler-ci-bot 提交者: Gitee

!1220 mm/memory_hotplug: extend offline_and_remove_memory() to handle more than one memory block

Merge Pull Request from: @ci-robot 
 
PR sync from: Wupeng Ma <mawupeng1@huawei.com>
https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/HO6QXFWOBWOT6QFQ3P5VMHCBDUJXVKCI/ 
 
 
Link:https://gitee.com/openeuler/kernel/pulls/1220 

Reviewed-by: Kefeng Wang <wangkefeng.wang@huawei.com> 
Signed-off-by: Jialin Zhang <zhangjialin11@huawei.com> 
...@@ -1675,39 +1675,112 @@ int remove_memory(int nid, u64 start, u64 size) ...@@ -1675,39 +1675,112 @@ int remove_memory(int nid, u64 start, u64 size)
} }
EXPORT_SYMBOL_GPL(remove_memory); EXPORT_SYMBOL_GPL(remove_memory);
static int try_offline_memory_block(struct memory_block *mem, void *arg)
{
uint8_t online_type = MMOP_ONLINE_KERNEL;
uint8_t **online_types = arg;
struct page *page;
int rc;
/*
* Sense the online_type via the zone of the memory block. Offlining
* with multiple zones within one memory block will be rejected
* by offlining code ... so we don't care about that.
*/
page = pfn_to_online_page(section_nr_to_pfn(mem->start_section_nr));
if (page && zone_idx(page_zone(page)) == ZONE_MOVABLE)
online_type = MMOP_ONLINE_MOVABLE;
rc = device_offline(&mem->dev);
/*
* Default is MMOP_OFFLINE - change it only if offlining succeeded,
* so try_reonline_memory_block() can do the right thing.
*/
if (!rc)
**online_types = online_type;
(*online_types)++;
/* Ignore if already offline. */
return rc < 0 ? rc : 0;
}
static int try_reonline_memory_block(struct memory_block *mem, void *arg)
{
uint8_t **online_types = arg;
int rc;
if (**online_types != MMOP_OFFLINE) {
mem->online_type = **online_types;
rc = device_online(&mem->dev);
if (rc < 0)
pr_warn("%s: Failed to re-online memory: %d",
__func__, rc);
}
/* Continue processing all remaining memory blocks. */
(*online_types)++;
return 0;
}
/* /*
* Try to offline and remove a memory block. Might take a long time to * Try to offline and remove memory. Might take a long time to finish in case
* finish in case memory is still in use. Primarily useful for memory devices * memory is still in use. Primarily useful for memory devices that logically
* that logically unplugged all memory (so it's no longer in use) and want to * unplugged all memory (so it's no longer in use) and want to offline + remove
* offline + remove the memory block. * that memory.
*/ */
int offline_and_remove_memory(int nid, u64 start, u64 size) int offline_and_remove_memory(int nid, u64 start, u64 size)
{ {
struct memory_block *mem; const unsigned long mb_count = size / memory_block_size_bytes();
int rc = -EINVAL; uint8_t *online_types, *tmp;
int rc;
if (!IS_ALIGNED(start, memory_block_size_bytes()) || if (!IS_ALIGNED(start, memory_block_size_bytes()) ||
size != memory_block_size_bytes()) !IS_ALIGNED(size, memory_block_size_bytes()) || !size)
return rc; return -EINVAL;
/*
* We'll remember the old online type of each memory block, so we can
* try to revert whatever we did when offlining one memory block fails
* after offlining some others succeeded.
*/
online_types = kmalloc_array(mb_count, sizeof(*online_types),
GFP_KERNEL);
if (!online_types)
return -ENOMEM;
/*
* Initialize all states to MMOP_OFFLINE, so when we abort processing in
* try_offline_memory_block(), we'll skip all unprocessed blocks in
* try_reonline_memory_block().
*/
memset(online_types, MMOP_OFFLINE, mb_count);
lock_device_hotplug(); lock_device_hotplug();
mem = find_memory_block(__pfn_to_section(PFN_DOWN(start)));
if (mem) tmp = online_types;
rc = device_offline(&mem->dev); rc = walk_memory_blocks(start, size, &tmp, try_offline_memory_block);
/* Ignore if the device is already offline. */
if (rc > 0)
rc = 0;
/* /*
* In case we succeeded to offline the memory block, remove it. * In case we succeeded to offline all memory, remove it.
* This cannot fail as it cannot get onlined in the meantime. * This cannot fail as it cannot get onlined in the meantime.
*/ */
if (!rc) { if (!rc) {
rc = try_remove_memory(nid, start, size); rc = try_remove_memory(nid, start, size);
WARN_ON_ONCE(rc); if (rc)
pr_err("%s: Failed to remove memory: %d", __func__, rc);
}
/*
* Rollback what we did. While memory onlining might theoretically fail
* (nacked by a notifier), it barely ever happens.
*/
if (rc) {
tmp = online_types;
walk_memory_blocks(start, size, &tmp,
try_reonline_memory_block);
} }
unlock_device_hotplug(); unlock_device_hotplug();
kfree(online_types);
return rc; return rc;
} }
EXPORT_SYMBOL_GPL(offline_and_remove_memory); EXPORT_SYMBOL_GPL(offline_and_remove_memory);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册