[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v15 08/10] x86/shadow: make log-dirty mode enable/disable properly preemptable


  • To: "xen-devel@xxxxxxxxxxxxxxxxxxxx" <xen-devel@xxxxxxxxxxxxxxxxxxxx>
  • From: Jan Beulich <jbeulich@xxxxxxxx>
  • Date: Tue, 28 Jul 2026 16:23:18 +0200
  • Authentication-results: eu.smtp.expurgate.cloud; dkim=pass header.s=google header.d=suse.com header.i="@suse.com" header.h="Content-Transfer-Encoding:Content-Type:In-Reply-To:Autocrypt:Content-Language:References:Cc:To:From:Subject:User-Agent:MIME-Version:Date:Message-ID"
  • Autocrypt: addr=jbeulich@xxxxxxxx; keydata= xsDiBFk3nEQRBADAEaSw6zC/EJkiwGPXbWtPxl2xCdSoeepS07jW8UgcHNurfHvUzogEq5xk hu507c3BarVjyWCJOylMNR98Yd8VqD9UfmX0Hb8/BrA+Hl6/DB/eqGptrf4BSRwcZQM32aZK 7Pj2XbGWIUrZrd70x1eAP9QE3P79Y2oLrsCgbZJfEwCgvz9JjGmQqQkRiTVzlZVCJYcyGGsD /0tbFCzD2h20ahe8rC1gbb3K3qk+LpBtvjBu1RY9drYk0NymiGbJWZgab6t1jM7sk2vuf0Py O9Hf9XBmK0uE9IgMaiCpc32XV9oASz6UJebwkX+zF2jG5I1BfnO9g7KlotcA/v5ClMjgo6Gl MDY4HxoSRu3i1cqqSDtVlt+AOVBJBACrZcnHAUSuCXBPy0jOlBhxPqRWv6ND4c9PH1xjQ3NP nxJuMBS8rnNg22uyfAgmBKNLpLgAGVRMZGaGoJObGf72s6TeIqKJo/LtggAS9qAUiuKVnygo 3wjfkS9A3DRO+SpU7JqWdsveeIQyeyEJ/8PTowmSQLakF+3fote9ybzd880fSmFuIEJldWxp Y2ggPGpiZXVsaWNoQHN1c2UuY29tPsJgBBMRAgAgBQJZN5xEAhsDBgsJCAcDAgQVAggDBBYC AwECHgECF4AACgkQoDSui/t3IH4J+wCfQ5jHdEjCRHj23O/5ttg9r9OIruwAn3103WUITZee e7Sbg12UgcQ5lv7SzsFNBFk3nEQQCACCuTjCjFOUdi5Nm244F+78kLghRcin/awv+IrTcIWF hUpSs1Y91iQQ7KItirz5uwCPlwejSJDQJLIS+QtJHaXDXeV6NI0Uef1hP20+y8qydDiVkv6l IreXjTb7DvksRgJNvCkWtYnlS3mYvQ9NzS9PhyALWbXnH6sIJd2O9lKS1Mrfq+y0IXCP10eS FFGg+Av3IQeFatkJAyju0PPthyTqxSI4lZYuJVPknzgaeuJv/2NccrPvmeDg6Coe7ZIeQ8Yj t0ARxu2xytAkkLCel1Lz1WLmwLstV30g80nkgZf/wr+/BXJW/oIvRlonUkxv+IbBM3dX2OV8 AmRv1ySWPTP7AAMFB/9PQK/VtlNUJvg8GXj9ootzrteGfVZVVT4XBJkfwBcpC/XcPzldjv+3 HYudvpdNK3lLujXeA5fLOH+Z/G9WBc5pFVSMocI71I8bT8lIAzreg0WvkWg5V2WZsUMlnDL9 mpwIGFhlbM3gfDMs7MPMu8YQRFVdUvtSpaAs8OFfGQ0ia3LGZcjA6Ik2+xcqscEJzNH+qh8V m5jjp28yZgaqTaRbg3M/+MTbMpicpZuqF4rnB0AQD12/3BNWDR6bmh+EkYSMcEIpQmBM51qM EKYTQGybRCjpnKHGOxG0rfFY1085mBDZCH5Kx0cl0HVJuQKC+dV2ZY5AqjcKwAxpE75MLFkr wkkEGBECAAkFAlk3nEQCGwwACgkQoDSui/t3IH7nnwCfcJWUDUFKdCsBH/E5d+0ZnMQi+G0A nAuWpQkjM1ASeQwSHEeAWPgskBQL
  • Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>, Tim Deegan <tim@xxxxxxx>
  • Delivery-date: Tue, 28 Jul 2026 14:23:24 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

Their calls to shadow_set_allocation() are the last missing piece.

While it may seem a little odd, it actually turns out easier to deal
with the continuation a level up from where the need for it was first
recognized.

Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
---
I think the point was raised before: It's questionable whether
shadow_one_bit_enable(), upon error, should bring the allocation back
down to zero. This is going to be especially bad for a domain which
previously had shadow enabled already (which could be HVM or L1TF-
affected PV). Even in shadow_one_bit_disable() it's not clear this is
the best possible behavior - the pool may have been set to something
larger than the default by the admin. For now I'm maintaining prior
behavior, but of course things would end up simpler if we could just get
rid of those set-to-zero operations (and then perhaps also on
shadow_enable()'s similar error path); the possible caveat there would
be that overall memory consumption may then appear to grow for people
monitoring a system.

Originally I was considering to further qualify the
d->arch.paging.preempt.drop_allocation checks by passing further down
the "resuming" flag, but for a well-behaved tool stack (which allows one
shadow-op to finish before starting another one) there shouldn't be a
difference. Thoughts?
---
v14: New.

--- a/xen/arch/x86/include/asm/domain.h
+++ b/xen/arch/x86/include/asm/domain.h
@@ -236,6 +236,7 @@ struct paging_domain {
     struct {
         const struct domain *dom;
         unsigned int op;
+        bool drop_allocation:1;
         union {
             struct {
                 unsigned long done:PADDR_BITS - PAGE_SHIFT;
--- a/xen/arch/x86/mm/paging.c
+++ b/xen/arch/x86/mm/paging.c
@@ -215,9 +215,10 @@ static int paging_log_dirty_enable(struc
 
     paging_lock(d);
 
-    if ( d->arch.paging.preempt.dom &&
-         (d->arch.paging.preempt.dom != current->domain ||
-          d->arch.paging.preempt.op != op) )
+    if ( !d->arch.paging.preempt.dom )
+        d->arch.paging.preempt.drop_allocation = false;
+    else if ( d->arch.paging.preempt.dom != current->domain ||
+              d->arch.paging.preempt.op != op )
     {
         paging_unlock(d);
         if ( !resuming )
@@ -259,9 +260,10 @@ static int paging_log_dirty_disable(stru
 
     paging_lock(d);
 
-    if ( d->arch.paging.preempt.dom &&
-         (d->arch.paging.preempt.dom != current->domain ||
-          d->arch.paging.preempt.op != XEN_DOMCTL_SHADOW_OP_OFF) )
+    if ( !d->arch.paging.preempt.dom )
+        d->arch.paging.preempt.drop_allocation = false;
+    else if ( d->arch.paging.preempt.dom != current->domain ||
+              d->arch.paging.preempt.op != XEN_DOMCTL_SHADOW_OP_OFF )
     {
         paging_unlock(d);
         if ( !resuming )
--- a/xen/arch/x86/mm/shadow/common.c
+++ b/xen/arch/x86/mm/shadow/common.c
@@ -2440,12 +2440,22 @@ static int shadow_one_bit_enable(struct
 
     if ( d->arch.paging.total_pages < sh_min_allocation(d) )
     {
+        bool preempted = false;
+
         /* Init the shadow memory allocation if the user hasn't done so */
-        if ( shadow_set_allocation(d, 1, NULL) != 0 )
+        if ( shadow_set_allocation(d, 1,
+                                   mode & PG_log_dirty ? &preempted
+                                                       : NULL) != 0 )
         {
-            shadow_set_allocation(d, 0, NULL);
-            return -ENOMEM;
+            shadow_set_allocation(d, 0,
+                                  mode & PG_log_dirty ? &preempted : NULL);
+            if ( !preempted )
+                return -ENOMEM;
+            d->arch.paging.preempt.drop_allocation = true;
         }
+
+        if ( preempted )
+            return -ERESTART;
     }
 
     /* Allow p2m and log-dirty code to borrow shadow memory */
@@ -2484,6 +2494,8 @@ static int shadow_one_bit_disable(struct
     sh_new_mode(d, mode);
     if ( d->arch.paging.mode == 0 )
     {
+        bool preempted = false;
+
         /* Get this domain off shadows */
         SHADOW_PRINTK("un-shadowing of domain %u starts."
                        "  Shadow pages total = %u, free = %u, p2m=%u\n",
@@ -2511,8 +2523,16 @@ static int shadow_one_bit_disable(struct
         }
 
         /* Pull down the memory allocation */
-        if ( shadow_set_allocation(d, 0, NULL) != 0 )
+        if ( shadow_set_allocation(d, 0,
+                                   mode & PG_log_dirty ? &preempted
+                                                       : NULL) != 0 )
             BUG(); /* In fact, we will have BUG()ed already */
+        if ( preempted )
+        {
+            d->arch.paging.preempt.drop_allocation = true;
+            return -ERESTART;
+        }
+
         shadow_hash_teardown(d);
         SHADOW_PRINTK("un-shadowing of domain %u done."
                        "  Shadow pages total = %u, free = %u, p2m=%u\n",
@@ -2558,14 +2578,20 @@ static int shadow_test_disable(struct do
  */
 static int cf_check sh_enable_log_dirty(struct domain *d)
 {
+    bool preempted = false;
     int ret;
 
     ASSERT(paging_locked_by_me(d));
 
-    if ( shadow_mode_enabled(d) )
+    if ( d->arch.paging.preempt.drop_allocation )
     {
-        bool preempted = false;
+        shadow_set_allocation(d, 0, &preempted);
 
+        return preempted ? -ERESTART : -ENOMEM;
+    }
+
+    if ( shadow_mode_enabled(d) )
+    {
         /*
          * This domain already has some shadows: need to clear them out
          * of the way to make sure that all references to guest memory are
@@ -2598,6 +2624,21 @@ static int cf_check sh_disable_log_dirty
 
     ASSERT(paging_locked_by_me(d));
 
+    if ( d->arch.paging.preempt.drop_allocation )
+    {
+        shadow_set_allocation(d, 0, &preempted);
+
+        if ( preempted )
+            return -ERESTART;
+
+        shadow_hash_teardown(d);
+        SHADOW_PRINTK("un-shadowing of domain %u done."
+                       "  Shadow pages total = %u, free = %u, p2m=%u\n",
+                       d->domain_id, d->arch.paging.total_pages,
+                       d->arch.paging.free_pages, d->arch.paging.p2m_pages);
+        return 0;
+    }
+
     /*
      * Limit the amount of work to do from sh_detach_old_tables() (called from
      * shadow_one_bit_disable() via sh_new_mode() -> sh_update_paging_modes()),




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.