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

[xen master] domctl: Handle some of XEN_DOMCTL_shadow_op without the domctl lock



commit ffe7a07597b43c77245d7acf3e57d8a2ed0896cf
Author:     Ross Lagerwall <ross.lagerwall@xxxxxxxxxx>
AuthorDate: Tue Jun 9 16:15:28 2026 +0100
Commit:     Roger Pau Monne <roger.pau@xxxxxxxxxx>
CommitDate: Wed Jun 10 14:54:50 2026 +0200

    domctl: Handle some of XEN_DOMCTL_shadow_op without the domctl lock
    
    Handle XEN_DOMCTL_SHADOW_OP_{CLEAN,PEEK} without taking the domctl lock.
    This is safe because for these subops, the paging lock is mostly held
    which prevents it from operating concurrently on the same domain. There
    are some parts that are called without the paging lock held:
    
    * hvm_mapped_guest_frames_mark_dirty() - The function itself takes a
      spinlock so is protected from concurrent calls. In any case, it will
      mark all the pages dirty as required.
    
    * domain_{,un}pause() - The toolstack cannot {,un}pause the domain while
      in paging_log_dirty_op() because the toolstack's pause/unpause ops have
      a separate ref count.
    
    * p2m_flush_hardware_cached_dirty() - This is called elsewhere without
      the domctl lock held so holding it wouldn't achieve anything. It
      should be fine as long as it is called at least once.
    
    * log_dirty.ops->clean() - If the callback is hap_clean_dirty_bitmap(),
      then it will hold the p2m lock while modifying the table. If the
      callback is sh_clean_dirty_bitmap(), it will hold the paging lock
      while modifying the table. In both cases, this is OK.
    
    Signed-off-by: Ross Lagerwall <ross.lagerwall@xxxxxxxxxx>
    Reviewed-by: Roger Pau Monné <roger.pau@xxxxxxxxxx>
    Release-Acked-by: Oleksii Kurochko <oleksii.kurochko@xxxxxxxxx>
---
 xen/arch/x86/mm/paging.c |  8 ++++++--
 xen/common/domctl.c      | 13 +++++++++++++
 2 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/xen/arch/x86/mm/paging.c b/xen/arch/x86/mm/paging.c
index 1a58228086..bfb5b423a0 100644
--- a/xen/arch/x86/mm/paging.c
+++ b/xen/arch/x86/mm/paging.c
@@ -746,11 +746,15 @@ long do_paging_domctl_cont(
     ret = xsm_domctl(XSM_OTHER, d, &op);
     if ( !ret )
     {
-        if ( domctl_lock_acquire() )
+        bool lock = !(op.u.shadow_op.op == XEN_DOMCTL_SHADOW_OP_CLEAN ||
+                      op.u.shadow_op.op == XEN_DOMCTL_SHADOW_OP_PEEK);
+
+        if ( !lock || domctl_lock_acquire() )
         {
             ret = paging_domctl(d, &op.u.shadow_op, u_domctl, 1);
 
-            domctl_lock_release();
+            if ( lock )
+                domctl_lock_release();
         }
         else
             ret = -ERESTART;
diff --git a/xen/common/domctl.c b/xen/common/domctl.c
index 35144d95b8..6f71a68d51 100644
--- a/xen/common/domctl.c
+++ b/xen/common/domctl.c
@@ -546,6 +546,19 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) 
u_domctl)
         /* Other sub-ops handled further down. */
         break;
 
+    case XEN_DOMCTL_shadow_op:
+        if ( op->u.shadow_op.op == XEN_DOMCTL_SHADOW_OP_CLEAN ||
+             op->u.shadow_op.op == XEN_DOMCTL_SHADOW_OP_PEEK )
+        {
+            ret = xsm_domctl(XSM_OTHER, d, op);
+            if ( ret )
+                goto domctl_out_unlock_domonly;
+
+            ret = arch_do_domctl(op, d, u_domctl);
+            goto domctl_out_unlock_domonly;
+        }
+        break;
+
     case XEN_DOMCTL_get_device_group:
         ret = iommu_do_domctl(op, d, u_domctl);
         goto domctl_out_unlock_domonly;
--
generated by git-patchbot for /home/xen/git/xen.git#master



 


Rackspace

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