From: Anirudh Rayabharam (Microsoft) <[email protected]> Sent: Wednesday,
May 6, 2026 6:45 AM
>
> 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/20260505-huge_1g-v2-1-
> [email protected]
>
> Changes in v2:
> - 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/20260416-huge_1g-v1-1-
> [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))
One more thought on this patch:
This test could be unnecessarily restrictive. For example, if
there was a 4 MiB contiguous physical memory allocation,
page_order would be PMD_ORDER+1. There's no reason to
map such memory as single pages. While today there may
be no way for the user space VMM process address space
to be populated with a 4 MiB contiguous physical memory
range, who knows what the mm subsystem might do in the
future. I'd suggest doing (page_order < PMD_ORDER) to
allow page_orders of PMD_ORDER or bigger to be
processed in PMD-size chunks.
Michael
> 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]>
>