Re: [PATCH RFC v2 05/12] qemu: hotplug: Support hot attach block disk along with throttle filters

2024-05-03 Thread Peter Krempa
On Thu, Apr 11, 2024 at 19:01:53 -0700, w...@linux.ibm.com wrote:
> From: Chun Feng Wu 
> 
> When attaching disk along with specified throttle groups, those groups will 
> be chained up by parent node name, this change includes service side codes:
> * Each filter references one throttle group by group name
> * Each filter has a nodename, and those filters are chained up in sequence
> * Filter nodename index is persistented in 
> virDomainObj->privateData(qemuDomainObjPrivate)
> * During hotplug, filter is created through QMP request("blockdev-add" with 
> "driver":"throttle") to QEMU
> * Finally, "device_add"(attach) QMP request is adjusted to set "drive" to be 
> top filter nodename in chain.
> 
> Signed-off-by: Chun Feng Wu 
> ---a

As noted before, the proper approach is to add the XML bits first so
some asumptions may be off.

Before next version please add implementation only after the XML and
docs is added.

>  src/qemu/qemu_block.c | 131 ++
>  src/qemu/qemu_block.h |  53 +++
>  src/qemu/qemu_command.c   |  64 +
>  src/qemu/qemu_command.h   |   6 +
>  src/qemu/qemu_domain.c|  71 ++
>  src/qemu/qemu_domain.h|  19 ++-
>  src/qemu/qemu_hotplug.c   |  24 
>  .../qemustatusxml2xmldata/backup-pull-in.xml  |   1 +
>  .../blockjob-blockdev-in.xml  |   1 +
>  .../blockjob-mirror-in.xml|   1 +
>  .../migration-in-params-in.xml|   1 +
>  .../migration-out-nbd-bitmaps-in.xml  |   1 +
>  .../migration-out-nbd-out.xml |   1 +
>  .../migration-out-nbd-tls-out.xml |   1 +
>  .../migration-out-params-in.xml   |   1 +
>  tests/qemustatusxml2xmldata/modern-in.xml |   1 +
>  tests/qemustatusxml2xmldata/upgrade-out.xml   |   1 +
>  .../qemustatusxml2xmldata/vcpus-multi-in.xml  |   1 +
>  18 files changed, 375 insertions(+), 4 deletions(-)
> 
> diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c
> index 738b72d7ea..c53de2465e 100644
> --- a/src/qemu/qemu_block.c
> +++ b/src/qemu/qemu_block.c
> @@ -2739,6 +2739,137 @@ qemuBlockStorageSourceCreateDetectSize(GHashTable 
> *blockNamedNodeData,
>  }
>  
>  
> +void
> +qemuBlockThrottleFilterSetNodename(virDomainThrottleFilterDef *filter,
> +   char *nodename)
> +{
> +g_free(filter->nodename);
> +filter->nodename = nodename;
> +}
> +
> +
> +const char *
> +qemuBlockThrottleFilterGetNodename(virDomainThrottleFilterDef *filter)
> +{
> +return filter->nodename;
> +}
> +
> +
> +/**
> + * qemuBlockThrottleFilterGetProps:
> + * @filter: throttle filter
> + * @parentNodeName: parent nodename of @filter
> + *
> + * Build "arguments" part of "blockdev-add" QMP cmd.
> + * e.g. {"execute":"blockdev-add", "arguments":{"driver":"throttle",
> + * "node-name":"libvirt-2-filter",  "throttle-group":"limits0",
> + * "file": "libvirt-1-format"}}



> + */
> +virJSONValue *
> +qemuBlockThrottleFilterGetProps(virDomainThrottleFilterDef *filter,
> +const char *parentNodeName)
> +{
> +g_autoptr(virJSONValue) props = NULL;
> +
> +if (virJSONValueObjectAdd(&props,
> +  "s:driver", "throttle",
> +  "s:node-name", 
> qemuBlockThrottleFilterGetNodename(filter),
> +  "s:throttle-group", filter->group_name,
> +  "s:file", parentNodeName,
> +  NULL) < 0)
> +return 0;
> +
> +return g_steal_pointer(&props);
> +}
> +
> +
> +void
> +qemuBlockThrottleFilterAttachDataFree(qemuBlockThrottleFilterAttachData 
> *data)
> +{
> +if (!data)
> +return;
> +
> +virJSONValueFree(data->filterProps);
> +g_free(data);
> +}
> +
> +
> +qemuBlockThrottleFilterAttachData *
> +qemuBlockThrottleFilterAttachPrepareBlockdev(virDomainThrottleFilterDef 
> *filter,
> + const char *parentNodeName)
> +{
> +g_autoptr(qemuBlockThrottleFilterAttachData) data = NULL;
> +
> +data = g_new0(qemuBlockThrottleFilterAttachData, 1);
> +
> +if (!(data->filterProps = qemuBlockThrottleFilterGetProps(filter, 
> parentNodeName)))
> +return NULL;
> +
> +data->filterNodeName = qemuBlockThrottleFilterGetNodename(filter);
> +data->filterAttached = true;

You can't claim that the filter node was attached at this point. The
rollback code won't work properly.

> +
> +return g_steal_pointer(&data);
> +}
> +
> +
> +void
> +qemuBlockThrottleFilterAttachRollback(qemuMonitor *mon,
> +  qemuBlockThrottleFilterAttachData 
> *data)
> +{
> +virErrorPtr orig_err;
> +
> +virErrorPreserveLast(&orig_err);
> +
> +if (data->filterAttached)
> +ignore_value(qemuMonitorBlockdevDel(mon, data->filterN

[PATCH RFC v2 05/12] qemu: hotplug: Support hot attach block disk along with throttle filters

2024-04-11 Thread wucf
From: Chun Feng Wu 

When attaching disk along with specified throttle groups, those groups will be 
chained up by parent node name, this change includes service side codes:
* Each filter references one throttle group by group name
* Each filter has a nodename, and those filters are chained up in sequence
* Filter nodename index is persistented in 
virDomainObj->privateData(qemuDomainObjPrivate)
* During hotplug, filter is created through QMP request("blockdev-add" with 
"driver":"throttle") to QEMU
* Finally, "device_add"(attach) QMP request is adjusted to set "drive" to be 
top filter nodename in chain.

Signed-off-by: Chun Feng Wu 
---
 src/qemu/qemu_block.c | 131 ++
 src/qemu/qemu_block.h |  53 +++
 src/qemu/qemu_command.c   |  64 +
 src/qemu/qemu_command.h   |   6 +
 src/qemu/qemu_domain.c|  71 ++
 src/qemu/qemu_domain.h|  19 ++-
 src/qemu/qemu_hotplug.c   |  24 
 .../qemustatusxml2xmldata/backup-pull-in.xml  |   1 +
 .../blockjob-blockdev-in.xml  |   1 +
 .../blockjob-mirror-in.xml|   1 +
 .../migration-in-params-in.xml|   1 +
 .../migration-out-nbd-bitmaps-in.xml  |   1 +
 .../migration-out-nbd-out.xml |   1 +
 .../migration-out-nbd-tls-out.xml |   1 +
 .../migration-out-params-in.xml   |   1 +
 tests/qemustatusxml2xmldata/modern-in.xml |   1 +
 tests/qemustatusxml2xmldata/upgrade-out.xml   |   1 +
 .../qemustatusxml2xmldata/vcpus-multi-in.xml  |   1 +
 18 files changed, 375 insertions(+), 4 deletions(-)

diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c
index 738b72d7ea..c53de2465e 100644
--- a/src/qemu/qemu_block.c
+++ b/src/qemu/qemu_block.c
@@ -2739,6 +2739,137 @@ qemuBlockStorageSourceCreateDetectSize(GHashTable 
*blockNamedNodeData,
 }
 
 
+void
+qemuBlockThrottleFilterSetNodename(virDomainThrottleFilterDef *filter,
+   char *nodename)
+{
+g_free(filter->nodename);
+filter->nodename = nodename;
+}
+
+
+const char *
+qemuBlockThrottleFilterGetNodename(virDomainThrottleFilterDef *filter)
+{
+return filter->nodename;
+}
+
+
+/**
+ * qemuBlockThrottleFilterGetProps:
+ * @filter: throttle filter
+ * @parentNodeName: parent nodename of @filter
+ *
+ * Build "arguments" part of "blockdev-add" QMP cmd.
+ * e.g. {"execute":"blockdev-add", "arguments":{"driver":"throttle",
+ * "node-name":"libvirt-2-filter",  "throttle-group":"limits0",
+ * "file": "libvirt-1-format"}}
+ */
+virJSONValue *
+qemuBlockThrottleFilterGetProps(virDomainThrottleFilterDef *filter,
+const char *parentNodeName)
+{
+g_autoptr(virJSONValue) props = NULL;
+
+if (virJSONValueObjectAdd(&props,
+  "s:driver", "throttle",
+  "s:node-name", 
qemuBlockThrottleFilterGetNodename(filter),
+  "s:throttle-group", filter->group_name,
+  "s:file", parentNodeName,
+  NULL) < 0)
+return 0;
+
+return g_steal_pointer(&props);
+}
+
+
+void
+qemuBlockThrottleFilterAttachDataFree(qemuBlockThrottleFilterAttachData *data)
+{
+if (!data)
+return;
+
+virJSONValueFree(data->filterProps);
+g_free(data);
+}
+
+
+qemuBlockThrottleFilterAttachData *
+qemuBlockThrottleFilterAttachPrepareBlockdev(virDomainThrottleFilterDef 
*filter,
+ const char *parentNodeName)
+{
+g_autoptr(qemuBlockThrottleFilterAttachData) data = NULL;
+
+data = g_new0(qemuBlockThrottleFilterAttachData, 1);
+
+if (!(data->filterProps = qemuBlockThrottleFilterGetProps(filter, 
parentNodeName)))
+return NULL;
+
+data->filterNodeName = qemuBlockThrottleFilterGetNodename(filter);
+data->filterAttached = true;
+
+return g_steal_pointer(&data);
+}
+
+
+void
+qemuBlockThrottleFilterAttachRollback(qemuMonitor *mon,
+  qemuBlockThrottleFilterAttachData *data)
+{
+virErrorPtr orig_err;
+
+virErrorPreserveLast(&orig_err);
+
+if (data->filterAttached)
+ignore_value(qemuMonitorBlockdevDel(mon, data->filterNodeName));
+
+virErrorRestore(&orig_err);
+}
+
+
+void
+qemuBlockThrottleFilterChainDataFree(qemuBlockThrottleFilterChainData *data)
+{
+size_t i;
+
+if (!data)
+return;
+
+for (i = 0; i < data->nfilterdata; i++)
+qemuBlockThrottleFilterAttachDataFree(data->filterdata[i]);
+
+g_free(data->filterdata);
+g_free(data);
+}
+
+
+int
+qemuBlockThrottleFilterChainAttach(qemuMonitor *mon,
+   qemuBlockThrottleFilterChainData *data)
+{
+size_t i;
+
+for (i = 0; i < data->nfilterdata; i++) {
+if (qemuMonitorBlockdevAdd(mon, &data->filterdata[