Skip to content

Commit 9ef3463

Browse files
oohalmpe
authored andcommitted
powerpc/mm: Fallback to RAM if the altmap is unusable
The "altmap" is used to provide a pool of memory that is reserved for the vmemmap backing of hot-plugged memory. This is useful when adding large amount of ZONE_DEVICE memory to a system with a limited amount of normal memory. On ppc64 we use huge pages to map the vmemmap which requires the backing storage to be contigious and aligned to the hugepage size. The altmap implementation allows for the altmap provider to reserve a few PFNs at the start of the range for it's own uses and when this occurs the first chunk of the altmap is not usable for hugepage mappings. On hash there is no sane way to fall back to a normal sized page mapping so we fail the allocation. This results in memory hotplug failing with ENOMEM when the new range doesn't fall into an existing vmemmap block. This patch handles this case by falling back to using system memory rather than failing if we cannot allocate from the altmap. This fallback should only ever be used for the first vmemmap block so it should not cause excess memory consumption. Fixes: 7b73d97 ("mm: pass the vmem_altmap to vmemmap_populate") Signed-off-by: Oliver O'Halloran <oohall@gmail.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
1 parent 43001c5 commit 9ef3463

File tree

1 file changed

+16
-3
lines changed

1 file changed

+16
-3
lines changed

arch/powerpc/mm/init_64.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,15 +188,20 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
188188
pr_debug("vmemmap_populate %lx..%lx, node %d\n", start, end, node);
189189

190190
for (; start < end; start += page_size) {
191-
void *p;
191+
void *p = NULL;
192192
int rc;
193193

194194
if (vmemmap_populated(start, page_size))
195195
continue;
196196

197+
/*
198+
* Allocate from the altmap first if we have one. This may
199+
* fail due to alignment issues when using 16MB hugepages, so
200+
* fall back to system memory if the altmap allocation fail.
201+
*/
197202
if (altmap)
198203
p = altmap_alloc_block_buf(page_size, altmap);
199-
else
204+
if (!p)
200205
p = vmemmap_alloc_block_buf(page_size, node);
201206
if (!p)
202207
return -ENOMEM;
@@ -255,8 +260,15 @@ void __ref vmemmap_free(unsigned long start, unsigned long end,
255260
{
256261
unsigned long page_size = 1 << mmu_psize_defs[mmu_vmemmap_psize].shift;
257262
unsigned long page_order = get_order(page_size);
263+
unsigned long alt_start = ~0, alt_end = ~0;
264+
unsigned long base_pfn;
258265

259266
start = _ALIGN_DOWN(start, page_size);
267+
if (altmap) {
268+
alt_start = altmap->base_pfn;
269+
alt_end = altmap->base_pfn + altmap->reserve +
270+
altmap->free + altmap->alloc + altmap->align;
271+
}
260272

261273
pr_debug("vmemmap_free %lx...%lx\n", start, end);
262274

@@ -280,8 +292,9 @@ void __ref vmemmap_free(unsigned long start, unsigned long end,
280292
page = pfn_to_page(addr >> PAGE_SHIFT);
281293
section_base = pfn_to_page(vmemmap_section_start(start));
282294
nr_pages = 1 << page_order;
295+
base_pfn = PHYS_PFN(addr);
283296

284-
if (altmap) {
297+
if (base_pfn >= alt_start && base_pfn < alt_end) {
285298
vmem_altmap_free(altmap, nr_pages);
286299
} else if (PageReserved(page)) {
287300
/* allocated from bootmem */

0 commit comments

Comments
 (0)