From fbc6ac1471bdc6ffdb5fe5e47bf6df2753acf949 Mon Sep 17 00:00:00 2001
From: lutong <lutong14@huawei.com>
Date: Sat, 26 Jul 2025 17:40:03 +0800
Subject: [PATCH 2/6] util:resctrl:add L3 priority parse and format method

---
 src/libvirt_private.syms  |   2 +
 src/util/virresctrl.c     | 168 +++++++++++++++++++++++++++++++-------
 src/util/virresctrl.h     |   1 +
 src/util/virresctrlpriv.h |   7 ++
 tests/virresctrltest.c    |   5 ++
 5 files changed, 153 insertions(+), 30 deletions(-)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index cd99cc302a..a3799a0108 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -3252,11 +3252,13 @@ virCacheKernelTypeToString;
 virCacheTypeFromString;
 virCacheTypeToString;
 virResctrlAllocAddPID;
+virResctrlAllocCopyCacheProperties;
 virResctrlAllocCreate;
 virResctrlAllocDeterminePath;
 virResctrlAllocForeachCache;
 virResctrlAllocForeachMemory;
 virResctrlAllocFormat;
+virResctrlAllocGetDefault;
 virResctrlAllocGetID;
 virResctrlAllocGetUnused;
 virResctrlAllocIsEmpty;
diff --git a/src/util/virresctrl.c b/src/util/virresctrl.c
index 7d661e944f..3d2be7560c 100644
--- a/src/util/virresctrl.c
+++ b/src/util/virresctrl.c
@@ -60,6 +60,7 @@ VIR_ENUM_IMPL(virCacheKernel,
               "Unified",
               "Instruction",
               "Data",
+              "Priority",
 );
 
 /* Cache name mapping for our XML naming. */
@@ -68,6 +69,7 @@ VIR_ENUM_IMPL(virCache,
               "both",
               "code",
               "data",
+              "priority",
 );
 
 /* Cache name mapping for resctrl interface naming. */
@@ -77,6 +79,7 @@ VIR_ENUM_IMPL(virResctrl,
               "",
               "CODE",
               "DATA",
+              "PRI",
 );
 
 /* Monitor feature name prefix mapping for monitor naming */
@@ -313,6 +316,10 @@ struct _virResctrlAllocPerType {
     /* cache id map for each cache */
     unsigned int **cache_ids;
     size_t ncache_ids;
+
+    /* priority for each cahe */
+    unsigned long long **priorities;
+    size_t npriorities;
 };
 
 struct _virResctrlAllocPerLevel {
@@ -401,9 +408,13 @@ virResctrlAllocDispose(void *obj)
             for (k = 0; k < type->ncache_ids; k++)
                 g_free(type->cache_ids[k]);
 
+            for (k = 0; k < type->npriorities; k++)
+                g_free(type->priorities[k]);
+
             g_free(type->sizes);
             g_free(type->masks);
             g_free(type->cache_ids);
+            g_free(type->priorities);
             g_free(type);
         }
         g_free(level->types);
@@ -1518,19 +1529,25 @@ virResctrlAllocFormatCache(virResctrlAlloc *alloc,
 
             virBufferAsprintf(buf, "L%u%s:", level, virResctrlTypeToString(type));
 
-            for (cache = 0; cache < a_type->nmasks; cache++) {
-                virBitmap *mask = a_type->masks[cache];
-                char *mask_str = NULL;
-
-                if (!mask)
-                    continue;
-
-                mask_str = virBitmapToString(mask);
-                if (!mask_str)
-                    return -1;
-
-                virBufferAsprintf(buf, "%u=%s;", *a_type->cache_ids[cache], mask_str);
-                VIR_FREE(mask_str);
+            if (type == VIR_CACHE_TYPE_PRIORITY) {
+                for (cache = 0; cache < a_type->npriorities; cache++) {
+                    virBufferAsprintf(buf, "%u=%llu;", *(a_type->cache_ids[cache]), *(a_type->priorities[cache]));
+                }
+            } else {
+                for (cache = 0; cache < a_type->nmasks; cache++) {
+                    virBitmap *mask = a_type->masks[cache];
+                    char *mask_str = NULL;
+
+                    if (!mask)
+                        continue;
+
+                    mask_str = virBitmapToString(mask);
+                    if (!mask_str)
+                        return -1;
+
+                    virBufferAsprintf(buf, "%u=%s;", *(a_type->cache_ids[cache]), mask_str);
+                    VIR_FREE(mask_str);
+                }
             }
 
             virBufferTrim(buf, ";");
@@ -1604,6 +1621,41 @@ virResctrlAllocParseProcessCacheId(virResctrlInfo *resctrl,
 }
 
 
+static int
+virResctrlAllocParseProcessCachePriority(virResctrlAlloc *alloc,
+                                         unsigned int level,
+                                         virCacheType type,
+                                         char *value,
+                                         unsigned int node_id)
+{
+    unsigned int priority = 0;
+    virResctrlAllocPerType *a_type = NULL;
+
+    if (virStrToLong_uip(value, NULL, 10, &priority) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Invalid priority '%1$s'"), value);
+        return -1;
+    }
+
+    a_type = virResctrlAllocGetType(alloc, level, type);
+
+    if (!a_type)
+        return -1;
+
+    if (a_type->npriorities <= node_id) {
+        VIR_EXPAND_N(a_type->priorities, a_type->npriorities,
+                     node_id - a_type->npriorities + 1);
+    }
+
+    if (!a_type->priorities[node_id])
+        a_type->priorities[node_id] = g_new0(unsigned long long, 1);
+
+    *(a_type->priorities[node_id]) = priority;
+
+    return 0;
+}
+
+
 static int
 virResctrlAllocParseProcessCache(virResctrlInfo *resctrl,
                                  virResctrlAlloc *alloc,
@@ -1613,7 +1665,6 @@ virResctrlAllocParseProcessCache(virResctrlInfo *resctrl,
                                  unsigned int node_id)
 {
     char *tmp = strchr(cache, '=');
-    unsigned int cache_id = 0;
     g_autoptr(virBitmap) mask = NULL;
 
     if (!tmp)
@@ -1626,10 +1677,8 @@ virResctrlAllocParseProcessCache(virResctrlInfo *resctrl,
         return -1;
     }
 
-    if (virStrToLong_uip(cache, NULL, 10, &cache_id) < 0) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Invalid cache id '%1$s'"), cache);
-        return -1;
+    if (type == VIR_CACHE_TYPE_PRIORITY) {
+        return virResctrlAllocParseProcessCachePriority(alloc, level, type, tmp, node_id);
     }
 
     mask = virBitmapNewString(tmp);
@@ -1762,7 +1811,7 @@ virResctrlAllocGetGroup(virResctrlInfo *resctrl,
 }
 
 
-static virResctrlAlloc *
+virResctrlAlloc *
 virResctrlAllocGetDefault(virResctrlInfo *resctrl)
 {
     virResctrlAlloc *ret = NULL;
@@ -2128,9 +2177,9 @@ virResctrlAllocCopyMemBW(virResctrlAlloc *dst,
 }
 
 
-static int
-virResctrlAllocCopyCache(virResctrlAlloc *dst,
-                         virResctrlAlloc *src)
+int
+virResctrlAllocCopyCacheProperties(virResctrlAlloc *dst,
+                                   virResctrlAlloc *src)
 {
     unsigned int level = 0;
 
@@ -2153,13 +2202,6 @@ virResctrlAllocCopyCache(virResctrlAlloc *dst,
             if (!d_type)
                 return -1;
 
-            for (cache = 0; cache < s_type->nmasks; cache++) {
-                virBitmap *mask = s_type->masks[cache];
-
-                if (mask && virResctrlAllocUpdateMask(dst, level, type, cache, mask) < 0)
-                    return -1;
-            }
-
             if (s_type->ncache_ids > d_type->ncache_ids)
                 VIR_EXPAND_N(d_type->cache_ids, d_type->ncache_ids,
                              s_type->ncache_ids - d_type->ncache_ids);
@@ -2168,7 +2210,18 @@ virResctrlAllocCopyCache(virResctrlAlloc *dst,
                 if (d_type->cache_ids[cache])
                     continue;
                 d_type->cache_ids[cache] = g_new0(unsigned int, 1);
-                *d_type->cache_ids[cache] = *s_type->cache_ids[cache];
+                *(d_type->cache_ids[cache]) = *(s_type->cache_ids[cache]);
+            }
+
+            if (s_type->npriorities > d_type->npriorities)
+                VIR_EXPAND_N(d_type->priorities, d_type->npriorities,
+                             s_type->npriorities - d_type->npriorities);
+
+            for (cache = 0; cache < s_type->npriorities; cache++) {
+                if (d_type->priorities[cache])
+                    continue;
+                d_type->priorities[cache] = g_new0(long long unsigned int, 1);
+                *(d_type->priorities[cache]) = *(s_type->priorities[cache]);
             }
         }
     }
@@ -2177,6 +2230,44 @@ virResctrlAllocCopyCache(virResctrlAlloc *dst,
 }
 
 
+static int
+virResctrlAllocCopyCache(virResctrlAlloc *dst,
+                         virResctrlAlloc *src)
+{
+    unsigned int level = 0;
+
+    for (level = 0; level < src->nlevels; level++) {
+        virResctrlAllocPerLevel *s_level = src->levels[level];
+        unsigned int type = 0;
+
+        if (!s_level)
+            continue;
+
+        for (type = 0; type < VIR_CACHE_TYPE_LAST; type++) {
+            virResctrlAllocPerType *s_type = s_level->types[type];
+            virResctrlAllocPerType *d_type = NULL;
+            unsigned int cache = 0;
+
+            if (!s_type)
+                continue;
+
+            d_type = virResctrlAllocGetType(dst, level, type);
+            if (!d_type)
+                return -1;
+
+            for (cache = 0; cache < s_type->nmasks; cache++) {
+                virBitmap *mask = s_type->masks[cache];
+
+                if (mask && virResctrlAllocUpdateMask(dst, level, type, cache, mask) < 0)
+                    return -1;
+            }
+        }
+    }
+
+    return virResctrlAllocCopyCacheProperties(dst, src);
+}
+
+
 /*
  * This function is called when creating an allocation in the system.
  * What it does is that it gets all the unused resources using
@@ -2234,6 +2325,23 @@ virResctrlAllocAssign(virResctrlInfo *resctrl,
             if (!a_type)
                 continue;
 
+            if (type == VIR_CACHE_TYPE_PRIORITY) {
+                for (cache = 0; cache < a_type->nsizes; cache++) {
+                    if (!a_type->sizes[cache])
+                        continue;
+
+                    if (!a_type->priorities[cache]) {
+                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                            _("Cache level %1$d does not support tuning for scope type '%2$s'"),
+                            level, virCacheTypeToString(type));
+                        return -1;
+                    }
+
+                    *a_type->priorities[cache] = *a_type->sizes[cache];
+                }
+                continue;
+            }
+
             if (!f_type) {
                 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                _("Cache level %1$d does not support tuning for scope type '%2$s'"),
diff --git a/src/util/virresctrl.h b/src/util/virresctrl.h
index 0e4b535f9e..af135520d7 100644
--- a/src/util/virresctrl.h
+++ b/src/util/virresctrl.h
@@ -27,6 +27,7 @@ typedef enum {
     VIR_CACHE_TYPE_BOTH,
     VIR_CACHE_TYPE_CODE,
     VIR_CACHE_TYPE_DATA,
+    VIR_CACHE_TYPE_PRIORITY,
 
     VIR_CACHE_TYPE_LAST
 } virCacheType;
diff --git a/src/util/virresctrlpriv.h b/src/util/virresctrlpriv.h
index 803f9b62ab..646b040761 100644
--- a/src/util/virresctrlpriv.h
+++ b/src/util/virresctrlpriv.h
@@ -26,3 +26,10 @@
 
 virResctrlAlloc *
 virResctrlAllocGetUnused(virResctrlInfo *resctrl);
+
+virResctrlAlloc *
+virResctrlAllocGetDefault(virResctrlInfo *resctrl);
+
+int
+virResctrlAllocCopyCacheProperties(virResctrlAlloc *dst,
+                                   virResctrlAlloc *src);
\ No newline at end of file
diff --git a/tests/virresctrltest.c b/tests/virresctrltest.c
index c5733a7972..d5bc37259c 100644
--- a/tests/virresctrltest.c
+++ b/tests/virresctrltest.c
@@ -21,6 +21,7 @@ test_virResctrlGetUnused(const void *opaque)
     g_autofree char *system_dir = NULL;
     g_autofree char *resctrl_dir = NULL;
     g_autoptr(virResctrlAlloc) alloc = NULL;
+    g_autoptr(virResctrlAlloc) default_alloc = NULL;
     g_autofree char *schemata_str = NULL;
     g_autofree char *schemata_file = NULL;
     g_autoptr(virCaps) caps = NULL;
@@ -44,6 +45,10 @@ test_virResctrlGetUnused(const void *opaque)
     }
 
     alloc = virResctrlAllocGetUnused(caps->host.resctrl);
+    default_alloc = virResctrlAllocGetDefault(caps->host.resctrl);
+
+    if (virResctrlAllocCopyCacheProperties(alloc, default_alloc) < 0)
+        return -1;
 
     virFileWrapperClearPrefixes();
 
-- 
2.33.0