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

Alejandro Vallejo posted 1 patch an hour ago
Patches applied successfully (tree, apply log)
git fetch https://gitlab.com/xen-project/patchew/xen tags/patchew/20260209103118.5885-1-alejandro.garciavallejo@amd.com
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(-)
[PATCH] x86: Add Kconfig option for log-dirty tracking
Posted by Alejandro Vallejo an hour ago
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@amd.com>
---
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