On Wed, May 06, 2026 at 01:44:53PM +0000, Anirudh Rayabharam (Microsoft) wrote:
> The hypervisor's map GPA hypercall coalesces contiguous 2M-aligned
> chunks into 1G mappings when alignment permits, so the driver can
> support 1G hugepages by feeding them in as 2M chunks. Note that this
> is the only way to make 1G mappings; there is no way to directly map
> a 1G hugepage using the hypercall.
> 
> Update mshv_chunk_stride() to:
> 
>   - Accept 2M-aligned tail pages of a larger folio. The previous
>     PageHead() check rejected every page after the head of a 1G
>     hugepage and fell back to 4K mappings for the remaining 1022 MB.
>     Replace it with a PFN alignment check so any 2M-aligned page of a
>     sufficiently large folio is acceptable.
> 
>   - Always emit a 2M (PMD_ORDER) stride for the huge-page case. The
>     hypercall has no 1G stride, so 1G folios are processed as a
>     sequence of 2M chunks. Folios whose order is neither PMD_ORDER nor
>     PUD_ORDER (e.g. mTHP) fall back to single-page stride; mapping
>     them as 2M would fail in the hypervisor anyway.
> 
> Assisted-by: Copilot-CLI:claude-opus-4.7
> Signed-off-by: Anirudh Rayabharam (Microsoft) <[email protected]>
> ---
> Changes in v3:
> - Fixed various corner cases reported by Sashiko.
> - Link to v2: 
> https://lore.kernel.org/r/[email protected]
> 
> Changes in v2:

LGTM, thanks.

Acked-by: Stanislav Kinsburskii <[email protected]>


> - Handled the case where we can have 2M aligned pages in the middle of a
>   1G page
> - Brought back the page order check but expanded it to include 1G
> - Clamp stride to requested page count in mshv_region_process_chunk
> - Link to v1: 
> https://lore.kernel.org/r/[email protected]
> ---
>  drivers/hv/mshv_regions.c | 32 +++++++++++++++-----------------
>  1 file changed, 15 insertions(+), 17 deletions(-)
> 
> diff --git a/drivers/hv/mshv_regions.c b/drivers/hv/mshv_regions.c
> index fdffd4f002f6..1756b733968c 100644
> --- a/drivers/hv/mshv_regions.c
> +++ b/drivers/hv/mshv_regions.c
> @@ -29,29 +29,28 @@
>   * Uses huge page stride if the backing page is huge and the guest mapping
>   * is properly aligned; otherwise falls back to single page stride.
>   *
> - * Return: Stride in pages, or -EINVAL if page order is unsupported.
> + * Return: Stride in pages.
>   */
> -static int mshv_chunk_stride(struct page *page,
> -                          u64 gfn, u64 page_count)
> +static unsigned int mshv_chunk_stride(struct page *page, u64 gfn,
> +                                   u64 page_count)
>  {
> -     unsigned int page_order;
> +     unsigned int page_order = folio_order(page_folio(page));
>  
>       /*
>        * Use single page stride by default. For huge page stride, the
> -      * page must be compound and point to the head of the compound
> -      * page, and both gfn and page_count must be huge-page aligned.
> +      * page must be compound, the page's PFN must itself be 2M-aligned
> +      * (so that a 2M-aligned tail page of a larger folio is acceptable),
> +      * and both gfn and page_count must be huge-page aligned.
>        */
> -     if (!PageCompound(page) || !PageHead(page) ||
> +     if (!PageCompound(page) ||
> +         !IS_ALIGNED(page_to_pfn(page), PTRS_PER_PMD) ||
>           !IS_ALIGNED(gfn, PTRS_PER_PMD) ||
> -         !IS_ALIGNED(page_count, PTRS_PER_PMD))
> +         !IS_ALIGNED(page_count, PTRS_PER_PMD) ||
> +         (page_order != PMD_ORDER && page_order != PUD_ORDER))
>               return 1;
>  
> -     page_order = folio_order(page_folio(page));
> -     /* The hypervisor only supports 2M huge page */
> -     if (page_order != PMD_ORDER)
> -             return -EINVAL;
> -
> -     return 1 << page_order;
> +     /* Use 2M stride always i.e. process 1G folios as 2M chunks */
> +     return 1 << PMD_ORDER;
>  }
>  
>  /**
> @@ -86,15 +85,14 @@ static long mshv_region_process_chunk(struct 
> mshv_mem_region *region,
>       u64 gfn = region->start_gfn + page_offset;
>       u64 count;
>       struct page *page;
> -     int stride, ret;
> +     unsigned int stride;
> +     int ret;
>  
>       page = region->mreg_pages[page_offset];
>       if (!page)
>               return -EINVAL;
>  
>       stride = mshv_chunk_stride(page, gfn, page_count);
> -     if (stride < 0)
> -             return stride;
>  
>       /* Start at stride since the first stride is validated */
>       for (count = stride; count < page_count; count += stride) {
> 
> ---
> base-commit: cd9f2e7d6e5b1837ef40b96e300fa28b73ab5a77
> change-id: 20260416-huge_1g-e44461393c8f
> 
> Best regards,
> -- 
> Anirudh Rayabharam (Microsoft) <[email protected]>
> 

Reply via email to