Re: [PATCH] mm/ptdesc: Derive from the compound head in page_ptdesc()

From: Anshuman Khandual
Date: Mon Nov 10 2025 - 21:01:33 EST


On 10/11/25 2:23 PM, David Hildenbrand (Red Hat) wrote:
> On 10.11.25 07:37, Anshuman Khandual wrote:
>> struct ptdesc (including all relevant helpers) support multi order compound
>> pages. But page_ptdesc() coverts given page into its own ptdesc rather than
>> deriving from its compound head as would have been expected otherwise. Just
>> change the macro to fetch the struct ptdesc from the compound head instead,
>> so that the same struct ptdesc is reached from all tail pages.
>>
>> Cc: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx>
>> Cc: David Hildenbrand <david@xxxxxxxxxx>
>> Cc: Lorenzo Stoakes <lorenzo.stoakes@xxxxxxxxxx>
>> Cc: Liam R. Howlett <Liam.Howlett@xxxxxxxxxx>
>> Cc: Vlastimil Babka <vbabka@xxxxxxx>
>> Cc: Mike Rapoport <rppt@xxxxxxxxxx>
>> Cc: Suren Baghdasaryan <surenb@xxxxxxxxxx>
>> Cc: Michal Hocko <mhocko@xxxxxxxx>
>> Cc: Matthew Wilcox <willy@xxxxxxxxxxxxx>
>> Cc: linux-mm@xxxxxxxxx
>> Cc: linux-kernel@xxxxxxxxxxxxxxx
>> Signed-off-by: Anshuman Khandual <anshuman.khandual@xxxxxxx>
>> ---
>> This applies on v6.18-rc5
>>
>> Found via code inspection. Apparently struct ptdesc could represent a page
>> table page which is multi order looking into helpers as ptdesc_nr_pages(),
>> __pagetable_ctor/dtor() and pagetable_free() etc. Am I missing something ?
>>
>>   include/linux/mm_types.h | 6 +++---
>>   1 file changed, 3 insertions(+), 3 deletions(-)
>>
>> diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
>> index 90e5790c318f..f7107bc55d1e 100644
>> --- a/include/linux/mm_types.h
>> +++ b/include/linux/mm_types.h
>> @@ -604,9 +604,9 @@ static_assert(sizeof(struct ptdesc) <= sizeof(struct page));
>>       const struct ptdesc *:        (const struct folio *)(pt),    \
>>       struct ptdesc *:        (struct folio *)(pt)))
>>   -#define page_ptdesc(p)            (_Generic((p),            \
>> -    const struct page *:        (const struct ptdesc *)(p),    \
>> -    struct page *:            (struct ptdesc *)(p)))
>> +#define page_ptdesc(p)            (_Generic((p),                    \
>> +    const struct page *:        (const struct ptdesc *)_compound_head(p),    \
>> +    struct page *:            (struct ptdesc *)_compound_head(p)))
>
> Well, this adds overhead :)
>
> The real question is when we would be converting from a tail page to a ptdesc.
>
> Take a look at pmd_ptdesc()->pmd_pgtable_page() where we avoid looking up a tail page in the first place.
>

Agreed - it does avoid looking into the tail pages. Currently there
are no instances where tail pages are converted into struct ptdesc.
But on its own page_ptdesc() does not look right and would not work
when applied on a tail page.

static inline struct page *pmd_pgtable_page(pmd_t *pmd)
{
unsigned long mask = ~(PTRS_PER_PMD * sizeof(pmd_t) - 1);
return virt_to_page((void *)((unsigned long) pmd & mask));
}

static inline struct ptdesc *pmd_ptdesc(pmd_t *pmd)
{
return page_ptdesc(pmd_pgtable_page(pmd));
}