When a pgmap @align is set, all pages are mapped at a given huge page
alignment and thus uses compound pages to describe them as opposed to a
struct per 4K.
With @align > PAGE_SIZE and when struct pages are stored in ram
(!altmap) most tail pages are reused. Consequently, the amount of unique
struct pages is a lot smaller that the total amount of struct pages
being mapped.
When struct pages are initialize in memmap_init_zone_device, make
sure that only unique struct pages are initialized i.e. the first 2
4K pages per @align which means 128 struct pages, instead of 32768 for
2M @align or 262144 for a 1G @align.
Keep old behaviour with altmap given that it doesn't support reusal
of tail vmemmap areas.
Signed-off-by: Joao Martins <redacted>
---
mm/page_alloc.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 3a77f9e43f3a..948dfad6754b 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -6277,6 +6277,8 @@ static void __ref __init_zone_device_page(struct page *page, unsigned long pfn,
}
}
+#define MEMMAP_NR_PAGES (2 * (PAGE_SIZE/sizeof(struct page)))
+
void __ref memmap_init_zone_device(struct zone *zone,
unsigned long start_pfn,
unsigned long nr_pages,
@@ -6287,6 +6289,7 @@ void __ref memmap_init_zone_device(struct zone *zone,
struct vmem_altmap *altmap = pgmap_altmap(pgmap);
unsigned int pfn_align = pgmap_pfn_align(pgmap);
unsigned int order_align = order_base_2(pfn_align);
+ unsigned long ntails = min_t(unsigned long, pfn_align, MEMMAP_NR_PAGES);
unsigned long zone_idx = zone_idx(zone);
unsigned long start = jiffies;
int nid = pgdat->node_id;
@@ -6302,6 +6305,7 @@ void __ref memmap_init_zone_device(struct zone *zone,
if (altmap) {
start_pfn = altmap->base_pfn + vmem_altmap_offset(altmap);
nr_pages = end_pfn - start_pfn;
+ ntails = pfn_align;
}
for (pfn = start_pfn; pfn < end_pfn; pfn += pfn_align) {@@ -6315,7 +6319,7 @@ void __ref memmap_init_zone_device(struct zone *zone,
__SetPageHead(page);
- for (i = 1; i < pfn_align; i++) {
+ for (i = 1; i < ntails; i++) {
__init_zone_device_page(page + i, pfn + i, zone_idx,
nid, pgmap);
prep_compound_tail(page, i);--
2.17.1