Subject: Re: [PATCH 1/2] mm/memory_hotplug: allow marking of memory sections as hotpluggable

From: Mike Rapoport <[email-masked]>
Date: Sat, 17 Oct 2020 11:26:00 +0300

On Fri, Oct 16, 2020 at 07:02:23PM -0700, Sudarshan Rajagopalan wrote:
> Certain architectures such as arm64 doesn't allow boot memory to be
> offlined and removed. Distinguish certain memory sections as
> "hotpluggable" which can be marked by module drivers stating to memory
> hotplug layer that these sections can be offlined and then removed.

I don't quite follow why marking sections as hotpluggable or not should
be done by a device driver. Can you describe in more details your
use-case and why there is a need to add a flag to the memory map?

> This is done by using a separate section memory mab bit and setting it,
> rather than clearing the existing SECTION_IS_EARLY bit.
> This patch introduces SECTION_MARK_HOTPLUGGABLE bit into section mem map.
> Only the allowed sections which are in movable zone and have unmovable
> pages are allowed to be set with this new bit.
> 
> Signed-off-by: Sudarshan Rajagopalan <[email-masked]>
> Cc: Catalin Marinas <[email-masked]>
> Cc: Will Deacon <[email-masked]>
> Cc: Mike Rapoport <[email-masked]>
> Cc: Anshuman Khandual <[email-masked]>
> Cc: David Hildenbrand <[email-masked]>
> Cc: Mark Rutland <[email-masked]>
> Cc: Steven Price <[email-masked]>
> Cc: Logan Gunthorpe <[email-masked]>
> Cc: Suren Baghdasaryan <[email-masked]>
> ---
>  include/linux/memory_hotplug.h |  1 +
>  include/linux/mmzone.h         |  9 ++++++++-
>  mm/memory_hotplug.c            | 20 ++++++++++++++++++++
>  mm/sparse.c                    | 31 +++++++++++++++++++++++++++++++
>  4 files changed, 60 insertions(+), 1 deletion(-)
> 
> diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h
> index 375515803cd8..81df45b582c8 100644
> --- a/include/linux/memory_hotplug.h
> +++ b/include/linux/memory_hotplug.h
> @@ -319,6 +319,7 @@ extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages);
>  extern int remove_memory(int nid, u64 start, u64 size);
>  extern void __remove_memory(int nid, u64 start, u64 size);
>  extern int offline_and_remove_memory(int nid, u64 start, u64 size);
> +extern int mark_memory_hotpluggable(unsigned long start, unsigned long end);
>  
>  #else
>  static inline void try_offline_node(int nid) {}
> diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
> index 8379432f4f2f..3df3a4975236 100644
> --- a/include/linux/mmzone.h
> +++ b/include/linux/mmzone.h
> @@ -1247,7 +1247,8 @@ extern size_t mem_section_usage_size(void);
>  #define SECTION_HAS_MEM_MAP	(1UL<<1)
>  #define SECTION_IS_ONLINE	(1UL<<2)
>  #define SECTION_IS_EARLY	(1UL<<3)
> -#define SECTION_MAP_LAST_BIT	(1UL<<4)
> +#define SECTION_MARK_HOTPLUGGABLE	(1UL<<4)
> +#define SECTION_MAP_LAST_BIT	(1UL<<5)
>  #define SECTION_MAP_MASK	(~(SECTION_MAP_LAST_BIT-1))
>  #define SECTION_NID_SHIFT	3
>  
> @@ -1278,6 +1279,11 @@ static inline int early_section(struct mem_section *section)
>  	return (section && (section->section_mem_map & SECTION_IS_EARLY));
>  }
>  
> +static inline int removable_section(struct mem_section *section)
> +{
> +	return (section && (section->section_mem_map & SECTION_MARK_HOTPLUGGABLE));
> +}
> +
>  static inline int valid_section_nr(unsigned long nr)
>  {
>  	return valid_section(__nr_to_section(nr));
> @@ -1297,6 +1303,7 @@ static inline int online_section_nr(unsigned long nr)
>  void online_mem_sections(unsigned long start_pfn, unsigned long end_pfn);
>  #ifdef CONFIG_MEMORY_HOTREMOVE
>  void offline_mem_sections(unsigned long start_pfn, unsigned long end_pfn);
> +int section_mark_hotpluggable(struct mem_section *ms);
>  #endif
>  #endif
>  
> diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
> index e9d5ab5d3ca0..503b0de489a0 100644
> --- a/mm/memory_hotplug.c
> +++ b/mm/memory_hotplug.c
> @@ -1860,4 +1860,24 @@ int offline_and_remove_memory(int nid, u64 start, u64 size)
>  	return rc;
>  }
>  EXPORT_SYMBOL_GPL(offline_and_remove_memory);
> +
> +int mark_memory_hotpluggable(unsigned long start_pfn, unsigned long end_pfn)
> +{
> +	struct mem_section *ms;
> +	unsigned long nr;
> +	int rc = -EINVAL;
> +
> +	if (end_pfn < start_pfn)
> +		return rc;
> +
> +	for (nr = start_pfn; nr <= end_pfn; nr++) {
> +		ms = __pfn_to_section(nr);
> +		rc = section_mark_hotpluggable(ms);
> +		if (!rc)
> +			break;
> +	}
> +
> +	return rc;
> +}
> +EXPORT_SYMBOL_GPL(mark_memory_hotpluggable);
>  #endif /* CONFIG_MEMORY_HOTREMOVE */
> diff --git a/mm/sparse.c b/mm/sparse.c
> index fcc3d176f1ea..cc21c23e2f1d 100644
> --- a/mm/sparse.c
> +++ b/mm/sparse.c
> @@ -13,6 +13,7 @@
>  #include <linux/vmalloc.h>
>  #include <linux/swap.h>
>  #include <linux/swapops.h>
> +#include <linux/page-isolation.h>
>  
>  #include "internal.h"
>  #include <asm/dma.h>
> @@ -644,6 +645,36 @@ void offline_mem_sections(unsigned long start_pfn, unsigned long end_pfn)
>  		ms->section_mem_map &= ~SECTION_IS_ONLINE;
>  	}
>  }
> +
> +int section_mark_hotpluggable(struct mem_section *ms)
> +{
> +	unsigned long section_nr, pfn;
> +	bool unmovable;
> +	struct page *page;
> +
> +	/* section needs to be both valid and present to be marked */
> +	if (WARN_ON(!valid_section(ms)) || !present_section(ms))
> +		return -EINVAL;
> +
> +	/*
> +	 * now check if this section is removable. This can be done by checking
> +	 * if section has unmovable pages or not.
> +	 */
> +	section_nr = __section_nr(ms);
> +	pfn = section_nr_to_pfn(section_nr);
> +	page = pfn_to_page(pfn);
> +	unmovable = has_unmovable_pages(page_zone(page), page,
> +					MIGRATE_MOVABLE, MEMORY_OFFLINE | REPORT_FAILURE);
> +	if (unmovable) {
> +		pr_info("section %lu has unmovable pages. Cannot be marked as hotpluggable\n");
> +		return -EINVAL;
> +	}
> +
> +	/* all good! mark section as hotpluggable */
> +	ms->section_mem_map |= SECTION_MARK_HOTPLUGGABLE;
> +
> +	return 0;
> +}
>  #endif
>  
>  #ifdef CONFIG_SPARSEMEM_VMEMMAP
> -- 
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
> a Linux Foundation Collaborative Project
> 

-- 
Sincerely yours,
Mike.

_______________________________________________
linux-arm-kernel mailing list
[email-masked]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel