The patch titled Subject: mm/memory_hotplug.c: refactor unregister_mem_sect_under_nodes has been added to the -mm tree. Its filename is mm-memory_hotplug-refactor-unregister_mem_sect_under_nodes.patch This patch should soon appear at http://ozlabs.org/~akpm/mmots/broken-out/mm-memory_hotplug-refactor-unregister_mem_sect_under_nodes.patch and later at http://ozlabs.org/~akpm/mmotm/broken-out/mm-memory_hotplug-refactor-unregister_mem_sect_under_nodes.patch Before you just go and hit "reply", please: a) Consider who else should be cc'ed b) Prefer to cc a suitable mailing list as well c) Ideally: find the original patch on the mailing list and do a reply-to-all to that, adding suitable additional cc's *** Remember to use Documentation/process/submit-checklist.rst when testing your code *** The -mm tree is included into linux-next and is updated there every 3-4 working days ------------------------------------------------------ From: Oscar Salvador <osalvador@xxxxxxx> Subject: mm/memory_hotplug.c: refactor unregister_mem_sect_under_nodes unregister_mem_sect_under_nodes() tries to allocate a nodemask_t in order to check within the loop which nodes have already been unlinked, so we do not repeat the operation on them. NODEMASK_ALLOC calls kmalloc() if NODES_SHIFT > 8, otherwise it just declares a nodemask_t variable whithin the stack. Since kmalloc() can fail, we actually check whether NODEMASK_ALLOC failed or not, and we return -ENOMEM accordingly. remove_memory_section() does not check for the return value though. The problem with this is that if we return -ENOMEM, it means that unregister_mem_sect_under_nodes will not be able to remove the symlinks, but since we do not check the return value, we go ahead and we call unregister_memory(), which will remove all the mem_blks directories. This will leave us with dangled symlinks. The easiest way to overcome this is to fallback by calling sysfs_remove_link() unconditionally in case NODEMASK_ALLOC failed. This means that we will call sysfs_remove_link on nodes that have been already unlinked, but nothing wrong happens as sysfs_remove_link() backs off somewhere down the chain in case the link has already been removed. I think that this is better than a) dangled symlinks b) having to recovery from such error in remove_memory_section Since from now on we will not need to care about return values, we can make the function void. As we have a safe fallback, one thing that could also be done is to add __GFP_NORETRY in the flags when calling NODEMASK_ALLOC, so we do not retry. Link: http://lkml.kernel.org/r/20180815144219.6014-4-osalvador@xxxxxxxxxxxxxxxxxx Signed-off-by: Oscar Salvador <osalvador@xxxxxxx> Cc: Dan Williams <dan.j.williams@xxxxxxxxx> Cc: David Hildenbrand <david@xxxxxxxxxx> Cc: Jonathan Cameron <jonathan.cameron@xxxxxxxxxx> Cc: Michal Hocko <mhocko@xxxxxxxx> Cc: Vlastimil Babka <vbabka@xxxxxxx> Cc: <yasu.isimatu@xxxxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> --- drivers/base/node.c | 23 +++++++++++++++-------- include/linux/node.h | 5 ++--- 2 files changed, 17 insertions(+), 11 deletions(-) --- a/drivers/base/node.c~mm-memory_hotplug-refactor-unregister_mem_sect_under_nodes +++ a/drivers/base/node.c @@ -449,35 +449,42 @@ int register_mem_sect_under_node(struct } /* unregister memory section under all nodes that it spans */ -int unregister_mem_sect_under_nodes(struct memory_block *mem_blk, +void unregister_mem_sect_under_nodes(struct memory_block *mem_blk, unsigned long phys_index) { NODEMASK_ALLOC(nodemask_t, unlinked_nodes, GFP_KERNEL); unsigned long pfn, sect_start_pfn, sect_end_pfn; - if (!unlinked_nodes) - return -ENOMEM; - nodes_clear(*unlinked_nodes); + if (unlinked_nodes) + nodes_clear(*unlinked_nodes); sect_start_pfn = section_nr_to_pfn(phys_index); sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1; for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) { - int nid; + int nid = get_nid_for_pfn(pfn); - nid = get_nid_for_pfn(pfn); if (nid < 0) continue; if (!node_online(nid)) continue; - if (node_test_and_set(nid, *unlinked_nodes)) + /* + * It is possible that NODEMASK_ALLOC fails due to memory + * pressure. + * If that happens, we fallback to call sysfs_remove_link + * unconditionally. + * Nothing wrong will happen as sysfs_remove_link will back off + * somewhere down the chain in case the link has already been + * removed. + */ + if (unlinked_nodes && node_test_and_set(nid, *unlinked_nodes)) continue; + sysfs_remove_link(&node_devices[nid]->dev.kobj, kobject_name(&mem_blk->dev.kobj)); sysfs_remove_link(&mem_blk->dev.kobj, kobject_name(&node_devices[nid]->dev.kobj)); } NODEMASK_FREE(unlinked_nodes); - return 0; } int link_mem_sections(int nid, unsigned long start_pfn, unsigned long end_pfn) --- a/include/linux/node.h~mm-memory_hotplug-refactor-unregister_mem_sect_under_nodes +++ a/include/linux/node.h @@ -72,7 +72,7 @@ extern int register_cpu_under_node(unsig extern int unregister_cpu_under_node(unsigned int cpu, unsigned int nid); extern int register_mem_sect_under_node(struct memory_block *mem_blk, void *arg); -extern int unregister_mem_sect_under_nodes(struct memory_block *mem_blk, +extern void unregister_mem_sect_under_nodes(struct memory_block *mem_blk, unsigned long phys_index); #ifdef CONFIG_HUGETLBFS @@ -105,10 +105,9 @@ static inline int register_mem_sect_unde { return 0; } -static inline int unregister_mem_sect_under_nodes(struct memory_block *mem_blk, +static inline void unregister_mem_sect_under_nodes(struct memory_block *mem_blk, unsigned long phys_index) { - return 0; } static inline void register_hugetlbfs_with_node(node_registration_func_t reg, _ Patches currently in -mm which might be from osalvador@xxxxxxx are mm-memory_hotplug-make-add_memory_resource-use-__try_online_node.patch mm-memory_hotplug-call-register_mem_sect_under_node.patch mm-memory_hotplug-make-register_mem_sect_under_node-a-cb-of-walk_memory_range.patch mm-memory_hotplug-drop-unnecessary-checks-from-register_mem_sect_under_node.patch mm-sparse-make-sparse_init_one_section-void-and-remove-check.patch mm-remove-zone_id-and-make-use-of-zone_idx-in-is_dev_zone.patch mm-page_alloc-move-ifdefery-out-of-free_area_init_core.patch mm-page_alloc-inline-function-to-handle-config_deferred_struct_page_init.patch mm-page_alloc-introduce-free_area_init_core_hotplug.patch mm-page_alloc-introduce-free_area_init_core_hotplug-v6.patch mm-memory_hotplug-drop-unused-args-from-remove_memory_section.patch mm-memory_hotplug-drop-unneeded-check-from-unregister_mem_sect_under_nodes.patch mm-memory_hotplug-refactor-unregister_mem_sect_under_nodes.patch mm-memory_hotplug-drop-node_online-check-in-unregister_mem_sect_under_nodes.patch