]> xenbits.xensource.com Git - people/tklengyel/xen.git/commitdiff
x86/mem_sharing: option to enforce fork starting with empty p2m
authorTamas K Lengyel <tamas.lengyel@intel.com>
Mon, 21 Mar 2022 15:35:35 +0000 (11:35 -0400)
committerTamas K Lengyel <tamas@tklengyel.com>
Fri, 25 Mar 2022 16:50:49 +0000 (16:50 +0000)
Add option to the fork memop to enforce a start with an empty p2m.
Pre-populating special pages to the fork tend to be necessary only when setting
up forks to be fully functional with a toolstack or if the fork makes use of
them in some way. For short-lived forks these pages are optional and starting
with an empty p2m has advantages both in terms of reset performance as well as
easier reasoning about the state of the fork after creation.

Signed-off-by: Tamas K Lengyel <tamas.lengyel@intel.com>
---
v2: rename flag to empty_p2m, add assert at the end and move
     vAPIC page mapping skipping logic into where its mapped

xen/arch/x86/hvm/vmx/vmx.c
xen/arch/x86/include/asm/hvm/domain.h
xen/arch/x86/mm/mem_sharing.c
xen/include/public/memory.h

index d61c3d64d378f2adbc88f7a5e1c83e03a159a0e3..27718600c5d94fcc424f0826ea3eaeae226c0053 100644 (file)
@@ -424,6 +424,11 @@ static void cf_check domain_creation_finished(struct domain *d)
     if ( !has_vlapic(d) || mfn_eq(apic_access_mfn, INVALID_MFN) )
         return;
 
+#ifdef CONFIG_MEM_SHARING
+    if ( d->arch.hvm.mem_sharing.empty_p2m )
+        return;
+#endif
+
     ASSERT(epte_get_entry_emt(d, gfn, apic_access_mfn, 0, &ipat,
                               p2m_mmio_direct) == MTRR_TYPE_WRBACK);
     ASSERT(ipat);
index 698455444ea85b691126c3e8a31c08bbd48acb25..22a17c36c5e87d237dde9ba2fc7fbf0562080389 100644 (file)
@@ -31,7 +31,9 @@
 #ifdef CONFIG_MEM_SHARING
 struct mem_sharing_domain
 {
-    bool enabled, block_interrupts;
+    bool enabled;
+    bool block_interrupts;
+    bool empty_p2m;
 
     /*
      * When releasing shared gfn's in a preemptible manner, recall where
index 857accee588641604226f17e2a912b898765f9c9..908bde495400c4e359d03e17740740794df1995a 100644 (file)
@@ -1650,7 +1650,8 @@ static void copy_vcpu_nonreg_state(struct vcpu *d_vcpu, struct vcpu *cd_vcpu)
     hvm_set_nonreg_state(cd_vcpu, &nrs);
 }
 
-static int copy_vcpu_settings(struct domain *cd, const struct domain *d)
+static int copy_vcpu_settings(struct domain *cd, const struct domain *d,
+                              bool empty_p2m)
 {
     unsigned int i;
     struct p2m_domain *p2m = p2m_get_hostp2m(cd);
@@ -1667,7 +1668,7 @@ static int copy_vcpu_settings(struct domain *cd, const struct domain *d)
 
         /* Copy & map in the vcpu_info page if the guest uses one */
         vcpu_info_mfn = d_vcpu->vcpu_info_mfn;
-        if ( !mfn_eq(vcpu_info_mfn, INVALID_MFN) )
+        if ( !empty_p2m && !mfn_eq(vcpu_info_mfn, INVALID_MFN) )
         {
             mfn_t new_vcpu_info_mfn = cd_vcpu->vcpu_info_mfn;
 
@@ -1816,17 +1817,18 @@ static int copy_special_pages(struct domain *cd, struct domain *d)
     return 0;
 }
 
-static int copy_settings(struct domain *cd, struct domain *d)
+static int copy_settings(struct domain *cd, struct domain *d,
+                         bool empty_p2m)
 {
     int rc;
 
-    if ( (rc = copy_vcpu_settings(cd, d)) )
+    if ( (rc = copy_vcpu_settings(cd, d, empty_p2m)) )
         return rc;
 
     if ( (rc = hvm_copy_context_and_params(cd, d)) )
         return rc;
 
-    if ( (rc = copy_special_pages(cd, d)) )
+    if ( !empty_p2m && (rc = copy_special_pages(cd, d)) )
         return rc;
 
     copy_tsc(cd, d);
@@ -1835,9 +1837,11 @@ static int copy_settings(struct domain *cd, struct domain *d)
     return rc;
 }
 
-static int fork(struct domain *cd, struct domain *d)
+static int fork(struct domain *cd, struct domain *d, uint16_t flags)
 {
     int rc = -EBUSY;
+    bool block_interrupts = flags & XENMEM_FORK_BLOCK_INTERRUPTS;
+    bool empty_p2m = flags & XENMEM_FORK_EMPTY_P2M;
 
     if ( !cd->controller_pause_count )
         return rc;
@@ -1865,7 +1869,13 @@ static int fork(struct domain *cd, struct domain *d)
     if ( (rc = bring_up_vcpus(cd, d)) )
         goto done;
 
-    rc = copy_settings(cd, d);
+    if ( !(rc = copy_settings(cd, d, empty_p2m)) )
+    {
+        cd->arch.hvm.mem_sharing.block_interrupts = block_interrupts;
+
+        if ( (cd->arch.hvm.mem_sharing.empty_p2m = empty_p2m) )
+            ASSERT(page_list_empty(&cd->page_list));
+    }
 
  done:
     if ( rc && rc != -ERESTART )
@@ -1929,7 +1939,7 @@ static int mem_sharing_fork_reset(struct domain *d)
     }
     spin_unlock_recursive(&d->page_alloc_lock);
 
-    rc = copy_settings(d, pd);
+    rc = copy_settings(d, pd, d->arch.hvm.mem_sharing.empty_p2m);
 
     domain_unpause(d);
 
@@ -2199,7 +2209,8 @@ int mem_sharing_memop(XEN_GUEST_HANDLE_PARAM(xen_mem_sharing_op_t) arg)
         if ( mso.u.fork.pad )
             goto out;
         if ( mso.u.fork.flags &
-             ~(XENMEM_FORK_WITH_IOMMU_ALLOWED | XENMEM_FORK_BLOCK_INTERRUPTS) )
+             ~(XENMEM_FORK_WITH_IOMMU_ALLOWED | XENMEM_FORK_BLOCK_INTERRUPTS |
+               XENMEM_FORK_EMPTY_P2M) )
             goto out;
 
         rc = rcu_lock_live_remote_domain_by_id(mso.u.fork.parent_domain,
@@ -2221,14 +2232,12 @@ int mem_sharing_memop(XEN_GUEST_HANDLE_PARAM(xen_mem_sharing_op_t) arg)
             goto out;
         }
 
-        rc = fork(d, pd);
+        rc = fork(d, pd, mso.u.fork.flags);
 
         if ( rc == -ERESTART )
             rc = hypercall_create_continuation(__HYPERVISOR_memory_op,
                                                "lh", XENMEM_sharing_op,
                                                arg);
-        else if ( !rc && (mso.u.fork.flags & XENMEM_FORK_BLOCK_INTERRUPTS) )
-            d->arch.hvm.mem_sharing.block_interrupts = true;
 
         rcu_unlock_domain(pd);
         break;
index a1a0f0233a273833892cccab8ad7b87da4f8ef70..d44c256b3c1e516d9522d67d29c0f42bbd64ac72 100644 (file)
@@ -543,10 +543,10 @@ struct xen_mem_sharing_op {
         } debug;
         struct mem_sharing_op_fork {      /* OP_FORK */
             domid_t parent_domain;        /* IN: parent's domain id */
-/* Only makes sense for short-lived forks */
+/* These flags only makes sense for short-lived forks */
 #define XENMEM_FORK_WITH_IOMMU_ALLOWED (1u << 0)
-/* Only makes sense for short-lived forks */
 #define XENMEM_FORK_BLOCK_INTERRUPTS   (1u << 1)
+#define XENMEM_FORK_EMPTY_P2M          (1u << 2)
             uint16_t flags;               /* IN: optional settings */
             uint32_t pad;                 /* Must be set to 0 */
         } fork;