mm/memory_hotplug: Don't allow to online/offline memory blocks with holes
Subsystems (2)
PATCH v2 1/1 mm/memory_hotplug: Don't allow to online/offline memory blocks with holes
Our onlining/offlining code is unnecessarily complicated. Only memory blocks added during boot can have holes (a range that is not IORESOURCE_SYSTEM_RAM). Hotplugged memory never has holes (e.g., see add_memory_resource()). All memory blocks that belong to boot memory are already online.
Note that boot memory can have holes and the memmap of the holes is marked PG_reserved. However, also memory allocated early during boot is PG_reserved - basically every page of boot memory that is not given to the buddy is PG_reserved.
Therefore, when we stop allowing to offline memory blocks with holes, we implicitly no longer have to deal with onlining memory blocks with holes. E.g., online_pages() will do awalk_system_ram_range(..., online_pages_range), whereby online_pages_range() will effectively only free the memory holes not falling into a hole to the buddy. The other pages (holes) are kept PG_reserved (via move_pfn_range_to_zone()->memmap_init_zone()).
This allows to simplify the code. For example, we no longer have to worry about marking pages that fall into memory holes PG_reserved when onlining memory. We can stop setting pages PG_reserved completely in memmap_init_zone().
Offlining memory blocks added during boot is usually not guaranteed to work either way (unmovable data might have easily ended up on that memory during boot). So stopping to do that should not really hurt. Also, people are not even aware of a setup where onlining/offlining of memory blocks with holes used to work reliably (see [1] and [2] especially regarding the hotplug path) - I doubt it worked reliably.
For the use case of offlining memory to unplug DIMMs, we should see no change. (holes on DIMMs would be weird).
Please note that hardware errors (PG_hwpoison) are not memory holes and are not affected by this change when offlining.
[1] https://lkml.org/lkml/2019/10/22/135
[2] https://lkml.org/lkml/2019/8/14/1365
---
This patch was part of:
[PATCH v1 00/10] mm: Don't mark hotplugged pages PG_reserved (including ZONE_DEVICE) -> https://www.spinics.net/lists/linux-driver-devel/msg130042.html
However, before we can perform the PG_reserved changes, we have to fix pfn_to_online_page() in special scenarios first (bootmem and devmem falling into a single section). Dan is working on that.
I propose to give this patch a churn in -next so we can identify if this change would break any existing setup. I will then follow up with cleanups and the PG_reserved changes later.
--- mm/memory_hotplug.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-)
mm/memory_hotplug.c +26 -2
@@ -1455,10 +1455,19 @@ static void node_states_clear_node(int node, struct memory_notify *arg)node_clear_state (node,N_MEMORY ); } +static int count_system_ram_pages_cb (unsigned long start_pfn, +unsigned long nr_pages,void *data) +{ +unsigned long *nr_system_ram_pages = data; + + *nr_system_ram_pages += nr_pages; +return 0 ; +} +static int __ref __offline_pages (unsigned long start_pfn,unsigned long end_pfn) { -unsigned long pfn, nr_pages; +unsigned long pfn, nr_pages =0 ;unsigned long offlined_pages =0 ;int ret, node, nr_isolate_pageblock;unsigned long flags;
@@ -1469,6 +1478,22 @@ static int __ref __offline_pages(unsigned long start_pfn,mem_hotplug_begin (); +/* +* Don't allow to offline memory blocks that contain holes. +* Consequently, memory blocks with holes can never get onlined +* via the hotplug path - online_pages() - as hotplugged memory has +* no holes. This way, we e.g., don't have to worry about marking +* memory holes PG_reserved, don't need pfn_valid() checks, and can +* avoid using walk_system_ram_range() later. +*/ +walk_system_ram_range (start_pfn, end_pfn - start_pfn, &nr_pages, + count_system_ram_pages_cb); +if (nr_pages != end_pfn - start_pfn) { + ret = -EINVAL ; + reason ="memory holes" ; + goto failed_removal; + } +/* This makes hotplug much easier...and readable. we assume this for now. .*/ if (!test_pages_in_a_zone(start_pfn, end_pfn, &valid_start,
@@ -1480,7 +1505,6 @@ static int __ref __offline_pages(unsigned long start_pfn, zone =page_zone (pfn_to_page (valid_start)); node =zone_to_nid (zone); - nr_pages = end_pfn - start_pfn;/* set above range as isolated */ ret = start_isolate_page_range(start_pfn, end_pfn,
Signature · 1 line
2.21.0
Quoted 31 lines · David Hildenbrand
Our onlining/offlining code is unnecessarily complicated. Only memory blocks added during boot can have holes (a range that is not
IORESOURCE_SYSTEM_RAM). Hotplugged memory never has holes (e.g., seeadd_memory_resource()). All memory blocks that belong to boot memory are already online.Note that boot memory can have holes and the memmap of the holes is marked
PG_reserved. However, also memory allocated early during boot isPG_reserved- basically every page of boot memory that is not given to the buddy isPG_reserved.Therefore, when we stop allowing to offline memory blocks with holes, we implicitly no longer have to deal with onlining memory blocks with holes. E.g.,
online_pages()will do awalk_system_ram_range(..., online_pages_range), wherebyonline_pages_range()will effectively only free the memory holes not falling into a hole to the buddy. The other pages (holes) are keptPG_reserved(via move_pfn_range_to_zone()->memmap_init_zone()).This allows to simplify the code. For example, we no longer have to worry about marking pages that fall into memory holes
PG_reservedwhen onlining memory. We can stop setting pagesPG_reservedcompletely inmemmap_init_zone().Offlining memory blocks added during boot is usually not guaranteed to work either way (unmovable data might have easily ended up on that memory during boot). So stopping to do that should not really hurt. Also, people are not even aware of a setup where onlining/offlining of memory blocks with holes used to work reliably (see [1] and [2] especially regarding the hotplug path) - I doubt it worked reliably.
Quoted 8 lines
For the use case of offlining memory to unplug DIMMs, we should see no change. (holes on DIMMs would be weird).
Please note that hardware errors (
PG_hwpoison) are not memory holes and are not affected by this change when offlining.[1] https://lkml.org/lkml/2019/10/22/135
[2] https://lkml.org/lkml/2019/8/14/1365
Please do not use lkml.org links, they tend to break longterm. Use
http://lkml.kernel.org/r/$msg_id instead.
Quoted 8 lines
Reviewed-by Dan Williams <[email protected]>Cc Andrew Morton <[email protected]>Cc Michal Hocko <[email protected]>Cc Oscar Salvador <[email protected]>Cc Pavel Tatashin <[email protected]>Cc Dan Williams <[email protected]>Cc Anshuman Khandual <[email protected]>Signed-off-by David Hildenbrand <[email protected]>
yes this looks sensible. We already do restrict offlining memry blocks which span multiple zones (e.g. when NUMA nodes are interleaved through a memblock boundary) so this is not the first restriction like that. If that allows future changes then let's just try it out and see whether there are real usecases that needs to handle boottime memory with holes hotremove.
Quoted 77 lines
---
This patch was part of:
[PATCH v1 00/10] mm: Don't mark hotplugged pages PG_reserved (including ZONE_DEVICE) -> https://www.spinics.net/lists/linux-driver-devel/msg130042.htmlHowever, before we can perform the
PG_reservedchanges, we have to fixpfn_to_online_page()in special scenarios first (bootmem and devmem falling into a single section). Dan is working on that.I propose to give this patch a churn in -next so we can identify if this change would break any existing setup. I will then follow up with cleanups and the
PG_reservedchanges later.--- mm/memory_hotplug.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-)mm/memory_hotplug.c +26
-2@@ -1455,10 +1455,19 @@ static void node_states_clear_node(int node, struct memory_notify *arg)node_clear_state (node,N_MEMORY ); } +static int count_system_ram_pages_cb (unsigned long start_pfn, +unsigned long nr_pages,void *data) +{ +unsigned long *nr_system_ram_pages = data; + + *nr_system_ram_pages += nr_pages; +return 0 ; +} +static int __ref __offline_pages (unsigned long start_pfn,unsigned long end_pfn) { -unsigned long pfn, nr_pages; +unsigned long pfn, nr_pages =0 ;unsigned long offlined_pages =0 ;int ret, node, nr_isolate_pageblock;unsigned long flags;@@ -1469,6 +1478,22 @@ static int __ref __offline_pages(unsigned long start_pfn,mem_hotplug_begin (); +/* +* Don't allow to offline memory blocks that contain holes. +* Consequently, memory blocks with holes can never get onlined +* via the hotplug path - online_pages() - as hotplugged memory has +* no holes. This way, we e.g., don't have to worry about marking +* memory holes PG_reserved, don't need pfn_valid() checks, and can +* avoid using walk_system_ram_range() later. +*/ +walk_system_ram_range (start_pfn, end_pfn - start_pfn, &nr_pages, + count_system_ram_pages_cb); +if (nr_pages != end_pfn - start_pfn) { + ret = -EINVAL ; + reason ="memory holes" ; + goto failed_removal; + } +/* This makes hotplug much easier...and readable. we assume this for now. .*/ if (!test_pages_in_a_zone(start_pfn, end_pfn, &valid_start,@@ -1480,7 +1505,6 @@ static int __ref __offline_pages(unsigned long start_pfn, zone =page_zone (pfn_to_page (valid_start)); node =zone_to_nid (zone); - nr_pages = end_pfn - start_pfn;/* set above range as isolated */ ret = start_isolate_page_range(start_pfn, end_pfn,Signature · 1 line
2.21.0
Signature · 2 lines
Michal Hocko SUSE Labs
Quoted 35 lines · Michal Hocko
Quoted 34 lines · David Hildenbrand
Our onlining/offlining code is unnecessarily complicated. Only memory blocks added during boot can have holes (a range that is not
IORESOURCE_SYSTEM_RAM). Hotplugged memory never has holes (e.g., seeadd_memory_resource()). All memory blocks that belong to boot memory are already online.Note that boot memory can have holes and the memmap of the holes is marked
PG_reserved. However, also memory allocated early during boot isPG_reserved- basically every page of boot memory that is not given to the buddy isPG_reserved.Therefore, when we stop allowing to offline memory blocks with holes, we implicitly no longer have to deal with onlining memory blocks with holes. E.g.,
online_pages()will do awalk_system_ram_range(..., online_pages_range), wherebyonline_pages_range()will effectively only free the memory holes not falling into a hole to the buddy. The other pages (holes) are keptPG_reserved(via move_pfn_range_to_zone()->memmap_init_zone()).This allows to simplify the code. For example, we no longer have to worry about marking pages that fall into memory holes
PG_reservedwhen onlining memory. We can stop setting pagesPG_reservedcompletely inmemmap_init_zone().Offlining memory blocks added during boot is usually not guaranteed to work either way (unmovable data might have easily ended up on that memory during boot). So stopping to do that should not really hurt. Also, people are not even aware of a setup where onlining/offlining of memory blocks with holes used to work reliably (see [1] and [2] especially regarding the hotplug path) - I doubt it worked reliably.
For the use case of offlining memory to unplug DIMMs, we should see no change. (holes on DIMMs would be weird).
Quoted 8 lines
Quoted 5 lines
Please note that hardware errors (
PG_hwpoison) are not memory holes and are not affected by this change when offlining.[1] https://lkml.org/lkml/2019/10/22/135
[2] https://lkml.org/lkml/2019/8/14/1365Please do not use lkml.org links, they tend to break longterm. Use
http://lkml.kernel.org/r/$msg_id instead.
Thanks for the tip! I read a couple of times that these links are problematic but never knew what to use instead ...
Signature · 3 lines
Thanks, David / dhildenb
Quoted 74 lines · David Hildenbrand
Our onlining/offlining code is unnecessarily complicated. Only memory blocks added during boot can have holes (a range that is not
IORESOURCE_SYSTEM_RAM). Hotplugged memory never has holes (e.g., seeadd_memory_resource()). All memory blocks that belong to boot memory are already online.Note that boot memory can have holes and the memmap of the holes is marked
PG_reserved. However, also memory allocated early during boot isPG_reserved- basically every page of boot memory that is not given to the buddy isPG_reserved.Therefore, when we stop allowing to offline memory blocks with holes, we implicitly no longer have to deal with onlining memory blocks with holes. E.g.,
online_pages()will do awalk_system_ram_range(..., online_pages_range), wherebyonline_pages_range()will effectively only free the memory holes not falling into a hole to the buddy. The other pages (holes) are keptPG_reserved(via move_pfn_range_to_zone()->memmap_init_zone()).This allows to simplify the code. For example, we no longer have to worry about marking pages that fall into memory holes
PG_reservedwhen onlining memory. We can stop setting pagesPG_reservedcompletely inmemmap_init_zone().Offlining memory blocks added during boot is usually not guaranteed to work either way (unmovable data might have easily ended up on that memory during boot). So stopping to do that should not really hurt. Also, people are not even aware of a setup where onlining/offlining of memory blocks with holes used to work reliably (see [1] and [2] especially regarding the hotplug path) - I doubt it worked reliably.
For the use case of offlining memory to unplug DIMMs, we should see no change. (holes on DIMMs would be weird).
Please note that hardware errors (
PG_hwpoison) are not memory holes and are not affected by this change when offlining.[1] https://lkml.org/lkml/2019/10/22/135
[2] https://lkml.org/lkml/2019/8/14/1365Reviewed-by Dan Williams <[email protected]>Cc Andrew Morton <[email protected]>Cc Michal Hocko <[email protected]>Cc Oscar Salvador <[email protected]>Cc Pavel Tatashin <[email protected]>Cc Dan Williams <[email protected]>Cc Anshuman Khandual <[email protected]>Signed-off-by David Hildenbrand <[email protected]>---
This patch was part of:
[PATCH v1 00/10] mm: Don't mark hotplugged pages PG_reserved (including ZONE_DEVICE) -> https://www.spinics.net/lists/linux-driver-devel/msg130042.htmlHowever, before we can perform the
PG_reservedchanges, we have to fixpfn_to_online_page()in special scenarios first (bootmem and devmem falling into a single section). Dan is working on that.I propose to give this patch a churn in -next so we can identify if this change would break any existing setup. I will then follow up with cleanups and the
PG_reservedchanges later.--- mm/memory_hotplug.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-)mm/memory_hotplug.c +0
-0@@ -1455,10 +1455,19 @@ static void node_states_clear_node(int node, struct memory_notify *arg)node_clear_state (node,N_MEMORY ); }
mm/memory_hotplug.c static void node_states_clear_node(int node, struct memory_notify *arg) · line 1466
Quoted 10 lines
mm/memory_hotplug.c +9
-0+static int count_system_ram_pages_cb (unsigned long start_pfn, +unsigned long nr_pages,void *data) +{ +unsigned long *nr_system_ram_pages = data; + + *nr_system_ram_pages += nr_pages; +return 0 ; +} +
Hello David,
what is the meaning of the function ? The return is every time 0.
I dont understand it ?
Best regards
Damian
Quoted 43 lines
mm/memory_hotplug.c +17
-2static int __ref __offline_pages (unsigned long start_pfn,unsigned long end_pfn) { -unsigned long pfn, nr_pages; +unsigned long pfn, nr_pages =0 ;unsigned long offlined_pages =0 ;int ret, node, nr_isolate_pageblock;unsigned long flags;@@ -1469,6 +1478,22 @@ static int __ref __offline_pages(unsigned long start_pfn,mem_hotplug_begin (); +/* +* Don't allow to offline memory blocks that contain holes. +* Consequently, memory blocks with holes can never get onlined +* via the hotplug path - online_pages() - as hotplugged memory has +* no holes. This way, we e.g., don't have to worry about marking +* memory holes PG_reserved, don't need pfn_valid() checks, and can +* avoid using walk_system_ram_range() later. +*/ +walk_system_ram_range (start_pfn, end_pfn - start_pfn, &nr_pages, + count_system_ram_pages_cb); +if (nr_pages != end_pfn - start_pfn) { + ret = -EINVAL ; + reason ="memory holes" ; + goto failed_removal; + } +/* This makes hotplug much easier...and readable. we assume this for now. .*/ if (!test_pages_in_a_zone(start_pfn, end_pfn, &valid_start,@@ -1480,7 +1505,6 @@ static int __ref __offline_pages(unsigned long start_pfn, zone =page_zone (pfn_to_page (valid_start)); node =zone_to_nid (zone); - nr_pages = end_pfn - start_pfn;/* set above range as isolated */ ret = start_isolate_page_range(start_pfn, end_pfn,Signature · 1 line
2.21.0
Quoted 87 lines · Damian Tometzki
Quoted 74 lines · David Hildenbrand
Our onlining/offlining code is unnecessarily complicated. Only memory blocks added during boot can have holes (a range that is not
IORESOURCE_SYSTEM_RAM). Hotplugged memory never has holes (e.g., seeadd_memory_resource()). All memory blocks that belong to boot memory are already online.Note that boot memory can have holes and the memmap of the holes is marked
PG_reserved. However, also memory allocated early during boot isPG_reserved- basically every page of boot memory that is not given to the buddy isPG_reserved.Therefore, when we stop allowing to offline memory blocks with holes, we implicitly no longer have to deal with onlining memory blocks with holes. E.g.,
online_pages()will do awalk_system_ram_range(..., online_pages_range), wherebyonline_pages_range()will effectively only free the memory holes not falling into a hole to the buddy. The other pages (holes) are keptPG_reserved(via move_pfn_range_to_zone()->memmap_init_zone()).This allows to simplify the code. For example, we no longer have to worry about marking pages that fall into memory holes
PG_reservedwhen onlining memory. We can stop setting pagesPG_reservedcompletely inmemmap_init_zone().Offlining memory blocks added during boot is usually not guaranteed to work either way (unmovable data might have easily ended up on that memory during boot). So stopping to do that should not really hurt. Also, people are not even aware of a setup where onlining/offlining of memory blocks with holes used to work reliably (see [1] and [2] especially regarding the hotplug path) - I doubt it worked reliably.
For the use case of offlining memory to unplug DIMMs, we should see no change. (holes on DIMMs would be weird).
Please note that hardware errors (
PG_hwpoison) are not memory holes and are not affected by this change when offlining.[1] https://lkml.org/lkml/2019/10/22/135
[2] https://lkml.org/lkml/2019/8/14/1365Reviewed-by Dan Williams <[email protected]>Cc Andrew Morton <[email protected]>Cc Michal Hocko <[email protected]>Cc Oscar Salvador <[email protected]>Cc Pavel Tatashin <[email protected]>Cc Dan Williams <[email protected]>Cc Anshuman Khandual <[email protected]>Signed-off-by David Hildenbrand <[email protected]>---
This patch was part of:
[PATCH v1 00/10] mm: Don't mark hotplugged pages PG_reserved (including ZONE_DEVICE) -> https://www.spinics.net/lists/linux-driver-devel/msg130042.htmlHowever, before we can perform the
PG_reservedchanges, we have to fixpfn_to_online_page()in special scenarios first (bootmem and devmem falling into a single section). Dan is working on that.I propose to give this patch a churn in -next so we can identify if this change would break any existing setup. I will then follow up with cleanups and the
PG_reservedchanges later.--- mm/memory_hotplug.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-)mm/memory_hotplug.c +0
-0@@ -1455,10 +1455,19 @@ static void node_states_clear_node(int node, struct memory_notify *arg)node_clear_state (node,N_MEMORY ); }mm/memory_hotplug.c static void node_states_clear_node(int node, struct memory_notify *arg) · line 1466
Quoted 10 lines
mm/memory_hotplug.c +9
-0+static int count_system_ram_pages_cb (unsigned long start_pfn, +unsigned long nr_pages,void *data) +{ +unsigned long *nr_system_ram_pages = data; + + *nr_system_ram_pages += nr_pages; +return 0 ; +} +Hello David,
Quoted 4 lines
what is the meaning of the function ? The return is every time 0.
I dont understand it ?
Hi Damian,
please see how these callbacks are used within walk_system_ram_range(). A return value of 0 only means "don't stop iterating", the actual values are returned via the "void *data" parameter in this instance.
Cheers!
Signature · 3 lines
Thanks, David / dhildenb