Re: [PATCH v1 02/11] mm: convert track_pfn_insert() to pfnmap_sanitize_pgprot()

David Hildenbrand
2025-04-25T19:49:00Z

On 25.04.25 21:31, Peter Xu wrote:
> On Fri, Apr 25, 2025 at 10:17:06AM +0200, David Hildenbrand wrote:
>> ... by factoring it out from track_pfn_remap().
>>
>> For PMDs/PUDs, actually check the full range, and trigger a fallback
>> if we run into this "different memory types / cachemodes" scenario.
>
> The current patch looks like to still pass PAGE_SIZE into the new helper at
> all track_pfn_insert() call sites, so it seems this comment does not 100%
> match with the code? Or I may have misread somewhere.

No, you're right, while reshuffling the patches I forgot to add the
actual PMD/PUD size.

>
> Maybe it's still easier to keep the single-pfn lookup to never fail.. more
> below.
>

[...]

>> /*
>> @@ -1556,8 +1553,23 @@ static inline void untrack_pfn_clear(struct vm_area_struct *vma)
>> extern int track_pfn_remap(struct vm_area_struct *vma, pgprot_t *prot,
>> unsigned long pfn, unsigned long addr,
>> unsigned long size);
>> -extern void track_pfn_insert(struct vm_area_struct *vma, pgprot_t *prot,
>> - pfn_t pfn);
>> +
>> +/**
>> + * pfnmap_sanitize_pgprot - sanitize the pgprot for a pfn range
>
> Nit: s/sanitize/update|setup|.../?
>
> But maybe you have good reason to use sanitize. No strong opinions.

What it does on PAT (only implementation so far ...) is looking up the
memory type to select the caching mode that can be use.

"sanitize" was IMHO a good fit, because we must make sure that we don't
use the wrong caching mode.

update/setup/... don't make that quite clear. Any other suggestions?

>
>> + * @pfn: the start of the pfn range
>> + * @size: the size of the pfn range
>> + * @prot: the pgprot to sanitize
>> + *
>> + * Sanitize the given pgprot for a pfn range, for example, adjusting the
>> + * cachemode.
>> + *
>> + * This function cannot fail for a single page, but can fail for multiple
>> + * pages.
>> + *
>> + * Returns 0 on success and -EINVAL on error.
>> + */
>> +int pfnmap_sanitize_pgprot(unsigned long pfn, unsigned long size,
>> + pgprot_t *prot);
>> extern int track_pfn_copy(struct vm_area_struct *dst_vma,
>> struct vm_area_struct *src_vma, unsigned long *pfn);
>> extern void untrack_pfn_copy(struct vm_area_struct *dst_vma,
>> diff --git a/mm/huge_memory.c b/mm/huge_memory.c
>> index fdcf0a6049b9f..b8ae5e1493315 100644
>> --- a/mm/huge_memory.c
>> +++ b/mm/huge_memory.c
>> @@ -1455,7 +1455,9 @@ vm_fault_t vmf_insert_pfn_pmd(struct vm_fault *vmf, pfn_t pfn, bool write)
>> return VM_FAULT_OOM;
>> }
>>
>> - track_pfn_insert(vma, &pgprot, pfn);
>> + if (pfnmap_sanitize_pgprot(pfn_t_to_pfn(pfn), PAGE_SIZE, &pgprot))
>> + return VM_FAULT_FALLBACK;
>
> Would "pgtable" leak if it fails? If it's PAGE_SIZE, IIUC it won't ever
> trigger, though.
>
> Maybe we could have a "void pfnmap_sanitize_pgprot_pfn(&pgprot, pfn)" to
> replace track_pfn_insert() and never fail? Dropping vma ref is definitely
> a win already in all cases.

It could be a simple wrapper around pfnmap_sanitize_pgprot(), yes.
That's certainly helpful for the single-page case.

Regarding never failing here: we should check the whole range. We have
to make sure that none of the pages has a memory type / caching mode
that is incompatible with what we setup.

Thanks a bunch for the review!
--
Cheers,

David / dhildenb