From f2d73e1d3b02894f40dbb9513f6ed923d2132e88 Mon Sep 17 00:00:00 2001
From: lutong <lutong14@huawei.com>
Date: Mon, 4 Aug 2025 10:19:41 +0800
Subject: [PATCH 5/6] conf: add support for memorytune XML processing for MB
 hardlimit

---
 src/conf/domain_conf.c            | 23 ++++++++++++++---
 src/conf/schemas/domaincommon.rng |  5 ++++
 src/util/virresctrl.c             | 43 ++++++++++++++++++++++++-------
 src/util/virresctrl.h             |  3 ++-
 4 files changed, 59 insertions(+), 15 deletions(-)

diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 12e02e4893..6c25d62998 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -18237,6 +18237,7 @@ virDomainMemorytuneDefParseMemory(xmlXPathContextPtr ctxt,
     VIR_XPATH_NODE_AUTORESTORE(ctxt)
     unsigned int id;
     unsigned int bandwidth;
+    unsigned int hard_limit = UINT_MAX;
 
     ctxt->node = node;
 
@@ -18250,6 +18251,13 @@ virDomainMemorytuneDefParseMemory(xmlXPathContextPtr ctxt,
     if (virResctrlAllocSetMemoryBandwidth(alloc, VIR_MEMORY_TYPE_BANDWIDTH, id, bandwidth) < 0)
         return -1;
 
+    if (virXMLPropUIntDefault(node, "hardlimit", 10, 0, &hard_limit, UINT_MAX) < 0)
+        return -1;
+
+    if (hard_limit != UINT_MAX &&
+        virResctrlAllocSetMemoryBandwidth(alloc, VIR_MEMORY_TYPE_HARDLIMIT, id, hard_limit) < 0)
+        return -1;
+
     return 0;
 }
 
@@ -26846,14 +26854,21 @@ virDomainCachetuneDefFormat(virBuffer *buf,
 
 static int
 virDomainMemorytuneDefFormatHelper(unsigned int id,
-                                   unsigned int bandwidth,
+                                   unsigned int *types,
+                                   unsigned int *values,
                                    void *opaque)
 {
     virBuffer *buf = opaque;
+    size_t i;
 
-    virBufferAsprintf(buf,
-                      "<node id='%u' bandwidth='%u'/>\n",
-                      id, bandwidth);
+    virBufferAsprintf(buf, "<node id='%u'", id);
+    for (i = 0; i < VIR_MEMORY_TYPE_LAST; i++) {
+        if (types[i] == VIR_MEMORY_TYPE_LAST)
+            continue;
+
+        virBufferAsprintf(buf, " %s='%u'", virMemoryTypeToString(types[i]), values[i]);
+    }
+    virBufferAddLit(buf, "/>\n");
     return 0;
 }
 
diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng
index 7278b699e0..504147a0b5 100644
--- a/src/conf/schemas/domaincommon.rng
+++ b/src/conf/schemas/domaincommon.rng
@@ -1185,6 +1185,11 @@
                   <attribute name="bandwidth">
                     <ref name="unsignedInt"/>
                   </attribute>
+                  <optional>
+                    <attribute name="hardlimit">
+                      <ref name="unsignedInt"/>
+                    </attribute>
+                  </optional>
                 </element>
                 <element name="monitor">
                   <attribute name="vcpus">
diff --git a/src/util/virresctrl.c b/src/util/virresctrl.c
index 77abf03a3c..e262deae73 100644
--- a/src/util/virresctrl.c
+++ b/src/util/virresctrl.c
@@ -1383,10 +1383,11 @@ virResctrlAllocForeachCache(virResctrlAlloc *alloc,
 
 /* virResctrlAllocSetMemoryBandwidth
  * @alloc: Pointer to an active allocation
+ * @type: type of memory bandwidth to be set
  * @id: node id of MBA to be set
- * @memory_bandwidth: new memory bandwidth value
+ * @value: new memory bandwidth type value
  *
- * Set the @memory_bandwidth for the node @id entry in the @alloc.
+ * Set the @value for the node @id entry in the @alloc.
  *
  * Returns 0 on success, -1 on failure with error message set.
  */
@@ -1394,13 +1395,13 @@ int
 virResctrlAllocSetMemoryBandwidth(virResctrlAlloc *alloc,
                                   virMemoryType type,
                                   unsigned int id,
-                                  unsigned int memory_bandwidth)
+                                  unsigned int value)
 {
     virResctrlAllocMemBW *mem_bw = alloc->mem_bw;
     virResctrlAllocMemPerType *a_type = NULL;
 
     if (type == VIR_MEMORY_TYPE_HARDLIMIT) {
-        if (memory_bandwidth > 1) {
+        if (value > 1) {
             virReportError(VIR_ERR_XML_ERROR, "%s",
                         _("Memory Bandwidth hard limit value just support 0 or 1."));
             return -1;
@@ -1408,7 +1409,7 @@ virResctrlAllocSetMemoryBandwidth(virResctrlAlloc *alloc,
     }
 
     if (type == VIR_MEMORY_TYPE_BANDWIDTH) {
-        if (memory_bandwidth > 100) {
+        if (value > 100) {
             virReportError(VIR_ERR_XML_ERROR, "%s",
                         _("Memory Bandwidth value exceeding 100 is invalid."));
             return -1;
@@ -1437,7 +1438,7 @@ virResctrlAllocSetMemoryBandwidth(virResctrlAlloc *alloc,
     }
 
     a_type->user_values[id] = g_new0(unsigned int, 1);
-    *(a_type->user_values[id]) = memory_bandwidth;
+    *(a_type->user_values[id]) = value;
 
     return 0;
 }
@@ -1458,18 +1459,40 @@ virResctrlAllocForeachMemory(virResctrlAlloc *alloc,
                              virResctrlAllocForeachMemoryCallback cb,
                              void *opaque)
 {
-    size_t i = 0;
+    unsigned int i, type;
     virResctrlAllocMemBW *mem_bw;
+    g_autofree unsigned int *types = NULL;
+    g_autofree unsigned int *values = NULL;
 
     if (!alloc || !alloc->mem_bw)
         return 0;
 
     mem_bw = alloc->mem_bw;
+
+    if (!mem_bw->types)
+        return 0;
+
+    if (!mem_bw->types[VIR_MEMORY_TYPE_BANDWIDTH])
+        return 0;
+
+    types = g_new0(unsigned int, VIR_MEMORY_TYPE_LAST);
+    values = g_new0(unsigned int, VIR_MEMORY_TYPE_LAST);
+
     for (i = 0; i < mem_bw->types[VIR_MEMORY_TYPE_BANDWIDTH]->nuser_values; i++) {
-        if (mem_bw->types[VIR_MEMORY_TYPE_BANDWIDTH]->user_values[i]) {
-            if (cb(i, *mem_bw->types[VIR_MEMORY_TYPE_BANDWIDTH]->user_values[i], opaque) < 0)
-                return -1;
+        if (!mem_bw->types[VIR_MEMORY_TYPE_BANDWIDTH]->user_values[i])
+            continue;
+
+        for (type = 0; type < VIR_MEMORY_TYPE_LAST; type++) {
+            virResctrlAllocMemPerType *a_type = mem_bw->types[type];
+            if (!a_type || a_type->nuser_values <= i || !a_type->user_values[i]) {
+                types[type] = VIR_MEMORY_TYPE_LAST;
+                continue;
+            }
+
+            types[type] = type;
+            values[type] = *(a_type->user_values[i]);
         }
+        cb(i, types, values, opaque);
     }
 
     return 0;
diff --git a/src/util/virresctrl.h b/src/util/virresctrl.h
index 9ee76eb225..9b317187f5 100644
--- a/src/util/virresctrl.h
+++ b/src/util/virresctrl.h
@@ -129,7 +129,8 @@ typedef int virResctrlAllocForeachCacheCallback(unsigned int level,
                                                 void *opaque);
 
 typedef int virResctrlAllocForeachMemoryCallback(unsigned int id,
-                                                 unsigned int size,
+                                                 unsigned int *types,
+                                                 unsigned int *values,
                                                  void *opaque);
 
 virResctrlAlloc *
-- 
2.33.0