[PATCHv7 12/18] mm/hugetlb: Remove fake head pages
David Hildenbrand (Arm)
david at kernel.org
Mon Mar 16 10:01:51 PDT 2026
On 2/27/26 20:42, Kiryl Shutsemau (Meta) wrote:
> From: Kiryl Shutsemau <kas at kernel.org>
>
> 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 at kernel.org>
> ---
[...]
>
> +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 at kernel.org>
--
Cheers,
David
More information about the linux-riscv
mailing list