Skip to content

Commit 9444981

Browse files
author
Naman Jain
committed
Drivers: hv: mshv_vtl: restore 2M VTL0 low mappings to bound PageTables
Under sustained VTL0 I/O the paravisor's /proc/meminfo PageTables grew from ~660 kB into the tens of MB, steadily eating into VTL2 memory. The low VTL0 mapping (/dev/mshv_vtl_low) was installing a 4K PTE for every page it touched instead of a 2M PMD, so each touched 2M region cost a full extra page table. The regression came from gating the huge-fault path on a registered struct page. Underhill registers lower-VTL memory with the kernel lazily - only for ranges handed to a device for DMA (expose_va) - because a small VTL2 cannot afford struct pages for all of guest RAM. The CPU relay path, however, touches far more memory than is ever DMA'd, so most huge faults hit not-yet-registered pfns, failed the gate, and fell back to 4K. Fix it by mapping huge VTL0 faults by raw pfn again, via vmf_insert_pfn_pmd() with no registration gate (the pre-v6.15 behaviour). vmf_insert_pfn_pmd() dereferences no struct page, so a 2M map is valid even for an unregistered pfn and PageTables stays flat. Going back to the raw-pfn path re-exposes issues that the recent folio-based rework had addressed; handle each without giving up 2M: - rmap/RSS drift: vmf_insert_folio_pmd() adds a file rmap and RSS that zap_huge_pmd() never reverses on this VM_MIXEDMAP, non-DAX VMA (vma_is_special_huge() true, vma_is_dax() false), leaking a folio reference and tripping a "Bad rss-counter state" BUG. The pfn inserter carries no such state, so this drift simply goes away. - GUP refcount race: a huge pfn PMD holds no folio reference, so a zap racing pin_user_pages() could drop the refcount to 0 and warn in try_grab_folio(). Take a permanent reference on each pgmap folio in add_vtl0_mem() instead; VTL0 memory lives for the partition's lifetime, so the count never reaches 0. - GUP over smaller folios: add_vtl0_mem() derives the folio order from the range's alignment, so a sub-2M-aligned edge yields folios smaller than a PMD. Slow GUP would then batch a whole 2M span's references onto one base folio and corrupt its neighbours. Record such ranges on a normally-empty list - before the range itself is published - and fall back to 4K for any 2M window that overlaps one, so the mapping order never exceeds the folio order; only tiny RAM-edge tails lose 2M. - GUP into a memmap-less range: GUP on a huge pfn PMD walks the struct page (follow_huge_pmd -> pmd_page -> try_grab_folio) and would oops for a range whose devm_memremap_pages() failed. Track such failed ranges and fall back to 4K (pte_special) for any 2M window that overlaps one, so GUP fails gracefully with -EFAULT while all normal memory stays 2M. Also make add_vtl0_mem() idempotent (an already-registered range returns success, zapping any stale 4K PTEs so they refault as 2M) so re-registration across servicing never reports a spurious failure or leaves memory on 4K. Keep the failed-range bookkeeping consistent under concurrent registration: re-check registration when recording a failure, clear stale markers after the range is published so a transient -EBUSY never strands valid memory on 4K, coalesce failed ranges so repeated failures cannot grow the list without bound, and report success when a concurrent add has already registered the range. Fixes: 775741a ("Drivers: hv: mshv_vtl: use folio-aware inserters for huge VTL0 mappings") Signed-off-by: Naman Jain <[email protected]>
1 parent ee40c82 commit 9444981

1 file changed

Lines changed: 323 additions & 42 deletions

File tree

0 commit comments

Comments
 (0)