2020#include <linux/eventfd.h>
2121#include <linux/poll.h>
2222#include <linux/file.h>
23+ #include <linux/pagemap.h>
2324#include <linux/user-return-notifier.h>
2425#include <linux/vmalloc.h>
2526#include <asm/boot.h>
@@ -1154,6 +1155,9 @@ static int vtl_set_vp_register(struct hv_register_assoc *reg)
11541155
11551156#define DECRYPTED_MASK (1ul << 51)
11561157
1158+ /* Identity token tagged on every mshv_vtl pgmap; only its address matters. */
1159+ static const u8 mshv_vtl_pgmap_token ;
1160+
11571161static int mshv_vtl_ioctl_add_vtl0_mem (struct mshv_vtl * vtl , void __user * arg )
11581162{
11591163 struct mshv_vtl_ram_disposition vtl0_mem ;
@@ -1182,6 +1186,7 @@ static int mshv_vtl_ioctl_add_vtl0_mem(struct mshv_vtl *vtl, void __user *arg)
11821186 pgmap -> ranges [0 ].end = PFN_PHYS (vtl0_mem .last_pfn ) - 1 ;
11831187 pgmap -> nr_range = 1 ;
11841188 pgmap -> type = MEMORY_DEVICE_GENERIC ;
1189+ pgmap -> owner = (void * )& mshv_vtl_pgmap_token ;
11851190 if (decrypted )
11861191 pgmap -> flags = PGMAP_DECRYPTED ;
11871192
@@ -3640,6 +3645,18 @@ static struct miscdevice mshv_vtl_hvcall_dev = {
36403645 .minor = MISC_DYNAMIC_MINOR ,
36413646};
36423647
3648+ /*
3649+ * Mirror drivers/dax/device.c: once the fault path publishes folio->mapping
3650+ * to this inode's address_space, writeback-side helpers (e.g.
3651+ * folio_mark_dirty() called from bio_set_pages_dirty() after direct I/O into
3652+ * a GUP'd VTL0 buffer) will dispatch through mapping->a_ops->dirty_folio.
3653+ * The default empty_aops leaves dirty_folio NULL, so install noop_dirty_folio
3654+ * to keep that dispatch safe; nothing here participates in real writeback.
3655+ */
3656+ static const struct address_space_operations mshv_vtl_low_aops = {
3657+ .dirty_folio = noop_dirty_folio ,
3658+ };
3659+
36433660static int mshv_vtl_low_open (struct inode * inodep , struct file * filp )
36443661{
36453662 pid_t pid = task_pid_vnr (current );
@@ -3650,6 +3667,7 @@ static int mshv_vtl_low_open(struct inode *inodep, struct file *filp)
36503667
36513668 if (capable (CAP_SYS_ADMIN )) {
36523669 filp -> private_data = inodep ;
3670+ inodep -> i_mapping -> a_ops = & mshv_vtl_low_aops ;
36533671 } else {
36543672 pr_err ("%s: VTL low open failed: CAP_SYS_ADMIN required. task group %d, uid %d" ,
36553673 __func__ , pid , uid );
@@ -3678,26 +3696,102 @@ static bool can_fault(struct vm_fault *vmf, unsigned long size, unsigned long *p
36783696 return is_valid ;
36793697}
36803698
3699+ /*
3700+ * Resolve a user-supplied PFN to a page owned by an mshv_vtl pgmap, or NULL.
3701+ * Look up the pgmap via get_dev_pagemap() rather than page_pgmap(): the pgmap
3702+ * is published in pgmap_array before per-page state is initialized, so a
3703+ * concurrent MSHV_ADD_VTL0_MEMORY can leave folio->pgmap unset while pfn_valid
3704+ * and is_zone_device_page already return true. The owner check additionally
3705+ * rejects foreign MEMORY_DEVICE_GENERIC pgmaps (e.g. DAX).
3706+ */
3707+ static struct page * mshv_vtl_low_resolve_page (unsigned long pfn )
3708+ {
3709+ struct dev_pagemap * pgmap ;
3710+ struct page * page ;
3711+
3712+ pgmap = get_dev_pagemap (pfn );
3713+ if (!pgmap )
3714+ return NULL ;
3715+ page = NULL ;
3716+ if (pgmap -> type == MEMORY_DEVICE_GENERIC &&
3717+ pgmap -> owner == & mshv_vtl_pgmap_token )
3718+ page = pfn_to_page (pfn );
3719+ /* Safe to drop here: mshv_vtl pgmaps are never released for the life of the module. */
3720+ put_dev_pagemap (pgmap );
3721+ return page ;
3722+ }
3723+
3724+ /*
3725+ * Mirror dax_set_mapping(): rmap walkers locate a file-rmapped folio via
3726+ * folio->mapping/index. ZONE_DEVICE init only fills ->pgmap, so set the
3727+ * file-mapping fields here before each insert that adds file rmap.
3728+ * Idempotent: only the head folio carries mapping/index, and once set the
3729+ * fields persist for the lifetime of the (never-released) pgmap.
3730+ */
3731+ static void mshv_vtl_low_set_mapping (struct vm_fault * vmf , struct folio * folio ,
3732+ unsigned long fault_size )
3733+ {
3734+ if (folio -> mapping )
3735+ return ;
3736+
3737+ folio -> mapping = vmf -> vma -> vm_file -> f_mapping ;
3738+ folio -> index = linear_page_index (vmf -> vma ,
3739+ ALIGN_DOWN (vmf -> address , fault_size ));
3740+ }
3741+
3742+ /*
3743+ * Note on rmap/RSS accounting for huge VTL0 mappings:
3744+ * vmf_insert_folio_{pmd,pud}() takes a folio reference, adds a file rmap,
3745+ * and bumps mm RSS, but the matching teardown is skipped at zap/split time
3746+ * because vma_is_special_huge() is true (VM_MIXEDMAP) while vma_is_dax() is
3747+ * false (CONFIG_FS_DAX is not set in OHCL). The drift is theoretical for
3748+ * OpenVMM/OpenHCL: VTL0 memory is mapped once per partition and held for
3749+ * its lifetime - there is no map/unmap cycling, no partial munmap, and the
3750+ * driver is not unloaded. Stale refs land on ZONE_DEVICE folios whose
3751+ * pgmap is intentionally never released, no real bytes are leaked, and the
3752+ * mm's inflated RSS is discarded with the mm at process exit.
3753+ */
36813754static vm_fault_t mshv_vtl_low_huge_fault (struct vm_fault * vmf , unsigned int order )
36823755{
36833756 unsigned long pfn = vmf -> pgoff & ~DECRYPTED_MASK ;
3684- vm_fault_t ret = VM_FAULT_FALLBACK ;
3757+ bool write = vmf -> flags & FAULT_FLAG_WRITE ;
3758+ struct page * page ;
3759+ struct folio * folio ;
36853760
36863761 switch (order ) {
36873762 case 0 :
3688- /* __pfn_to_pfn_t ? */
3763+ /* pte_special path; GUP bails before try_grab_folio() so the WARN cannot fire here. */
36893764 return vmf_insert_mixed (vmf -> vma , vmf -> address , pfn );
36903765
36913766 case PMD_ORDER :
3692- if (can_fault (vmf , PMD_SIZE , & pfn ))
3693- ret = vmf_insert_pfn_pmd (vmf , pfn , vmf -> flags & FAULT_FLAG_WRITE );
3694- return ret ;
3767+ if (!can_fault (vmf , PMD_SIZE , & pfn ))
3768+ return VM_FAULT_FALLBACK ;
3769+ page = mshv_vtl_low_resolve_page (pfn );
3770+ if (!page )
3771+ return VM_FAULT_FALLBACK ;
3772+ folio = page_folio (page );
3773+ /*
3774+ * vmf_insert_folio_pmd() needs an exact-order folio; let core
3775+ * retry smaller on mismatch.
3776+ */
3777+ if (folio_order (folio ) != PMD_ORDER )
3778+ return VM_FAULT_FALLBACK ;
3779+ mshv_vtl_low_set_mapping (vmf , folio , PMD_SIZE );
3780+ return vmf_insert_folio_pmd (vmf , folio , write );
36953781
36963782#if defined(CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD )
36973783 case PUD_ORDER :
3698- if (can_fault (vmf , PUD_SIZE , & pfn ))
3699- ret = vmf_insert_pfn_pud (vmf , pfn , vmf -> flags & FAULT_FLAG_WRITE );
3700- return ret ;
3784+ if (!can_fault (vmf , PUD_SIZE , & pfn ))
3785+ return VM_FAULT_FALLBACK ;
3786+ page = mshv_vtl_low_resolve_page (pfn );
3787+ if (!page )
3788+ return VM_FAULT_FALLBACK ;
3789+ folio = page_folio (page );
3790+ /* Same exact-order requirement as the PMD case above. */
3791+ if (folio_order (folio ) != PUD_ORDER )
3792+ return VM_FAULT_FALLBACK ;
3793+ mshv_vtl_low_set_mapping (vmf , folio , PUD_SIZE );
3794+ return vmf_insert_folio_pud (vmf , folio , write );
37013795#endif
37023796
37033797 default :
@@ -3717,8 +3811,18 @@ static const struct vm_operations_struct mshv_vtl_low_vm_ops = {
37173811
37183812static int mshv_vtl_low_mmap (struct file * filp , struct vm_area_struct * vma )
37193813{
3814+ /*
3815+ * Reject MAP_PRIVATE: the fault path installs PTEs via
3816+ * vmf_insert_{page,folio}_{,pmd,pud}() and bypasses core-mm COW, so
3817+ * MAP_PRIVATE writes would land on the underlying VTL0/device page
3818+ * instead of a private copy. Mirror device-dax (drivers/dax/device.c).
3819+ */
3820+ if ((vma -> vm_flags & VM_MAYSHARE ) != VM_MAYSHARE )
3821+ return - EINVAL ;
3822+
37203823 vma -> vm_ops = & mshv_vtl_low_vm_ops ;
3721- vm_flags_set (vma , VM_HUGEPAGE | VM_MIXEDMAP );
3824+ /* VM_MIXEDMAP for the 4K pte_special path; VM_DONTEXPAND pins size to the pgmap. */
3825+ vm_flags_set (vma , VM_HUGEPAGE | VM_MIXEDMAP | VM_DONTEXPAND );
37223826
37233827 if (vma -> vm_pgoff & DECRYPTED_MASK )
37243828 vma -> vm_page_prot = pgprot_decrypted (vma -> vm_page_prot );
0 commit comments