enum hv_mem_host_visibility visibility = enc ?
                        VMBUS_PAGE_NOT_VISIBLE : VMBUS_PAGE_VISIBLE_READ_WRITE;
        u64 *pfn_array;
+       phys_addr_t paddr;
+       void *vaddr;
        int ret = 0;
        bool result = true;
        int i, pfn;
                return false;
 
        for (i = 0, pfn = 0; i < pagecount; i++) {
-               pfn_array[pfn] = virt_to_hvpfn((void *)kbuffer + i * HV_HYP_PAGE_SIZE);
+               /*
+                * Use slow_virt_to_phys() because the PRESENT bit has been
+                * temporarily cleared in the PTEs.  slow_virt_to_phys() works
+                * without the PRESENT bit while virt_to_hvpfn() or similar
+                * does not.
+                */
+               vaddr = (void *)kbuffer + (i * HV_HYP_PAGE_SIZE);
+               paddr = slow_virt_to_phys(vaddr);
+               pfn_array[pfn] = paddr >> HV_HYP_PAGE_SHIFT;
                pfn++;
 
                if (pfn == HV_MAX_MODIFY_GPA_REP_COUNT || i == pagecount - 1) {
 
  * areas on 32-bit NUMA systems.  The percpu areas can
  * end up in this kind of memory, for instance.
  *
- * This could be optimized, but it is only intended to be
- * used at initialization time, and keeping it
- * unoptimized should increase the testing coverage for
- * the more obscure platforms.
+ * Note that as long as the PTEs are well-formed with correct PFNs, this
+ * works without checking the PRESENT bit in the leaf PTE.  This is unlike
+ * the similar vmalloc_to_page() and derivatives.  Callers may depend on
+ * this behavior.
+ *
+ * This could be optimized, but it is only used in paths that are not perf
+ * sensitive, and keeping it unoptimized should increase the testing coverage
+ * for the more obscure platforms.
  */
 phys_addr_t slow_virt_to_phys(void *__virt_addr)
 {