Skip to content

Commit 71b491d

Browse files
Naman Jainnamancse
authored andcommitted
Drivers: hv: mshv_vtl: fix GUP into VTL0 mappings on the 4K fault path
Extend the folio-aware fault path to the 4K case so GUP into /dev/mshv_vtl_low works after MSHV_ADD_VTL0_MEMORY has registered the range. With the previous vmf_insert_mixed() path the PTE was always pte_special, vm_normal_page() returned NULL during pin_user_pages*(), follow_pfn_pte() returned -EEXIST, and io_uring O_DIRECT surfaced it as "disk io error: io error: File exists (os error 17)" on the first DMA into a freshly-registered VTL0 chunk. The 4K path now resolves the PFN via mshv_vtl_low_resolve_page(): when backed by an mshv_vtl pgmap the PTE is installed with vmf_insert_page_mkwrite(), giving GUP a normal pinnable page; otherwise it falls back to vmf_insert_mixed() so early CPU accesses (e.g. the VTL2 guest-memory self test reading GPA 0 before any add_vtl0_mem ioctl) still succeed instead of SIGBUSing. Such fallback PTEs would persist across registration and break later GUP. Capture the cdev's address_space on first open and, on successful MSHV_ADD_VTL0_MEMORY, invalidate the file-offset range via unmap_mapping_range() for both the encrypted (pfn) and decrypted (pfn | DECRYPTED_MASK) aliases that mshv_vtl_low_mmap() exposes. The next access re-faults into the folio path and GUP works. Signed-off-by: Naman Jain <namjain@linux.microsoft.com>
1 parent 8444765 commit 71b491d

1 file changed

Lines changed: 37 additions & 3 deletions

File tree

drivers/hv/mshv_vtl_main.c

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1155,6 +1155,12 @@ static int vtl_set_vp_register(struct hv_register_assoc *reg)
11551155

11561156
#define DECRYPTED_MASK (1ul << 51)
11571157

1158+
/*
1159+
* /dev/mshv_vtl_low address_space, captured on first open.
1160+
* Used by add_vtl0_mem() to zap stale 4K PTEs.
1161+
*/
1162+
static struct address_space *mshv_vtl_low_mapping;
1163+
11581164
/* Identity token tagged on every mshv_vtl pgmap; only its address matters. */
11591165
static const u8 mshv_vtl_pgmap_token;
11601166

@@ -1210,6 +1216,20 @@ static int mshv_vtl_ioctl_add_vtl0_mem(struct mshv_vtl *vtl, void __user *arg)
12101216
return PTR_ERR(addr);
12111217
}
12121218

1219+
/*
1220+
* Zap stale pte_special PTEs the 4K fallback installed before this
1221+
* range had a pgmap, so the next access re-faults into the folio path.
1222+
* Both encrypted (pfn) and decrypted (pfn | DECRYPTED_MASK) aliases.
1223+
*/
1224+
if (READ_ONCE(mshv_vtl_low_mapping)) {
1225+
pgoff_t start = vtl0_mem.start_pfn;
1226+
pgoff_t nr = vtl0_mem.last_pfn - vtl0_mem.start_pfn;
1227+
1228+
unmap_mapping_pages(mshv_vtl_low_mapping, start, nr, true);
1229+
unmap_mapping_pages(mshv_vtl_low_mapping,
1230+
start | DECRYPTED_MASK, nr, true);
1231+
}
1232+
12131233
/* Don't free pgmap, since it has to stick around until the memory
12141234
* is unmapped, which will never happen as there is no scenario
12151235
* where VTL0 can be released/shutdown without bringing down VTL2.
@@ -3667,6 +3687,9 @@ static int mshv_vtl_low_open(struct inode *inodep, struct file *filp)
36673687

36683688
if (capable(CAP_SYS_ADMIN)) {
36693689
filp->private_data = inodep;
3690+
/* All opens share one inode; first one publishes the address_space. */
3691+
if (!READ_ONCE(mshv_vtl_low_mapping))
3692+
cmpxchg(&mshv_vtl_low_mapping, NULL, inodep->i_mapping);
36703693
inodep->i_mapping->a_ops = &mshv_vtl_low_aops;
36713694
} else {
36723695
pr_err("%s: VTL low open failed: CAP_SYS_ADMIN required. task group %d, uid %d",
@@ -3760,8 +3783,19 @@ static vm_fault_t mshv_vtl_low_huge_fault(struct vm_fault *vmf, unsigned int ord
37603783

37613784
switch (order) {
37623785
case 0:
3763-
/* pte_special path; GUP bails before try_grab_folio() so the WARN cannot fire here. */
3764-
return vmf_insert_mixed(vmf->vma, vmf->address, pfn);
3786+
page = mshv_vtl_low_resolve_page(pfn);
3787+
if (!page) {
3788+
/*
3789+
* No pgmap yet: install pte_special so CPU access succeeds.
3790+
* The unmap_mapping_range() in add_vtl0_mem() invalidates this
3791+
* PTE on registration so a later GUP-bound access re-faults
3792+
* into the folio path below.
3793+
*/
3794+
return vmf_insert_mixed(vmf->vma, vmf->address, pfn);
3795+
}
3796+
/* Inserter operates on the compound-head folio per PTE; refcounts stay balanced. */
3797+
mshv_vtl_low_set_mapping(vmf, page_folio(page), PAGE_SIZE);
3798+
return vmf_insert_page_mkwrite(vmf, page, write);
37653799

37663800
case PMD_ORDER:
37673801
if (!can_fault(vmf, PMD_SIZE, &pfn))
@@ -3821,7 +3855,7 @@ static int mshv_vtl_low_mmap(struct file *filp, struct vm_area_struct *vma)
38213855
return -EINVAL;
38223856

38233857
vma->vm_ops = &mshv_vtl_low_vm_ops;
3824-
/* VM_MIXEDMAP for the 4K pte_special path; VM_DONTEXPAND pins size to the pgmap. */
3858+
/* VM_MIXEDMAP for pte_special 4K fallback; VM_DONTEXPAND pins size to pgmap. */
38253859
vm_flags_set(vma, VM_HUGEPAGE | VM_MIXEDMAP | VM_DONTEXPAND);
38263860

38273861
if (vma->vm_pgoff & DECRYPTED_MASK)

0 commit comments

Comments
 (0)