[PATCH v7 03/18] config: Introduce ThrottleGroup and corresponding XML parsing

Harikumar Rajkumar posted 18 patches 10 months, 1 week ago
[PATCH v7 03/18] config: Introduce ThrottleGroup and corresponding XML parsing
Posted by Harikumar Rajkumar 10 months, 1 week ago
Introduce throttlegroup into domain and provide corresponding methods

* Define new struct 'virDomainThrottleGroupDef' and corresponding destructor
* Add operations(Add, Update, Del, ByName, Copy, Free) for
'virDomainThrottleGroupDef'
* Update _virDomainDef to include virDomainThrottleGroupDef
* Support new resource "Parse" and "Format" for operations between
struct and DOM XML
* Make sure "group_name" is defined in xml

Signed-off-by: Harikumar Rajkumar <harirajkumar230@gmail.com>
---
 src/conf/domain_conf.c  | 300 ++++++++++++++++++++++++++++++++++++++++
 src/conf/domain_conf.h  |  27 ++++
 src/conf/virconftypes.h |   2 +
 3 files changed, 329 insertions(+)

diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 87f87bbe56..fd08e67edc 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -3799,6 +3799,32 @@ virDomainIOThreadIDDefArrayInit(virDomainDef *def,
 }
 
 
+void
+virDomainThrottleGroupDefFree(virDomainThrottleGroupDef *def)
+{
+    if (!def)
+        return;
+    g_free(def->group_name);
+    g_free(def);
+}
+
+
+static void
+virDomainThrottleGroupDefArrayFree(virDomainThrottleGroupDef **def,
+                                   int nthrottlegroups)
+{
+    size_t i;
+
+    if (!def)
+        return;
+
+    for (i = 0; i < nthrottlegroups; i++)
+        virDomainThrottleGroupDefFree(def[i]);
+
+    g_free(def);
+}
+
+
 void
 virDomainResourceDefFree(virDomainResourceDef *resource)
 {
@@ -4086,6 +4112,8 @@ void virDomainDefFree(virDomainDef *def)
 
     virDomainIOThreadIDDefArrayFree(def->iothreadids, def->niothreadids);
 
+    virDomainThrottleGroupDefArrayFree(def->throttlegroups, def->nthrottlegroups);
+
     g_free(def->defaultIOThread);
 
     virBitmapFree(def->cputune.emulatorpin);
@@ -7830,6 +7858,123 @@ virDomainDiskDefIotuneParse(virDomainDiskDef *def,
 }
 #undef PARSE_IOTUNE
 
+/* the field changes must also be applied to the other function that formats
+ * the <disk> throttling definition virDomainThrottleGroupFormat. */
+#define PARSE_THROTTLEGROUP(val) \
+    if (virXPathULongLong("string(./" #val ")", \
+                          ctxt, &group->val) == -2) { \
+        virReportError(VIR_ERR_XML_ERROR, \
+                       _("throttle group field '%1$s' must be an integer"), #val); \
+        return NULL; \
+    }
+
+
+static virDomainThrottleGroupDef *
+virDomainThrottleGroupDefParseXML(xmlNodePtr node,
+                                  xmlXPathContextPtr ctxt)
+{
+    g_autoptr(virDomainThrottleGroupDef) group = g_new0(virDomainThrottleGroupDef, 1);
+
+    VIR_XPATH_NODE_AUTORESTORE(ctxt)
+    ctxt->node = node;
+
+    PARSE_THROTTLEGROUP(total_bytes_sec);
+    PARSE_THROTTLEGROUP(read_bytes_sec);
+    PARSE_THROTTLEGROUP(write_bytes_sec);
+    PARSE_THROTTLEGROUP(total_iops_sec);
+    PARSE_THROTTLEGROUP(read_iops_sec);
+    PARSE_THROTTLEGROUP(write_iops_sec);
+
+    PARSE_THROTTLEGROUP(total_bytes_sec_max);
+    PARSE_THROTTLEGROUP(read_bytes_sec_max);
+    PARSE_THROTTLEGROUP(write_bytes_sec_max);
+    PARSE_THROTTLEGROUP(total_iops_sec_max);
+    PARSE_THROTTLEGROUP(read_iops_sec_max);
+    PARSE_THROTTLEGROUP(write_iops_sec_max);
+
+    PARSE_THROTTLEGROUP(size_iops_sec);
+
+    PARSE_THROTTLEGROUP(total_bytes_sec_max_length);
+    PARSE_THROTTLEGROUP(read_bytes_sec_max_length);
+    PARSE_THROTTLEGROUP(write_bytes_sec_max_length);
+    PARSE_THROTTLEGROUP(total_iops_sec_max_length);
+    PARSE_THROTTLEGROUP(read_iops_sec_max_length);
+    PARSE_THROTTLEGROUP(write_iops_sec_max_length);
+
+    /* group_name is required */
+    if (!(group->group_name = virXPathString("string(./group_name)", ctxt))) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("missing group name"));
+        return NULL;
+    }
+
+   return g_steal_pointer(&group);
+}
+#undef PARSE_THROTTLEGROUP
+
+
+/**
+ * virDomainThrottleGroupByName:
+ * @def: domain definition
+ * @name: throttle group name
+ *
+ * search throttle group within domain definition
+ * by @name
+ *
+ * Returns a pointer to throttle group found.
+ */
+virDomainThrottleGroupDef *
+virDomainThrottleGroupByName(const virDomainDef *def,
+                             const char *name)
+{
+    size_t i;
+
+    if (!def->throttlegroups || def->nthrottlegroups == 0)
+        return NULL;
+
+    for (i = 0; i < def->nthrottlegroups; i++) {
+        if (STREQ(def->throttlegroups[i]->group_name, name))
+            return def->throttlegroups[i];
+    }
+
+    return NULL;
+}
+
+
+static int
+virDomainDefThrottleGroupsParse(virDomainDef *def,
+                                xmlXPathContextPtr ctxt)
+{
+    size_t i;
+    int n = 0;
+    g_autofree xmlNodePtr *nodes = NULL;
+
+    if ((n = virXPathNodeSet("./throttlegroups/throttlegroup", ctxt, &nodes)) < 0)
+        return -1;
+
+    if (n == 0)
+        return 0;
+
+    def->throttlegroups = g_new0(virDomainThrottleGroupDef *, n);
+
+    for (i = 0; i < n; i++) {
+        g_autoptr(virDomainThrottleGroupDef) group = NULL;
+
+        if (!(group = virDomainThrottleGroupDefParseXML(nodes[i], ctxt))) {
+            return -1;
+        }
+
+        if (virDomainThrottleGroupByName(def, group->group_name)) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("duplicate group name '%1$s' found"),
+                           group->group_name);
+            return -1;
+        }
+        def->throttlegroups[def->nthrottlegroups++] = g_steal_pointer(&group);
+    }
+    return 0;
+}
+
 
 static int
 virDomainDiskDefMirrorParse(virDomainDiskDef *def,
@@ -19211,6 +19356,9 @@ virDomainDefParseXML(xmlXPathContextPtr ctxt,
     if (virDomainDefParseBootOptions(def, ctxt, xmlopt, flags) < 0)
         return NULL;
 
+    if (virDomainDefThrottleGroupsParse(def, ctxt) < 0)
+        return NULL;
+
     /* analysis of the disk devices */
     if ((n = virXPathNodeSet("./devices/disk", ctxt, &nodes)) < 0)
         return NULL;
@@ -22511,6 +22659,94 @@ virDomainIOThreadIDDel(virDomainDef *def,
 }
 
 
+/**
+ * virDomainThrottleGroupDefCopy:
+ * @src: throttle group to be copied from
+ * @dst: throttle group to be copied to
+ *
+ * copy throttle group content from @src to @dst,
+ * this function does not allocate memory for @dst - the caller must ensure
+ * @dst is already allocated before calling this function.
+ */
+void
+virDomainThrottleGroupDefCopy(const virDomainThrottleGroupDef *src,
+                              virDomainThrottleGroupDef *dst)
+{
+    *dst = *src;
+    dst->group_name = g_strdup(src->group_name);
+}
+
+
+/**
+ * virDomainThrottleGroupAdd:
+ * @def: domain definition
+ * @throttle_group: throttle group definition within domain
+ *
+ * add new throttle group into @def
+ *
+ * return a pointer to throttle group added
+ */
+virDomainThrottleGroupDef *
+virDomainThrottleGroupAdd(virDomainDef *def,
+                          virDomainThrottleGroupDef *throttle_group)
+{
+    virDomainThrottleGroupDef * new_group =  g_new0(virDomainThrottleGroupDef, 1);
+    virDomainThrottleGroupDefCopy(throttle_group, new_group);
+    VIR_APPEND_ELEMENT_COPY(def->throttlegroups, def->nthrottlegroups, new_group);
+    return new_group;
+}
+
+
+/**
+ * virDomainThrottleGroupUpdate:
+ * @def: domain definition
+ * @info: throttle group definition within domain
+ *
+ * Update corresponding throttle group in @def using new config @info. If a
+ * throttle group with given name doesn't exist this function does nothing.
+ */
+void
+virDomainThrottleGroupUpdate(virDomainDef *def,
+                             virDomainThrottleGroupDef *info)
+{
+    size_t i;
+
+    if (!info->group_name)
+        return;
+
+    for (i = 0; i < def->nthrottlegroups; i++) {
+        virDomainThrottleGroupDef *t = def->throttlegroups[i];
+
+        if (STREQ_NULLABLE(t->group_name, info->group_name)) {
+            VIR_FREE(t->group_name);
+            virDomainThrottleGroupDefCopy(info, t);
+        }
+    }
+}
+
+
+/**
+ * virDomainThrottleGroupDel:
+ * @def: domain definition
+ * @name: throttle group name
+ *
+ * Delete throttle group @name in @def
+ */
+void
+virDomainThrottleGroupDel(virDomainDef *def,
+                          const char *name)
+{
+    size_t i;
+    for (i = 0; i < def->nthrottlegroups; i++) {
+        if (STREQ_NULLABLE(def->throttlegroups[i]->group_name, name)) {
+            virDomainThrottleGroupDefFree(def->throttlegroups[i]);
+            VIR_DELETE_ELEMENT(def->throttlegroups, i, def->nthrottlegroups);
+            return;
+        }
+    }
+}
+
+
 static int
 virDomainEventActionDefFormat(virBuffer *buf,
                               int type,
@@ -27696,6 +27932,68 @@ virDomainDefIOThreadsFormat(virBuffer *buf,
     virDomainDefaultIOThreadDefFormat(buf, def);
 }
 
+/*
+ * the field changes must also be applied to the other function that parses
+ * the <disk> throttling definition virDomainThrottleGroupDefParseXML
+ */
+#define FORMAT_THROTTLE_GROUP(val) \
+        if (group->val > 0) { \
+            virBufferAsprintf(&childBuf, "<" #val ">%llu</" #val ">\n", \
+                              group->val); \
+        }
+
+
+static void
+virDomainThrottleGroupFormat(virBuffer *buf,
+                             virDomainThrottleGroupDef *group)
+{
+    g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf);
+
+    FORMAT_THROTTLE_GROUP(total_bytes_sec);
+    FORMAT_THROTTLE_GROUP(read_bytes_sec);
+    FORMAT_THROTTLE_GROUP(write_bytes_sec);
+    FORMAT_THROTTLE_GROUP(total_iops_sec);
+    FORMAT_THROTTLE_GROUP(read_iops_sec);
+    FORMAT_THROTTLE_GROUP(write_iops_sec);
+
+    FORMAT_THROTTLE_GROUP(total_bytes_sec_max);
+    FORMAT_THROTTLE_GROUP(read_bytes_sec_max);
+    FORMAT_THROTTLE_GROUP(write_bytes_sec_max);
+    FORMAT_THROTTLE_GROUP(total_iops_sec_max);
+    FORMAT_THROTTLE_GROUP(read_iops_sec_max);
+    FORMAT_THROTTLE_GROUP(write_iops_sec_max);
+
+    FORMAT_THROTTLE_GROUP(size_iops_sec);
+
+    FORMAT_THROTTLE_GROUP(total_bytes_sec_max_length);
+    FORMAT_THROTTLE_GROUP(read_bytes_sec_max_length);
+    FORMAT_THROTTLE_GROUP(write_bytes_sec_max_length);
+    FORMAT_THROTTLE_GROUP(total_iops_sec_max_length);
+    FORMAT_THROTTLE_GROUP(read_iops_sec_max_length);
+    FORMAT_THROTTLE_GROUP(write_iops_sec_max_length);
+
+    virBufferEscapeString(&childBuf, "<group_name>%s</group_name>\n",
+                          group->group_name);
+
+    virXMLFormatElement(buf, "throttlegroup", NULL, &childBuf);
+}
+
+#undef FORMAT_THROTTLE_GROUP
+
+static void
+virDomainDefThrottleGroupsFormat(virBuffer *buf,
+                                 const virDomainDef *def)
+{
+    g_auto(virBuffer) childrenBuf = VIR_BUFFER_INIT_CHILD(buf);
+    size_t n;
+
+    for (n = 0; n < def->nthrottlegroups; n++) {
+        virDomainThrottleGroupFormat(&childrenBuf, def->throttlegroups[n]);
+    }
+
+    virXMLFormatElement(buf, "throttlegroups", NULL, &childrenBuf);
+}
+
 
 static void
 virDomainIOMMUDefFormat(virBuffer *buf,
@@ -28398,6 +28696,8 @@ virDomainDefFormatInternalSetRootName(virDomainDef *def,
 
     virDomainDefIOThreadsFormat(buf, def);
 
+    virDomainDefThrottleGroupsFormat(buf, def);
+
     if (virDomainCputuneDefFormat(buf, def, flags) < 0)
         return -1;
 
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index e51c74b6d1..4977747d9c 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -3079,6 +3079,9 @@ struct _virDomainDef {
 
     virDomainDefaultIOThreadDef *defaultIOThread;
 
+    size_t nthrottlegroups;
+    virDomainThrottleGroupDef **throttlegroups;
+
     virDomainCputune cputune;
 
     virDomainResctrlDef **resctrls;
@@ -4600,3 +4603,27 @@ virDomainObjGetMessages(virDomainObj *vm,
 
 bool
 virDomainDefHasSpiceGraphics(const virDomainDef *def);
+
+void
+virDomainThrottleGroupDefFree(virDomainThrottleGroupDef *def);
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainThrottleGroupDef, virDomainThrottleGroupDefFree);
+
+virDomainThrottleGroupDef *
+virDomainThrottleGroupAdd(virDomainDef *def,
+                          virDomainThrottleGroupDef *throttle_group);
+
+void
+virDomainThrottleGroupUpdate(virDomainDef *def,
+                             virDomainThrottleGroupDef *info);
+
+void
+virDomainThrottleGroupDel(virDomainDef *def,
+                          const char *name);
+
+virDomainThrottleGroupDef *
+virDomainThrottleGroupByName(const virDomainDef *def,
+                             const char *name);
+
+void
+virDomainThrottleGroupDefCopy(const virDomainThrottleGroupDef *src,
+                              virDomainThrottleGroupDef *dst);
diff --git a/src/conf/virconftypes.h b/src/conf/virconftypes.h
index 59be61cea4..1936ef6ab1 100644
--- a/src/conf/virconftypes.h
+++ b/src/conf/virconftypes.h
@@ -80,6 +80,8 @@ typedef struct _virDomainBlkiotune virDomainBlkiotune;
 
 typedef struct _virDomainBlockIoTuneInfo virDomainBlockIoTuneInfo;
 
+typedef struct _virDomainBlockIoTuneInfo  virDomainThrottleGroupDef;
+
 typedef struct _virDomainCheckpointDef virDomainCheckpointDef;
 
 typedef struct _virDomainCheckpointObj virDomainCheckpointObj;
-- 
2.39.5 (Apple Git-154)
Re: [PATCH v7 03/18] config: Introduce ThrottleGroup and corresponding XML parsing
Posted by Daniel P. Berrangé 10 months, 1 week ago
On Wed, Feb 12, 2025 at 04:05:22PM +0530, Harikumar Rajkumar wrote:
> Introduce throttlegroup into domain and provide corresponding methods
> 
> * Define new struct 'virDomainThrottleGroupDef' and corresponding destructor
> * Add operations(Add, Update, Del, ByName, Copy, Free) for
> 'virDomainThrottleGroupDef'
> * Update _virDomainDef to include virDomainThrottleGroupDef
> * Support new resource "Parse" and "Format" for operations between
> struct and DOM XML
> * Make sure "group_name" is defined in xml
> 
> Signed-off-by: Harikumar Rajkumar <harirajkumar230@gmail.com>

When this patch was posted in v6:

  https://lists.libvirt.org/archives/list/devel@lists.libvirt.org/message/VUW7AKTYMM2S7EEVQLY3DN7YE7ON5NQZ/

The authorship was credited to Chun Feng Wu, and also had
their signed-off-by.

If picking up someone else's work, normally the git "Author" should
be left unchanged, only the "Comitter" record changes (automatically)
to your name.

Similarly the existing Signed-Off-By should be left intact, with your
own Signed-Off-By just appended, ideally with an initialed note about
what you altered from the original patch. eg the end of the commit
would look like this:

  Signed-off-by: Chun Feng Wu <danielwuwy@163.com>
  [HR: changed blah, blah & blah ]
  Signed-off-by: Harikumar Rajkumar <harirajkumar230@gmail.com>


Same applies to pretty much every patch in this series which were
all creditted to Chun Feng Wu previously.

> ---
>  src/conf/domain_conf.c  | 300 ++++++++++++++++++++++++++++++++++++++++
>  src/conf/domain_conf.h  |  27 ++++
>  src/conf/virconftypes.h |   2 +
>  3 files changed, 329 insertions(+)
> 
> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
> index 87f87bbe56..fd08e67edc 100644
> --- a/src/conf/domain_conf.c
> +++ b/src/conf/domain_conf.c
> @@ -3799,6 +3799,32 @@ virDomainIOThreadIDDefArrayInit(virDomainDef *def,
>  }
>  
>  
> +void
> +virDomainThrottleGroupDefFree(virDomainThrottleGroupDef *def)
> +{
> +    if (!def)
> +        return;
> +    g_free(def->group_name);
> +    g_free(def);
> +}
> +
> +
> +static void
> +virDomainThrottleGroupDefArrayFree(virDomainThrottleGroupDef **def,
> +                                   int nthrottlegroups)
> +{
> +    size_t i;
> +
> +    if (!def)
> +        return;
> +
> +    for (i = 0; i < nthrottlegroups; i++)
> +        virDomainThrottleGroupDefFree(def[i]);
> +
> +    g_free(def);
> +}
> +
> +
>  void
>  virDomainResourceDefFree(virDomainResourceDef *resource)
>  {
> @@ -4086,6 +4112,8 @@ void virDomainDefFree(virDomainDef *def)
>  
>      virDomainIOThreadIDDefArrayFree(def->iothreadids, def->niothreadids);
>  
> +    virDomainThrottleGroupDefArrayFree(def->throttlegroups, def->nthrottlegroups);
> +
>      g_free(def->defaultIOThread);
>  
>      virBitmapFree(def->cputune.emulatorpin);
> @@ -7830,6 +7858,123 @@ virDomainDiskDefIotuneParse(virDomainDiskDef *def,
>  }
>  #undef PARSE_IOTUNE
>  
> +/* the field changes must also be applied to the other function that formats
> + * the <disk> throttling definition virDomainThrottleGroupFormat. */
> +#define PARSE_THROTTLEGROUP(val) \
> +    if (virXPathULongLong("string(./" #val ")", \
> +                          ctxt, &group->val) == -2) { \
> +        virReportError(VIR_ERR_XML_ERROR, \
> +                       _("throttle group field '%1$s' must be an integer"), #val); \
> +        return NULL; \
> +    }
> +
> +
> +static virDomainThrottleGroupDef *
> +virDomainThrottleGroupDefParseXML(xmlNodePtr node,
> +                                  xmlXPathContextPtr ctxt)
> +{
> +    g_autoptr(virDomainThrottleGroupDef) group = g_new0(virDomainThrottleGroupDef, 1);
> +
> +    VIR_XPATH_NODE_AUTORESTORE(ctxt)
> +    ctxt->node = node;
> +
> +    PARSE_THROTTLEGROUP(total_bytes_sec);
> +    PARSE_THROTTLEGROUP(read_bytes_sec);
> +    PARSE_THROTTLEGROUP(write_bytes_sec);
> +    PARSE_THROTTLEGROUP(total_iops_sec);
> +    PARSE_THROTTLEGROUP(read_iops_sec);
> +    PARSE_THROTTLEGROUP(write_iops_sec);
> +
> +    PARSE_THROTTLEGROUP(total_bytes_sec_max);
> +    PARSE_THROTTLEGROUP(read_bytes_sec_max);
> +    PARSE_THROTTLEGROUP(write_bytes_sec_max);
> +    PARSE_THROTTLEGROUP(total_iops_sec_max);
> +    PARSE_THROTTLEGROUP(read_iops_sec_max);
> +    PARSE_THROTTLEGROUP(write_iops_sec_max);
> +
> +    PARSE_THROTTLEGROUP(size_iops_sec);
> +
> +    PARSE_THROTTLEGROUP(total_bytes_sec_max_length);
> +    PARSE_THROTTLEGROUP(read_bytes_sec_max_length);
> +    PARSE_THROTTLEGROUP(write_bytes_sec_max_length);
> +    PARSE_THROTTLEGROUP(total_iops_sec_max_length);
> +    PARSE_THROTTLEGROUP(read_iops_sec_max_length);
> +    PARSE_THROTTLEGROUP(write_iops_sec_max_length);
> +
> +    /* group_name is required */
> +    if (!(group->group_name = virXPathString("string(./group_name)", ctxt))) {
> +        virReportError(VIR_ERR_XML_ERROR, "%s",
> +                       _("missing group name"));
> +        return NULL;
> +    }
> +
> +   return g_steal_pointer(&group);
> +}
> +#undef PARSE_THROTTLEGROUP
> +
> +
> +/**
> + * virDomainThrottleGroupByName:
> + * @def: domain definition
> + * @name: throttle group name
> + *
> + * search throttle group within domain definition
> + * by @name
> + *
> + * Returns a pointer to throttle group found.
> + */
> +virDomainThrottleGroupDef *
> +virDomainThrottleGroupByName(const virDomainDef *def,
> +                             const char *name)
> +{
> +    size_t i;
> +
> +    if (!def->throttlegroups || def->nthrottlegroups == 0)
> +        return NULL;
> +
> +    for (i = 0; i < def->nthrottlegroups; i++) {
> +        if (STREQ(def->throttlegroups[i]->group_name, name))
> +            return def->throttlegroups[i];
> +    }
> +
> +    return NULL;
> +}
> +
> +
> +static int
> +virDomainDefThrottleGroupsParse(virDomainDef *def,
> +                                xmlXPathContextPtr ctxt)
> +{
> +    size_t i;
> +    int n = 0;
> +    g_autofree xmlNodePtr *nodes = NULL;
> +
> +    if ((n = virXPathNodeSet("./throttlegroups/throttlegroup", ctxt, &nodes)) < 0)
> +        return -1;
> +
> +    if (n == 0)
> +        return 0;
> +
> +    def->throttlegroups = g_new0(virDomainThrottleGroupDef *, n);
> +
> +    for (i = 0; i < n; i++) {
> +        g_autoptr(virDomainThrottleGroupDef) group = NULL;
> +
> +        if (!(group = virDomainThrottleGroupDefParseXML(nodes[i], ctxt))) {
> +            return -1;
> +        }
> +
> +        if (virDomainThrottleGroupByName(def, group->group_name)) {
> +            virReportError(VIR_ERR_XML_ERROR,
> +                           _("duplicate group name '%1$s' found"),
> +                           group->group_name);
> +            return -1;
> +        }
> +        def->throttlegroups[def->nthrottlegroups++] = g_steal_pointer(&group);
> +    }
> +    return 0;
> +}
> +
>  
>  static int
>  virDomainDiskDefMirrorParse(virDomainDiskDef *def,
> @@ -19211,6 +19356,9 @@ virDomainDefParseXML(xmlXPathContextPtr ctxt,
>      if (virDomainDefParseBootOptions(def, ctxt, xmlopt, flags) < 0)
>          return NULL;
>  
> +    if (virDomainDefThrottleGroupsParse(def, ctxt) < 0)
> +        return NULL;
> +
>      /* analysis of the disk devices */
>      if ((n = virXPathNodeSet("./devices/disk", ctxt, &nodes)) < 0)
>          return NULL;
> @@ -22511,6 +22659,94 @@ virDomainIOThreadIDDel(virDomainDef *def,
>  }
>  
>  
> +/**
> + * virDomainThrottleGroupDefCopy:
> + * @src: throttle group to be copied from
> + * @dst: throttle group to be copied to
> + *
> + * copy throttle group content from @src to @dst,
> + * this function does not allocate memory for @dst - the caller must ensure
> + * @dst is already allocated before calling this function.
> + */
> +void
> +virDomainThrottleGroupDefCopy(const virDomainThrottleGroupDef *src,
> +                              virDomainThrottleGroupDef *dst)
> +{
> +    *dst = *src;
> +    dst->group_name = g_strdup(src->group_name);
> +}
> +
> +
> +/**
> + * virDomainThrottleGroupAdd:
> + * @def: domain definition
> + * @throttle_group: throttle group definition within domain
> + *
> + * add new throttle group into @def
> + *
> + * return a pointer to throttle group added
> + */
> +virDomainThrottleGroupDef *
> +virDomainThrottleGroupAdd(virDomainDef *def,
> +                          virDomainThrottleGroupDef *throttle_group)
> +{
> +    virDomainThrottleGroupDef * new_group =  g_new0(virDomainThrottleGroupDef, 1);
> +    virDomainThrottleGroupDefCopy(throttle_group, new_group);
> +    VIR_APPEND_ELEMENT_COPY(def->throttlegroups, def->nthrottlegroups, new_group);
> +    return new_group;
> +}
> +
> +
> +/**
> + * virDomainThrottleGroupUpdate:
> + * @def: domain definition
> + * @info: throttle group definition within domain
> + *
> + * Update corresponding throttle group in @def using new config @info. If a
> + * throttle group with given name doesn't exist this function does nothing.
> + */
> +void
> +virDomainThrottleGroupUpdate(virDomainDef *def,
> +                             virDomainThrottleGroupDef *info)
> +{
> +    size_t i;
> +
> +    if (!info->group_name)
> +        return;
> +
> +    for (i = 0; i < def->nthrottlegroups; i++) {
> +        virDomainThrottleGroupDef *t = def->throttlegroups[i];
> +
> +        if (STREQ_NULLABLE(t->group_name, info->group_name)) {
> +            VIR_FREE(t->group_name);
> +            virDomainThrottleGroupDefCopy(info, t);
> +        }
> +    }
> +}
> +
> +
> +/**
> + * virDomainThrottleGroupDel:
> + * @def: domain definition
> + * @name: throttle group name
> + *
> + * Delete throttle group @name in @def
> + */
> +void
> +virDomainThrottleGroupDel(virDomainDef *def,
> +                          const char *name)
> +{
> +    size_t i;
> +    for (i = 0; i < def->nthrottlegroups; i++) {
> +        if (STREQ_NULLABLE(def->throttlegroups[i]->group_name, name)) {
> +            virDomainThrottleGroupDefFree(def->throttlegroups[i]);
> +            VIR_DELETE_ELEMENT(def->throttlegroups, i, def->nthrottlegroups);
> +            return;
> +        }
> +    }
> +}
> +
> +
>  static int
>  virDomainEventActionDefFormat(virBuffer *buf,
>                                int type,
> @@ -27696,6 +27932,68 @@ virDomainDefIOThreadsFormat(virBuffer *buf,
>      virDomainDefaultIOThreadDefFormat(buf, def);
>  }
>  
> +/*
> + * the field changes must also be applied to the other function that parses
> + * the <disk> throttling definition virDomainThrottleGroupDefParseXML
> + */
> +#define FORMAT_THROTTLE_GROUP(val) \
> +        if (group->val > 0) { \
> +            virBufferAsprintf(&childBuf, "<" #val ">%llu</" #val ">\n", \
> +                              group->val); \
> +        }
> +
> +
> +static void
> +virDomainThrottleGroupFormat(virBuffer *buf,
> +                             virDomainThrottleGroupDef *group)
> +{
> +    g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf);
> +
> +    FORMAT_THROTTLE_GROUP(total_bytes_sec);
> +    FORMAT_THROTTLE_GROUP(read_bytes_sec);
> +    FORMAT_THROTTLE_GROUP(write_bytes_sec);
> +    FORMAT_THROTTLE_GROUP(total_iops_sec);
> +    FORMAT_THROTTLE_GROUP(read_iops_sec);
> +    FORMAT_THROTTLE_GROUP(write_iops_sec);
> +
> +    FORMAT_THROTTLE_GROUP(total_bytes_sec_max);
> +    FORMAT_THROTTLE_GROUP(read_bytes_sec_max);
> +    FORMAT_THROTTLE_GROUP(write_bytes_sec_max);
> +    FORMAT_THROTTLE_GROUP(total_iops_sec_max);
> +    FORMAT_THROTTLE_GROUP(read_iops_sec_max);
> +    FORMAT_THROTTLE_GROUP(write_iops_sec_max);
> +
> +    FORMAT_THROTTLE_GROUP(size_iops_sec);
> +
> +    FORMAT_THROTTLE_GROUP(total_bytes_sec_max_length);
> +    FORMAT_THROTTLE_GROUP(read_bytes_sec_max_length);
> +    FORMAT_THROTTLE_GROUP(write_bytes_sec_max_length);
> +    FORMAT_THROTTLE_GROUP(total_iops_sec_max_length);
> +    FORMAT_THROTTLE_GROUP(read_iops_sec_max_length);
> +    FORMAT_THROTTLE_GROUP(write_iops_sec_max_length);
> +
> +    virBufferEscapeString(&childBuf, "<group_name>%s</group_name>\n",
> +                          group->group_name);
> +
> +    virXMLFormatElement(buf, "throttlegroup", NULL, &childBuf);
> +}
> +
> +#undef FORMAT_THROTTLE_GROUP
> +
> +static void
> +virDomainDefThrottleGroupsFormat(virBuffer *buf,
> +                                 const virDomainDef *def)
> +{
> +    g_auto(virBuffer) childrenBuf = VIR_BUFFER_INIT_CHILD(buf);
> +    size_t n;
> +
> +    for (n = 0; n < def->nthrottlegroups; n++) {
> +        virDomainThrottleGroupFormat(&childrenBuf, def->throttlegroups[n]);
> +    }
> +
> +    virXMLFormatElement(buf, "throttlegroups", NULL, &childrenBuf);
> +}
> +
>  
>  static void
>  virDomainIOMMUDefFormat(virBuffer *buf,
> @@ -28398,6 +28696,8 @@ virDomainDefFormatInternalSetRootName(virDomainDef *def,
>  
>      virDomainDefIOThreadsFormat(buf, def);
>  
> +    virDomainDefThrottleGroupsFormat(buf, def);
> +
>      if (virDomainCputuneDefFormat(buf, def, flags) < 0)
>          return -1;
>  
> diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
> index e51c74b6d1..4977747d9c 100644
> --- a/src/conf/domain_conf.h
> +++ b/src/conf/domain_conf.h
> @@ -3079,6 +3079,9 @@ struct _virDomainDef {
>  
>      virDomainDefaultIOThreadDef *defaultIOThread;
>  
> +    size_t nthrottlegroups;
> +    virDomainThrottleGroupDef **throttlegroups;
> +
>      virDomainCputune cputune;
>  
>      virDomainResctrlDef **resctrls;
> @@ -4600,3 +4603,27 @@ virDomainObjGetMessages(virDomainObj *vm,
>  
>  bool
>  virDomainDefHasSpiceGraphics(const virDomainDef *def);
> +
> +void
> +virDomainThrottleGroupDefFree(virDomainThrottleGroupDef *def);
> +G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainThrottleGroupDef, virDomainThrottleGroupDefFree);
> +
> +virDomainThrottleGroupDef *
> +virDomainThrottleGroupAdd(virDomainDef *def,
> +                          virDomainThrottleGroupDef *throttle_group);
> +
> +void
> +virDomainThrottleGroupUpdate(virDomainDef *def,
> +                             virDomainThrottleGroupDef *info);
> +
> +void
> +virDomainThrottleGroupDel(virDomainDef *def,
> +                          const char *name);
> +
> +virDomainThrottleGroupDef *
> +virDomainThrottleGroupByName(const virDomainDef *def,
> +                             const char *name);
> +
> +void
> +virDomainThrottleGroupDefCopy(const virDomainThrottleGroupDef *src,
> +                              virDomainThrottleGroupDef *dst);
> diff --git a/src/conf/virconftypes.h b/src/conf/virconftypes.h
> index 59be61cea4..1936ef6ab1 100644
> --- a/src/conf/virconftypes.h
> +++ b/src/conf/virconftypes.h
> @@ -80,6 +80,8 @@ typedef struct _virDomainBlkiotune virDomainBlkiotune;
>  
>  typedef struct _virDomainBlockIoTuneInfo virDomainBlockIoTuneInfo;
>  
> +typedef struct _virDomainBlockIoTuneInfo  virDomainThrottleGroupDef;
> +
>  typedef struct _virDomainCheckpointDef virDomainCheckpointDef;
>  
>  typedef struct _virDomainCheckpointObj virDomainCheckpointObj;
> -- 
> 2.39.5 (Apple Git-154)
> 

With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
Re: [PATCH v7 03/18] config: Introduce ThrottleGroup and corresponding XML parsing
Posted by Harikumar Rajkumar 10 months ago
> On Wed, Feb 12, 2025 at 04:05:22PM +0530, Harikumar Rajkumar wrote:
> 
> When this patch was posted in v6:
> 
>  
> https://lists.libvirt.org/archives/list/devel@lists.libvirt.org/message/V...
> 
> The authorship was credited to Chun Feng Wu, and also had
> their signed-off-by.
> 
> If picking up someone else's work, normally the git "Author" should
> be left unchanged, only the "Comitter" record changes (automatically)
> to your name.
> 
> Similarly the existing Signed-Off-By should be left intact, with your
> own Signed-Off-By just appended, ideally with an initialed note about
> what you altered from the original patch. eg the end of the commit
> would look like this:
> 
>   Signed-off-by: Chun Feng Wu <danielwuwy(a)163.com&gt;
>   [HR: changed blah, blah & blah ]
>   Signed-off-by: Harikumar Rajkumar <harirajkumar230(a)gmail.com&gt;
> 
> 
> Same applies to pretty much every patch in this series which were
> all creditted to Chun Feng Wu previously.
> 
> 
> With regards,
> Daniel

Thank you for letting us know about this sign-off process. We will follow this process for the next patch submission. Would you like me to submit a new patch with this sign-off fix?
Re: [PATCH v7 03/18] config: Introduce ThrottleGroup and corresponding XML parsing
Posted by Daniel P. Berrangé 10 months ago
On Wed, Feb 19, 2025 at 10:44:25AM -0000, Harikumar Rajkumar wrote:
> > On Wed, Feb 12, 2025 at 04:05:22PM +0530, Harikumar Rajkumar wrote:
> > 
> > When this patch was posted in v6:
> > 
> >  
> > https://lists.libvirt.org/archives/list/devel@lists.libvirt.org/message/V...
> > 
> > The authorship was credited to Chun Feng Wu, and also had
> > their signed-off-by.
> > 
> > If picking up someone else's work, normally the git "Author" should
> > be left unchanged, only the "Comitter" record changes (automatically)
> > to your name.
> > 
> > Similarly the existing Signed-Off-By should be left intact, with your
> > own Signed-Off-By just appended, ideally with an initialed note about
> > what you altered from the original patch. eg the end of the commit
> > would look like this:
> > 
> >   Signed-off-by: Chun Feng Wu <danielwuwy(a)163.com&gt;
> >   [HR: changed blah, blah & blah ]
> >   Signed-off-by: Harikumar Rajkumar <harirajkumar230(a)gmail.com&gt;
> > 
> > 
> > Same applies to pretty much every patch in this series which were
> > all creditted to Chun Feng Wu previously.
> > 
> 
> Thank you for letting us know about this sign-off process. We will
> follow this process for the next patch submission. Would you like
> me to submit a new patch with this sign-off fix?

Yes, please do.

With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|