Re: [PATCH V2 1/3] mm/hotplug: Prevalidate the address range being added with platform

2021-01-12 Thread Anshuman Khandual



On 1/12/21 3:39 PM, David Hildenbrand wrote:
> On 12.01.21 04:51, Anshuman Khandual wrote:
>>
>>
>> On 1/11/21 7:13 PM, Oscar Salvador wrote:
>>> On Mon, Jan 11, 2021 at 11:51:47AM +0100, David Hildenbrand wrote:
 AFAIKs, all memhp_get_pluggable_range() users pass "1".

 What about the "add_pages()-only" path?
>>>
>>> I guess you refer to memremap_pages(), right?
>>
>> Right, via pagemap_range().
>>
>>> If so, moving the added memhp_range_allowed() check above the if-else might 
>>> do
>>> the trick
>>>
>> We had that code in the earlier version. But dropped it, as we did
>> not want to add any new checks in the generic code. Can add it back
>> if that is preferred.
> 
> I remember discussing replacing the check in __add_pages() instead. But

The proposed change for __add_pages() now seems misleading. Instead of
VM_BUG_ON(), memhp_range_allowed() should be checked directly for a non
linear mapping i.e with 'false' argument and return prematurely in case
that check fails.

s/VM_BUG_ON(!memhp_range_allowed(.., 1)/!memhp_range_allowed(.., 0)/

 /*
  * Reasonably generic function for adding memory.  It is
  * expected that archs that support memory hotplug will
@@ -317,10 +304,7 @@ int __ref __add_pages(int nid, unsigned long pfn, unsigned 
long nr_pages,
if (WARN_ON_ONCE(!params->pgprot.pgprot))
return -EINVAL;
 
-   err = check_hotplug_memory_addressable(pfn, nr_pages);
-   if (err)
-   return err;
-
+   VM_BUG_ON(!memhp_range_allowed(PFN_PHYS(pfn), nr_pages * PAGE_SIZE, 1));
if (altmap) {
/*
 * Validate altmap is within bounds of the total request
@@ -1181,6 +1165,61 @@ int add_memory_driver_managed(int nid, u64 start, u64 
size,


> I don't really care where the check ends up being. As discussed, at some
> point, we should provide versions of add_pages() and arch_add_pages()
> that don't immediately end in arch-code.

Sure. But for now, AFAICS the above replacement should be sufficient.


Re: [PATCH V2 1/3] mm/hotplug: Prevalidate the address range being added with platform

2021-01-12 Thread David Hildenbrand
On 12.01.21 04:51, Anshuman Khandual wrote:
> 
> 
> On 1/11/21 7:13 PM, Oscar Salvador wrote:
>> On Mon, Jan 11, 2021 at 11:51:47AM +0100, David Hildenbrand wrote:
>>> AFAIKs, all memhp_get_pluggable_range() users pass "1".
>>>
>>> What about the "add_pages()-only" path?
>>
>> I guess you refer to memremap_pages(), right?
> 
> Right, via pagemap_range().
> 
>> If so, moving the added memhp_range_allowed() check above the if-else might 
>> do
>> the trick
>>
> We had that code in the earlier version. But dropped it, as we did
> not want to add any new checks in the generic code. Can add it back
> if that is preferred.

I remember discussing replacing the check in __add_pages() instead. But
I don't really care where the check ends up being. As discussed, at some
point, we should provide versions of add_pages() and arch_add_pages()
that don't immediately end in arch-code.

-- 
Thanks,

David / dhildenb



Re: [PATCH V2 1/3] mm/hotplug: Prevalidate the address range being added with platform

2021-01-11 Thread Anshuman Khandual



On 1/11/21 7:13 PM, Oscar Salvador wrote:
> On Mon, Jan 11, 2021 at 11:51:47AM +0100, David Hildenbrand wrote:
>> AFAIKs, all memhp_get_pluggable_range() users pass "1".
>>
>> What about the "add_pages()-only" path?
> 
> I guess you refer to memremap_pages(), right?

Right, via pagemap_range().

> If so, moving the added memhp_range_allowed() check above the if-else might do
> the trick
> 
We had that code in the earlier version. But dropped it, as we did
not want to add any new checks in the generic code. Can add it back
if that is preferred.


Re: [PATCH V2 1/3] mm/hotplug: Prevalidate the address range being added with platform

2021-01-11 Thread Anshuman Khandual



On 1/11/21 4:21 PM, David Hildenbrand wrote:
> On 17.12.20 16:28, Anshuman Khandual wrote:
>> This introduces memhp_range_allowed() which can be called in various memory
>> hotplug paths to prevalidate the address range which is being added, with
>> the platform. Then memhp_range_allowed() calls memhp_get_pluggable_range()
>> which provides applicable address range depending on whether linear mapping
>> is required or not. For ranges that require linear mapping, it calls a new
>> arch callback arch_get_mappable_range() which the platform can override. So
>> the new callback, in turn provides the platform an opportunity to configure
>> acceptable memory hotplug address ranges in case there are constraints.
>>
>> This mechanism will help prevent platform specific errors deep down during
>> hotplug calls. This drops now redundant check_hotplug_memory_addressable()
>> check in __add_pages() but instead adds a VM_BUG_ON() check which would
>> ensure that the range has been validated with memhp_range_allowed() earlier
>> in the call chain. Besides memhp_get_pluggable_range() also can be used by
>> potential memory hotplug callers to avail the allowed physical range which
>> would go through on a given platform.
>>
>> This does not really add any new range check in generic memory hotplug but
>> instead compensates for lost checks in arch_add_memory() where applicable
>> and check_hotplug_memory_addressable(), with unified memhp_range_allowed().
>>
> 
> Subject s/mm\/hotplug/mm\/memory_hotplug/

Sure, will do.

> 
> Everywhere in this patch: Use "true/false" for boolean values.

Sure, will change.

> 
>> Cc: David Hildenbrand 
>> Cc: Andrew Morton 
>> Cc: linux...@kvack.org
>> Cc: linux-kernel@vger.kernel.org
>> Suggested-by: David Hildenbrand 
>> Signed-off-by: Anshuman Khandual 
>> ---
>>  include/linux/memory_hotplug.h | 10 +
>>  mm/memory_hotplug.c| 79 +-
>>  mm/memremap.c  |  6 +++
>>  3 files changed, 75 insertions(+), 20 deletions(-)
>>
>> diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h
>> index 551093b74596..8d72354758c8 100644
>> --- a/include/linux/memory_hotplug.h
>> +++ b/include/linux/memory_hotplug.h
>> @@ -70,6 +70,9 @@ typedef int __bitwise mhp_t;
>>   */
>>  #define MEMHP_MERGE_RESOURCE((__force mhp_t)BIT(0))
>>  
>> +bool memhp_range_allowed(u64 start, u64 size, bool need_mapping);
>> +struct range memhp_get_pluggable_range(bool need_mapping);
> 
> AFAIKs, all memhp_get_pluggable_range() users pass "1".

Right.

> 
> What about the "add_pages()-only" path?

I had dropped memhp_range_allowed() changes for add_pages() in pagemap_range()
because you had mentioned not to add any new checks in the generic code. Will
add it back if that is preferred.


Re: [PATCH V2 1/3] mm/hotplug: Prevalidate the address range being added with platform

2021-01-11 Thread Oscar Salvador
On Mon, Jan 11, 2021 at 11:51:47AM +0100, David Hildenbrand wrote:
> AFAIKs, all memhp_get_pluggable_range() users pass "1".
> 
> What about the "add_pages()-only" path?

I guess you refer to memremap_pages(), right?
If so, moving the added memhp_range_allowed() check above the if-else might do
the trick

-- 
Oscar Salvador
SUSE L3


Re: [PATCH V2 1/3] mm/hotplug: Prevalidate the address range being added with platform

2021-01-11 Thread David Hildenbrand
On 17.12.20 16:28, Anshuman Khandual wrote:
> This introduces memhp_range_allowed() which can be called in various memory
> hotplug paths to prevalidate the address range which is being added, with
> the platform. Then memhp_range_allowed() calls memhp_get_pluggable_range()
> which provides applicable address range depending on whether linear mapping
> is required or not. For ranges that require linear mapping, it calls a new
> arch callback arch_get_mappable_range() which the platform can override. So
> the new callback, in turn provides the platform an opportunity to configure
> acceptable memory hotplug address ranges in case there are constraints.
> 
> This mechanism will help prevent platform specific errors deep down during
> hotplug calls. This drops now redundant check_hotplug_memory_addressable()
> check in __add_pages() but instead adds a VM_BUG_ON() check which would
> ensure that the range has been validated with memhp_range_allowed() earlier
> in the call chain. Besides memhp_get_pluggable_range() also can be used by
> potential memory hotplug callers to avail the allowed physical range which
> would go through on a given platform.
> 
> This does not really add any new range check in generic memory hotplug but
> instead compensates for lost checks in arch_add_memory() where applicable
> and check_hotplug_memory_addressable(), with unified memhp_range_allowed().
> 

Subject s/mm\/hotplug/mm\/memory_hotplug/

Everywhere in this patch: Use "true/false" for boolean values.

> Cc: David Hildenbrand 
> Cc: Andrew Morton 
> Cc: linux...@kvack.org
> Cc: linux-kernel@vger.kernel.org
> Suggested-by: David Hildenbrand 
> Signed-off-by: Anshuman Khandual 
> ---
>  include/linux/memory_hotplug.h | 10 +
>  mm/memory_hotplug.c| 79 +-
>  mm/memremap.c  |  6 +++
>  3 files changed, 75 insertions(+), 20 deletions(-)
> 
> diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h
> index 551093b74596..8d72354758c8 100644
> --- a/include/linux/memory_hotplug.h
> +++ b/include/linux/memory_hotplug.h
> @@ -70,6 +70,9 @@ typedef int __bitwise mhp_t;
>   */
>  #define MEMHP_MERGE_RESOURCE ((__force mhp_t)BIT(0))
>  
> +bool memhp_range_allowed(u64 start, u64 size, bool need_mapping);
> +struct range memhp_get_pluggable_range(bool need_mapping);

AFAIKs, all memhp_get_pluggable_range() users pass "1".

What about the "add_pages()-only" path?

-- 
Thanks,

David / dhildenb



[PATCH V2 1/3] mm/hotplug: Prevalidate the address range being added with platform

2020-12-17 Thread Anshuman Khandual
This introduces memhp_range_allowed() which can be called in various memory
hotplug paths to prevalidate the address range which is being added, with
the platform. Then memhp_range_allowed() calls memhp_get_pluggable_range()
which provides applicable address range depending on whether linear mapping
is required or not. For ranges that require linear mapping, it calls a new
arch callback arch_get_mappable_range() which the platform can override. So
the new callback, in turn provides the platform an opportunity to configure
acceptable memory hotplug address ranges in case there are constraints.

This mechanism will help prevent platform specific errors deep down during
hotplug calls. This drops now redundant check_hotplug_memory_addressable()
check in __add_pages() but instead adds a VM_BUG_ON() check which would
ensure that the range has been validated with memhp_range_allowed() earlier
in the call chain. Besides memhp_get_pluggable_range() also can be used by
potential memory hotplug callers to avail the allowed physical range which
would go through on a given platform.

This does not really add any new range check in generic memory hotplug but
instead compensates for lost checks in arch_add_memory() where applicable
and check_hotplug_memory_addressable(), with unified memhp_range_allowed().

Cc: David Hildenbrand 
Cc: Andrew Morton 
Cc: linux...@kvack.org
Cc: linux-kernel@vger.kernel.org
Suggested-by: David Hildenbrand 
Signed-off-by: Anshuman Khandual 
---
 include/linux/memory_hotplug.h | 10 +
 mm/memory_hotplug.c| 79 +-
 mm/memremap.c  |  6 +++
 3 files changed, 75 insertions(+), 20 deletions(-)

diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h
index 551093b74596..8d72354758c8 100644
--- a/include/linux/memory_hotplug.h
+++ b/include/linux/memory_hotplug.h
@@ -70,6 +70,9 @@ typedef int __bitwise mhp_t;
  */
 #define MEMHP_MERGE_RESOURCE   ((__force mhp_t)BIT(0))
 
+bool memhp_range_allowed(u64 start, u64 size, bool need_mapping);
+struct range memhp_get_pluggable_range(bool need_mapping);
+
 /*
  * Extended parameters for memory hotplug:
  * altmap: alternative allocator for memmap array (optional)
@@ -281,6 +284,13 @@ static inline bool movable_node_is_enabled(void)
 }
 #endif /* ! CONFIG_MEMORY_HOTPLUG */
 
+/*
+ * Keep this declaration outside CONFIG_MEMORY_HOTPLUG as some
+ * platforms might override and use arch_get_mappable_range()
+ * for internal non memory hotplug purposes.
+ */
+struct range arch_get_mappable_range(void);
+
 #if defined(CONFIG_MEMORY_HOTPLUG) || defined(CONFIG_DEFERRED_STRUCT_PAGE_INIT)
 /*
  * pgdat resizing functions
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 63b2e46b6555..27ee352cbe31 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -107,6 +107,9 @@ static struct resource *register_memory_resource(u64 start, 
u64 size,
if (strcmp(resource_name, "System RAM"))
flags |= IORESOURCE_SYSRAM_DRIVER_MANAGED;
 
+   if (!memhp_range_allowed(start, size, 1))
+   return ERR_PTR(-E2BIG);
+
/*
 * Make sure value parsed from 'mem=' only restricts memory adding
 * while booting, so that memory hotplug won't be impacted. Please
@@ -284,22 +287,6 @@ static int check_pfn_span(unsigned long pfn, unsigned long 
nr_pages,
return 0;
 }
 
-static int check_hotplug_memory_addressable(unsigned long pfn,
-   unsigned long nr_pages)
-{
-   const u64 max_addr = PFN_PHYS(pfn + nr_pages) - 1;
-
-   if (max_addr >> MAX_PHYSMEM_BITS) {
-   const u64 max_allowed = (1ull << (MAX_PHYSMEM_BITS + 1)) - 1;
-   WARN(1,
-"Hotplugged memory exceeds maximum addressable address, 
range=%#llx-%#llx, maximum=%#llx\n",
-(u64)PFN_PHYS(pfn), max_addr, max_allowed);
-   return -E2BIG;
-   }
-
-   return 0;
-}
-
 /*
  * Reasonably generic function for adding memory.  It is
  * expected that archs that support memory hotplug will
@@ -317,10 +304,7 @@ int __ref __add_pages(int nid, unsigned long pfn, unsigned 
long nr_pages,
if (WARN_ON_ONCE(!params->pgprot.pgprot))
return -EINVAL;
 
-   err = check_hotplug_memory_addressable(pfn, nr_pages);
-   if (err)
-   return err;
-
+   VM_BUG_ON(!memhp_range_allowed(PFN_PHYS(pfn), nr_pages * PAGE_SIZE, 1));
if (altmap) {
/*
 * Validate altmap is within bounds of the total request
@@ -1181,6 +1165,61 @@ int add_memory_driver_managed(int nid, u64 start, u64 
size,
 }
 EXPORT_SYMBOL_GPL(add_memory_driver_managed);
 
+/*
+ * Platforms should define arch_get_mappable_range() that provides
+ * maximum possible addressable physical memory range for which the
+ * linear mapping could be created. The platform returned address
+ * range must adhere to these following semantics.
+ *
+ *