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@citrix.com>
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
Release-Acked-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
This commit is contained in:
Ross Lagerwall authored and Roger Pau Monne committed 2026-06-10 14:54:50 +02:00
1 parent 261a2f51df
commit ffe7a07597
2 files changed
+19 -2

No files matched your search

+6 -2
View File
@@ -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;
+13
View File
@@ -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;
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.