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

[PATCH] x86: Add Kconfig option for log-dirty tracking


  • To: <xen-devel@xxxxxxxxxxxxxxxxxxxx>
  • From: Alejandro Vallejo <alejandro.garciavallejo@xxxxxxx>
  • Date: Mon, 9 Feb 2026 11:31:15 +0100
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 165.204.84.17) smtp.rcpttodomain=lists.xenproject.org smtp.mailfrom=amd.com; dmarc=pass (p=quarantine sp=quarantine pct=100) action=none header.from=amd.com; dkim=none (message not signed); arc=none (0)
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=Qeeq1xMi1fi4C++dxIjciOIE3wFIWwG27Soi5ZlWspE=; b=J8rY+sR5is0tLuBgDvvHODc+gNE6zWbrH/kL7V+rHpNctSixh4BNVhvNRym2j2wnmPXwHYD5CSyC/KFznn2htk7HALKi2PPILoYWobSS7kc1IbeJjCY1gtVq5u1TT93ZDRfChuYxHPXQbmsgpXRp8AR4sP92jJbc8oPHiU92Clcg4tSFRF1AIAIUgZridmATDItEwTEOYgCnIzWtlC9rsYoOrf/j1RezwlKroCFa8Sdryhl+HvuE1HP/uQn7VXix0a/y1tS73cQsSXV2T5/5cmKiGzLUZP9gKmCRY79zS2o0g4/B661ohsenaFGS023ZgElXmhid2DOyfmfyGLZ5bQ==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=a+JytafSwklHj7MW80gsBEId3sDiFrrlLYZLmr+NE6pJhNAkd3dYIXNHG6Q2VVucHLTW12Gtj5PAFVhOFxK7xQPS3OjWZ0E1xWxEdxRd89AQl/SuO2Zd7qlsZNyii8+3lI3rFVzWoKjvjY2vcsVn/pEfOsY35QnCrJ4ybwkBM5G0Y+m2TLV7yDCNM43lcoTlhzw7VCDNBlSbtjrcDP3hgUmCOW3Oz3IglziuEyXqV4AzaaxyLmdsQVaDHQ/n1bQm8wzp/9y6KaIAYJhl2MHBxDaG2njkCKpINazYRRlNmLCYgcLELvCXEEB+/V/lh3A/X7oOyYp/aRbXkGuG99/6qQ==
  • Cc: Alejandro Vallejo <alejandro.garciavallejo@xxxxxxx>, Jan Beulich <jbeulich@xxxxxxxx>, Andrew Cooper <andrew.cooper3@xxxxxxxxxx>, Roger Pau Monné <roger.pau@xxxxxxxxxx>, Anthony PERARD <anthony.perard@xxxxxxxxxx>, Michal Orzel <michal.orzel@xxxxxxx>, "Julien Grall" <julien@xxxxxxx>, Stefano Stabellini <sstabellini@xxxxxxxxxx>
  • Delivery-date: Mon, 09 Feb 2026 10:31:54 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

Creates a CONFIG_LOG_DIRTY Kconfig option with the following effects
when disabled:

  * paging_domctl{,_cont} return -EOPNOTSUPP (XEN_DOMCTL_shadow_op).
  * VRAM tracking via DMOP returns EOPNOTSUPP.

And compiles out all log-dirty tracking infra.

Signed-off-by: Alejandro Vallejo <alejandro.garciavallejo@xxxxxxx>
---
RFC for the Kconfig help message.
---
 xen/arch/x86/Kconfig              |  9 +++++++++
 xen/arch/x86/domctl.c             |  8 ++++----
 xen/arch/x86/hvm/dm.c             |  3 +++
 xen/arch/x86/include/asm/domain.h |  2 ++
 xen/arch/x86/include/asm/p2m.h    |  2 ++
 xen/arch/x86/include/asm/paging.h |  8 +++-----
 xen/arch/x86/mm/hap/hap.c         | 22 +++++++++++++---------
 xen/arch/x86/mm/p2m.c             |  2 ++
 xen/arch/x86/mm/paging.c          |  2 ++
 xen/include/hypercall-defs.c      |  4 ++--
 10 files changed, 42 insertions(+), 20 deletions(-)

diff --git a/xen/arch/x86/Kconfig b/xen/arch/x86/Kconfig
index 61f58aa829..fbf044aa4d 100644
--- a/xen/arch/x86/Kconfig
+++ b/xen/arch/x86/Kconfig
@@ -146,6 +146,7 @@ config XEN_IBT
 config SHADOW_PAGING
        bool "Shadow Paging"
        default !PV_SHIM_EXCLUSIVE
+       select LOG_DIRTY
        depends on PV || HVM
        help
 
@@ -166,6 +167,14 @@ config SHADOW_PAGING
 config PAGING
        def_bool HVM || SHADOW_PAGING
 
+config LOG_DIRTY
+       bool "Log-dirty page tracking" if EXPERT
+       depends on PAGING
+       default !PV_SHIM_EXCLUSIVE
+       help
+         Enable log-dirty infrastructure so Xen can track domain memory writes 
and
+         the dirty state of VRAM for device models and live migrations.
+
 config BIGMEM
        bool "big memory support"
        default n
diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c
index d9521808dc..61d43a21d0 100644
--- a/xen/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -220,15 +220,15 @@ long arch_do_domctl(
     {
 
     case XEN_DOMCTL_shadow_op:
-#ifdef CONFIG_PAGING
+        ret = -EOPNOTSUPP;
+        if ( !IS_ENABLED(CONFIG_LOG_DIRTY) )
+            break;
+
         ret = paging_domctl(d, &domctl->u.shadow_op, u_domctl, 0);
         if ( ret == -ERESTART )
             return hypercall_create_continuation(
                        __HYPERVISOR_paging_domctl_cont, "h", u_domctl);
         copyback = true;
-#else
-        ret = -EOPNOTSUPP;
-#endif
         break;
 
     case XEN_DOMCTL_ioport_permission:
diff --git a/xen/arch/x86/hvm/dm.c b/xen/arch/x86/hvm/dm.c
index 3b53471af0..94216aecc2 100644
--- a/xen/arch/x86/hvm/dm.c
+++ b/xen/arch/x86/hvm/dm.c
@@ -48,6 +48,9 @@ static int track_dirty_vram(struct domain *d, xen_pfn_t 
first_pfn,
                             unsigned int nr_frames,
                             const struct xen_dm_op_buf *buf)
 {
+    if ( !IS_ENABLED(CONFIG_LOG_DIRTY) )
+        return -EOPNOTSUPP;
+
     if ( nr_frames > (GB(1) >> PAGE_SHIFT) )
         return -EINVAL;
 
diff --git a/xen/arch/x86/include/asm/domain.h 
b/xen/arch/x86/include/asm/domain.h
index 94b0cf7f1d..f09c13909f 100644
--- a/xen/arch/x86/include/asm/domain.h
+++ b/xen/arch/x86/include/asm/domain.h
@@ -226,7 +226,9 @@ struct paging_domain {
     unsigned int            p2m_pages;    /* number of pages allocated to p2m 
*/
 
     /* log dirty support */
+#ifdef CONFIG_LOG_DIRTY
     struct log_dirty_domain log_dirty;
+#endif /* CONFIG_LOG_DIRTY */
 
     /* preemption handling */
     struct {
diff --git a/xen/arch/x86/include/asm/p2m.h b/xen/arch/x86/include/asm/p2m.h
index 9016e88411..3c2dcacfa5 100644
--- a/xen/arch/x86/include/asm/p2m.h
+++ b/xen/arch/x86/include/asm/p2m.h
@@ -253,9 +253,11 @@ struct p2m_domain {
                                     bool *sve);
     int                (*recalc)(struct p2m_domain *p2m,
                                  unsigned long gfn);
+#ifdef CONFIG_LOG_DIRTY
     void               (*enable_hardware_log_dirty)(struct p2m_domain *p2m);
     void               (*disable_hardware_log_dirty)(struct p2m_domain *p2m);
     void               (*flush_hardware_cached_dirty)(struct p2m_domain *p2m);
+#endif /* CONFIG_LOG_DIRTY */
     void               (*change_entry_type_global)(struct p2m_domain *p2m,
                                                    p2m_type_t ot,
                                                    p2m_type_t nt);
diff --git a/xen/arch/x86/include/asm/paging.h 
b/xen/arch/x86/include/asm/paging.h
index 291ab386e8..980cdfa455 100644
--- a/xen/arch/x86/include/asm/paging.h
+++ b/xen/arch/x86/include/asm/paging.h
@@ -55,12 +55,9 @@
 #define PG_translate   0
 #define PG_external    0
 #endif
-#if defined(CONFIG_PAGING) && !defined(CONFIG_PV_SHIM_EXCLUSIVE)
 /* Enable log dirty mode */
-#define PG_log_dirty   (XEN_DOMCTL_SHADOW_ENABLE_LOG_DIRTY << PG_mode_shift)
-#else
-#define PG_log_dirty   0
-#endif
+#define PG_log_dirty   IS_ENABLED(CONFIG_LOG_DIRTY) * \
+                       (XEN_DOMCTL_SHADOW_ENABLE_LOG_DIRTY << PG_mode_shift)
 
 /* All paging modes. */
 #define PG_MASK (PG_refcounts | PG_log_dirty | PG_translate | PG_external)
@@ -174,6 +171,7 @@ static inline void paging_log_dirty_init(struct domain *d,
                                          const struct log_dirty_ops *ops) {}
 static inline void paging_mark_dirty(struct domain *d, mfn_t gmfn) {}
 static inline void paging_mark_pfn_dirty(struct domain *d, pfn_t pfn) {}
+static inline void paging_mark_pfn_clean(struct domain *d, pfn_t pfn) {}
 static inline bool paging_mfn_is_dirty(struct domain *d, mfn_t gmfn) { return 
false; }
 
 #endif /* PG_log_dirty */
diff --git a/xen/arch/x86/mm/hap/hap.c b/xen/arch/x86/mm/hap/hap.c
index a337752bf4..21672db011 100644
--- a/xen/arch/x86/mm/hap/hap.c
+++ b/xen/arch/x86/mm/hap/hap.c
@@ -50,7 +50,7 @@ struct hap_dirty_vram {
  * calling p2m_log_dirty_range(), which interrogates each vram
  * page's p2m type looking for pages that have been made writable.
  */
-
+#ifdef CONFIG_LOG_DIRTY
 int hap_track_dirty_vram(struct domain *d,
                          unsigned long begin_pfn,
                          unsigned int nr_frames,
@@ -161,6 +161,7 @@ out:
 
     return rc;
 }
+#endif /* CONFIG_LOG_DIRTY */
 
 /************************************************/
 /*            HAP LOG DIRTY SUPPORT             */
@@ -440,14 +441,17 @@ static bool cf_check flush_tlb(const unsigned long 
*vcpu_bitmap);
 
 void hap_domain_init(struct domain *d)
 {
-    static const struct log_dirty_ops hap_ops = {
-        .enable  = hap_enable_log_dirty,
-        .disable = hap_disable_log_dirty,
-        .clean   = hap_clean_dirty_bitmap,
-    };
-
-    /* Use HAP logdirty mechanism. */
-    paging_log_dirty_init(d, &hap_ops);
+    if ( IS_ENABLED(CONFIG_LOG_DIRTY) )
+    {
+        static const struct log_dirty_ops hap_ops = {
+            .enable  = hap_enable_log_dirty,
+            .disable = hap_disable_log_dirty,
+            .clean   = hap_clean_dirty_bitmap,
+        };
+
+        /* Use HAP logdirty mechanism. */
+        paging_log_dirty_init(d, &hap_ops);
+    }
 
     d->arch.paging.update_paging_modes = hap_update_paging_modes;
     d->arch.paging.flush_tlb           = flush_tlb;
diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
index e915da26a8..373382c28c 100644
--- a/xen/arch/x86/mm/p2m.c
+++ b/xen/arch/x86/mm/p2m.c
@@ -236,6 +236,7 @@ struct ioreq_server *p2m_get_ioreq_server(struct domain *d,
     return s;
 }
 
+#ifdef CONFIG_LOG_DIRTY
 void p2m_enable_hardware_log_dirty(struct domain *d)
 {
     struct p2m_domain *p2m = p2m_get_hostp2m(d);
@@ -263,6 +264,7 @@ void p2m_flush_hardware_cached_dirty(struct domain *d)
         p2m_unlock(p2m);
     }
 }
+#endif /* CONFIG_LOG_DIRTY */
 
 /*
  * Force a synchronous P2M TLB flush if a deferred flush is pending.
diff --git a/xen/arch/x86/mm/paging.c b/xen/arch/x86/mm/paging.c
index 2396f81ad5..13ee137db9 100644
--- a/xen/arch/x86/mm/paging.c
+++ b/xen/arch/x86/mm/paging.c
@@ -623,10 +623,12 @@ int paging_domain_init(struct domain *d)
     INIT_PAGE_LIST_HEAD(&d->arch.paging.freelist);
     mm_lock_init(&d->arch.paging.lock);
 
+#ifdef CONFIG_LOG_DIRTY
     /* This must be initialized separately from the rest of the
      * log-dirty init code as that can be called more than once and we
      * don't want to leak any active log-dirty bitmaps */
     d->arch.paging.log_dirty.top = INVALID_MFN;
+#endif /* CONFIG_LOG_DIRTY */
 
     /*
      * Shadow pagetables are the default, but we will use
diff --git a/xen/include/hypercall-defs.c b/xen/include/hypercall-defs.c
index 63755bb8df..be7ed832be 100644
--- a/xen/include/hypercall-defs.c
+++ b/xen/include/hypercall-defs.c
@@ -194,7 +194,7 @@ dm_op(domid_t domid, unsigned int nr_bufs, xen_dm_op_buf_t 
*bufs)
 #ifdef CONFIG_SYSCTL
 sysctl(xen_sysctl_t *u_sysctl)
 #endif
-#if defined(CONFIG_X86) && defined(CONFIG_PAGING) && 
!defined(CONFIG_PV_SHIM_EXCLUSIVE)
+#if defined(CONFIG_LOG_DIRTY)
 paging_domctl_cont(xen_domctl_t *u_domctl)
 #endif
 #ifndef CONFIG_PV_SHIM_EXCLUSIVE
@@ -292,7 +292,7 @@ dm_op                              compat   do       compat 
  do       do
 hypfs_op                           do       do       do       do       do
 #endif
 mca                                do       do       -        -        -
-#if defined(CONFIG_X86) && defined(CONFIG_PAGING) && 
!defined(CONFIG_PV_SHIM_EXCLUSIVE)
+#if defined(CONFIG_LOG_DIRTY)
 paging_domctl_cont                 do       do       do       do       -
 #endif
 

base-commit: 1ee8b11c1106dca6b8fe0d54c0e79146bb6545f0
-- 
2.43.0




 


Rackspace

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