Re: [PATCHv7 12/18] mm/hugetlb: Remove fake head pages

From: David Hildenbrand (Arm)

Date: Mon Mar 16 2026 - 13:08:02 EST


On 2/27/26 20:42, Kiryl Shutsemau (Meta) wrote:
> From: Kiryl Shutsemau <kas@xxxxxxxxxx>
>
> HugeTLB Vmemmap Optimization (HVO) reduces memory usage by freeing most
> vmemmap pages for huge pages and remapping the freed range to a single
> page containing the struct page metadata.
>
> With the new mask-based compound_info encoding (for power-of-2 struct
> page sizes), all tail pages of the same order are now identical
> regardless of which compound page they belong to. This means the tail
> pages can be truly shared without fake heads.
>
> Allocate a single page of initialized tail struct pages per zone
> per order in the vmemmap_tails[] array in struct zone. All huge pages of
> that order in the zone share this tail page, mapped read-only into their
> vmemmap. The head page remains unique per huge page.
>
> Redefine MAX_FOLIO_ORDER using ilog2(). The define has to produce a
> compile-constant as it is used to specify vmemmap_tail array size.
> For some reason, compiler is not able to solve get_order() at
> compile-time, but ilog2() works.
>
> Avoid PUD_ORDER to define MAX_FOLIO_ORDER as it adds dependency to
> <linux/pgtable.h> which generates hard-to-break include loop.
>
> This eliminates fake heads while maintaining the same memory savings,
> and simplifies compound_head() by removing fake head detection.
>
> Signed-off-by: Kiryl Shutsemau <kas@xxxxxxxxxx>
> ---

[...]
>
> +static struct zone *pfn_to_zone(unsigned nid, unsigned long pfn)

I'd make it clearer that this some hugetlb helper, not just some
page_zone(pfn_to_page()).

Also, it's only really valid during boot, where we cannot have
overlapping zones yet (hopefully IIRC).

static struct zone *hugetlb_early_pfn_to_zone(unsigned nid,
unsigned long pfn)

or sth. like that (throwing in an __init).

[...]

> index c76122f22294..928e79c7549c 100644
> --- a/mm/internal.h
> +++ b/mm/internal.h
> @@ -886,6 +886,15 @@ static inline void prep_compound_tail(struct page *tail,
> set_page_private(tail, 0);
> }
>
> +static inline void init_compound_tail(struct page *tail,
> + const struct page *head, unsigned int order, struct zone *zone)
> +{

In light of the refcount rework (lock/frozen bit), it might make sense
to directly set the page count here to 0, so it's easier to spot and
consider later.

set_page_count(tail, 0)

> + atomic_set(&tail->_mapcount, -1);
> + set_page_node(tail, zone_to_nid(zone));
> + set_page_zone(tail, zone_idx(zone));
> + prep_compound_tail(tail, head, order);
> +}
> +
Nothing else jumped at me

Acked-by: David Hildenbrand (Arm) <david@xxxxxxxxxx>

--
Cheers,

David