x86/hyperv: Use slow_virt_to_phys() in page transition hypervisor callback
authorMichael Kelley <mhklinux@outlook.com>
Tue, 16 Jan 2024 02:20:06 +0000 (18:20 -0800)
committerWei Liu <wei.liu@kernel.org>
Fri, 1 Mar 2024 08:31:41 +0000 (08:31 +0000)
In preparation for temporarily marking pages not present during a
transition between encrypted and decrypted, use slow_virt_to_phys()
in the hypervisor callback. As long as the PFN is correct,
slow_virt_to_phys() works even if the leaf PTE is not present.
The existing functions that depend on vmalloc_to_page() all
require that the leaf PTE be marked present, so they don't work.

Update the comments for slow_virt_to_phys() to note this broader usage
and the requirement to work even if the PTE is not marked present.

Signed-off-by: Michael Kelley <mhklinux@outlook.com>
Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Reviewed-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
Link: https://lore.kernel.org/r/20240116022008.1023398-2-mhklinux@outlook.com
Signed-off-by: Wei Liu <wei.liu@kernel.org>
Message-ID: <20240116022008.1023398-2-mhklinux@outlook.com>

arch/x86/hyperv/ivm.c
arch/x86/mm/pat/set_memory.c

index 7dcbf153ad7257c3fda712df91b3195efe522ab2..f38cdcb130edea4115db546e34ccec5bb76a2203 100644 (file)
@@ -515,6 +515,8 @@ static bool hv_vtom_set_host_visibility(unsigned long kbuffer, int pagecount, bo
        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;
@@ -524,7 +526,15 @@ static bool hv_vtom_set_host_visibility(unsigned long kbuffer, int pagecount, bo
                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) {
index e9b448d1b1b70f08dae6216250f02e783091a83a..b28b6f8afb0e9f6004a8ac6603086931bdd11b63 100644 (file)
@@ -755,10 +755,14 @@ pmd_t *lookup_pmd_address(unsigned long address)
  * 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)
 {