diff options
| author | Lance Yang <lance.yang@linux.dev> | 2026-10-01 00:04:32 +0800 |
|---|---|---|
| committer | David Hildenbrand (Arm) <david@kernel.org> | 2026-10-01 21:52:30 +0200 |
| commit | c31bb839fb829958101250ee5acfa4f94fdb7ecd (patch) | |
| tree | f7bd69a191163d426ccf235236093a4e1e9a20d3 | |
| parent | fa4df92e3d18e2428d7313350350de21824e183d (diff) | |
mm/memory_hotplug: fix missing rollback in __add_pages()
__add_pages() returns on a sparse_add_section() failure without removing
the sections already added in the same request.
For memremap_pages(), the failed range is not counted in pgmap->nr_range,
so memunmap_pages() skips it. The sections already added in that range
retain their vmemmap mappings and subsection bits. Retrying a
section-aligned range can then fail with -EEXIST.
Save the initial PFN and remove [start_pfn, pfn) on failure. For a vmemmap
population failure, section_activate() already cleans up the current
section, so the rollback excludes it. If the first section fails,
__remove_pages() receives an empty range and does nothing.
Link: https://lore.kernel.org/all/BAD58999-1EDD-4A37-ABA0-DB1BD8AB3453@linux.dev/
Suggested-by: Muchun Song <muchun.song@linux.dev>
Signed-off-by: Lance Yang <lance.yang@linux.dev>
Fixes: ba72b4c8cf60 ("mm/sparsemem: support sub-section hotplug")
Acked-by: Muchun Song <muchun.song@linux.dev>
Link: https://patch.msgid.link/20260930160432.5564-1-lance.yang@linux.dev
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
| -rw-r--r-- | mm/memory_hotplug.c | 6 |
1 files changed, 5 insertions, 1 deletions
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 100941d1b828..3f2bb2828ab1 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -384,6 +384,7 @@ EXPORT_SYMBOL_GPL(pfn_to_online_page); int __add_pages(int nid, unsigned long pfn, unsigned long nr_pages, struct mhp_params *params) { + const unsigned long start_pfn = pfn; const unsigned long end_pfn = pfn + nr_pages; unsigned long cur_nr_pages; int err; @@ -417,8 +418,11 @@ int __add_pages(int nid, unsigned long pfn, unsigned long nr_pages, SECTION_ALIGN_UP(pfn + 1) - pfn); err = sparse_add_section(nid, pfn, cur_nr_pages, altmap, params->pgmap); - if (err) + if (err) { + __remove_pages(start_pfn, pfn - start_pfn, altmap, + params->pgmap); break; + } cond_resched(); } vmemmap_populate_print_last(); |
