From 24a179c25897dbfaa015ff62940648877d9d50ef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hyman=20Huang=28=E9=BB=84=E5=8B=87=29?=
 <huangy81@chinatelecom.cn>
Date: Tue, 23 Nov 2021 09:36:58 -0500
Subject: [PATCH] qemu: support dirty ring feature
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Dirty ring feature was introduced in qemu-6.1.0, this patch
add the corresponding feature named 'dirty-ring', which enable
dirty ring feature when starting VM.

To enable the feature, the following XML needs to be added to
the guest's domain description:

<features>
   <kvm>
     <dirty-ring state='on' size='xxx'>
   </kvm>
</features>

If property "state=on", property "size" must be specified, which
should be power of 2 and range in [1024, 65526].

Signed-off-by: Hyman Huang(榛勫媷) <huangy81@chinatelecom.cn>
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Shaokun Wei <weishaokun@kylinos.cn>
---
 docs/formatdomain.html.in                     |  7 ++++
 docs/schemas/domaincommon.rng                 | 10 +++++
 src/conf/domain_conf.c                        | 42 +++++++++++++++++++
 src/conf/domain_conf.h                        |  3 ++
 src/qemu/qemu_command.c                       |  3 ++
 tests/qemuxml2argvdata/kvm-features-off.xml   |  1 +
 tests/qemuxml2argvdata/kvm-features.xml       |  1 +
 tests/qemuxml2xmloutdata/kvm-features-off.xml |  1 +
 tests/qemuxml2xmloutdata/kvm-features.xml     |  1 +
 9 files changed, 69 insertions(+)

diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 6e51c3bac9..0521a847d8 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -2055,6 +2055,7 @@
   &lt;kvm&gt;
     &lt;hidden state='on'/&gt;
     &lt;hint-dedicated state='on'/&gt;
+    &lt;dirty-ring state='on' size='4096'/&gt;
   &lt;/kvm&gt;
   &lt;pvspinlock state='on'/&gt;
   &lt;gic version='2'/&gt;
@@ -2235,6 +2236,12 @@
           <td>on, off</td>
           <td><span class="since">5.7.0 (QEMU 2.12.0)</span></td>
         </tr>
+        <tr>
+          <td>dirty-ring</td>
+          <td>Enable dirty ring feature</td>
+          <td>on, off; size - must be power of 2, range [1024,65536]</td>
+          <td><span class="since">8.0.0 (QEMU 6.1)</span></td>
+        </tr>
       </table>
       </dd>
       <dt><code>pmu</code></dt>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 764f826df4..e3b51d333c 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -6327,6 +6327,16 @@
             <ref name="featurestate"/>
           </element>
         </optional>
+        <optional>
+          <element name="dirty-ring">
+            <ref name="featurestate"/>
+            <optional>
+              <attribute name="size">
+                <data type="unsignedInt"/>
+              </attribute>
+            </optional>
+          </element>
+        </optional>
       </interleave>
     </element>
   </define>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index e94ae4ea17..cf807c7747 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -205,6 +205,7 @@ VIR_ENUM_IMPL(virDomainKVM,
               VIR_DOMAIN_KVM_LAST,
               "hidden",
               "hint-dedicated",
+              "dirty-ring",
 );
 
 VIR_ENUM_IMPL(virDomainMsrsUnknown,
@@ -20620,6 +20621,22 @@ virDomainFeaturesKVMDefParse(virDomainDef *def,
 
         kvm->features[feature] = value;
 
+        /* dirty ring feature should parse size property */
+        if (feature == VIR_DOMAIN_KVM_DIRTY_RING &&
+            value == VIR_TRISTATE_SWITCH_ON) {
+            if (virXMLPropUInt(node, "size", 0, VIR_XML_PROP_REQUIRED,
+                               &kvm->dirty_ring_size) < 0) {
+                return -1;
+            }
+            if (!VIR_IS_POW2(kvm->dirty_ring_size) ||
+                kvm->dirty_ring_size < 1024 ||
+                kvm->dirty_ring_size > 65536) {
+                virReportError(VIR_ERR_XML_ERROR, "%s",
+                               _("dirty ring must be power of 2 and ranges [1024, 65536]"));
+                return -1;
+            }
+        }
+
         node = xmlNextElementSibling(node);
     }
 
@@ -23590,6 +23607,7 @@ virDomainDefFeaturesCheckABIStability(virDomainDefPtr src,
             switch ((virDomainKVM) i) {
             case VIR_DOMAIN_KVM_HIDDEN:
             case VIR_DOMAIN_KVM_DEDICATED:
+            case VIR_DOMAIN_KVM_DIRTY_RING:
                 if (src->kvm_features->features[i] != dst->kvm_features->features[i]) {
                     virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                    _("State of KVM feature '%s' differs: "
@@ -23607,6 +23625,16 @@ virDomainDefFeaturesCheckABIStability(virDomainDefPtr src,
                 break;
             }
         }
+
+        if (src->kvm_features->dirty_ring_size != dst->kvm_features->dirty_ring_size) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                           _("dirty ring size of KVM feature '%s' differs: "
+                             "source: '%d', destination: '%d'"),
+                           virDomainKVMTypeToString(i),
+                           src->kvm_features->dirty_ring_size,
+                           dst->kvm_features->dirty_ring_size);
+            return false;
+        }
     }
 
     /* smm */
@@ -29214,6 +29242,20 @@ virDomainDefFormatFeatures(virBufferPtr buf,
                                               def->kvm_features->features[j]));
                     break;
 
+                case VIR_DOMAIN_KVM_DIRTY_RING:
+                    if (def->kvm_features->features[j] != VIR_TRISTATE_SWITCH_ABSENT) {
+                        virBufferAsprintf(&childBuf, "<%s state='%s'",
+                                          virDomainKVMTypeToString(j),
+                                          virTristateSwitchTypeToString(def->kvm_features->features[j]));
+                        if (def->kvm_features->dirty_ring_size > 0) {
+                            virBufferAsprintf(&childBuf, " size='%d'/>\n",
+                                              def->kvm_features->dirty_ring_size);
+                        } else {
+                            virBufferAddLit(&childBuf, "/>\n");
+                        }
+                    }
+                    break;
+
                 /* coverity[dead_error_begin] */
                 case VIR_DOMAIN_KVM_LAST:
                     break;
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index d75d06d7b8..7419bf8d7e 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1840,6 +1840,7 @@ typedef enum {
 typedef enum {
     VIR_DOMAIN_KVM_HIDDEN = 0,
     VIR_DOMAIN_KVM_DEDICATED,
+    VIR_DOMAIN_KVM_DIRTY_RING,
 
     VIR_DOMAIN_KVM_LAST
 } virDomainKVM;
@@ -2300,6 +2301,8 @@ struct _virDomainResctrlDef {
 typedef struct _virDomainFeatureKVM virDomainFeatureKVM;
 struct _virDomainFeatureKVM {
     int features[VIR_DOMAIN_KVM_LAST];
+
+    unsigned int dirty_ring_size; /* size of dirty ring for each vCPU, no units */
 };
 
 
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index ed843315dc..b879f7f39a 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -6920,6 +6920,9 @@ qemuBuildCpuCommandLine(virCommandPtr cmd,
                     virBufferAddLit(&buf, ",kvm-hint-dedicated=on");
                 break;
 
+            case VIR_DOMAIN_KVM_DIRTY_RING:
+                break;
+
             /* coverity[dead_error_begin] */
             case VIR_DOMAIN_KVM_LAST:
                 break;
diff --git a/tests/qemuxml2argvdata/kvm-features-off.xml b/tests/qemuxml2argvdata/kvm-features-off.xml
index 21d492c8b9..f53e31db6b 100644
--- a/tests/qemuxml2argvdata/kvm-features-off.xml
+++ b/tests/qemuxml2argvdata/kvm-features-off.xml
@@ -13,6 +13,7 @@
     <kvm>
       <hidden state='off'/>
       <hint-dedicated state='off'/>
+      <dirty-ring state='off'/>
     </kvm>
   </features>
   <clock offset='utc'/>
diff --git a/tests/qemuxml2argvdata/kvm-features.xml b/tests/qemuxml2argvdata/kvm-features.xml
index 85f74786c9..fd08a7a0f5 100644
--- a/tests/qemuxml2argvdata/kvm-features.xml
+++ b/tests/qemuxml2argvdata/kvm-features.xml
@@ -13,6 +13,7 @@
     <kvm>
       <hidden state='on'/>
       <hint-dedicated state='on'/>
+      <dirty-ring state='on' size='4096'/>
     </kvm>
   </features>
   <cpu mode='host-passthrough' check='none'/>
diff --git a/tests/qemuxml2xmloutdata/kvm-features-off.xml b/tests/qemuxml2xmloutdata/kvm-features-off.xml
index 9068be3e7b..2c8b6a81d3 100644
--- a/tests/qemuxml2xmloutdata/kvm-features-off.xml
+++ b/tests/qemuxml2xmloutdata/kvm-features-off.xml
@@ -13,6 +13,7 @@
     <kvm>
       <hidden state='off'/>
       <hint-dedicated state='off'/>
+      <dirty-ring state='off'/>
     </kvm>
   </features>
   <clock offset='utc'/>
diff --git a/tests/qemuxml2xmloutdata/kvm-features.xml b/tests/qemuxml2xmloutdata/kvm-features.xml
index 7c554671b3..6e97065fed 100644
--- a/tests/qemuxml2xmloutdata/kvm-features.xml
+++ b/tests/qemuxml2xmloutdata/kvm-features.xml
@@ -13,6 +13,7 @@
     <kvm>
       <hidden state='on'/>
       <hint-dedicated state='on'/>
+      <dirty-ring state='on' size='4096'/>
     </kvm>
   </features>
   <cpu mode='host-passthrough' check='none'/>
-- 
2.27.0

