From: Chun Feng Wu <wucf(a)linux.ibm.com>
Support throttlegroup lifecycle management by the following implementation:
* New methods defined in "include/libvirt/libvirt-domain.h"
* And they're exported in "src/libvirt_public.syms"
* Corresponding internal API is defined in "src/driver-hypervisor.h"
* Public API calls are implemented in "src/libvirt-domain.c"
* Wire protocol is defined in "src/remote/remote_protocol.x"
* RPC client implementation is in "src/remote/remote_driver.c"
* Server side dispatch is implemented in "src/remote/remote_daemon_dispatch.c"
* Also "src/remote_protocol-structs" is updated
Signed-off-by: Chun Feng Wu <wucf(a)linux.ibm.com>
---
include/libvirt/libvirt-domain.h | 29 ++
src/driver-hypervisor.h | 22 ++
src/libvirt-domain.c | 188 ++++++++++
src/libvirt_private.syms | 9 +
src/libvirt_public.syms | 7 +
src/qemu/qemu_domain.c | 12 +
src/qemu/qemu_domain.h | 2 +
src/qemu/qemu_driver.c | 515 ++++++++++++++++++++++++++++
src/remote/remote_daemon_dispatch.c | 60 ++++
src/remote/remote_driver.c | 46 +++
src/remote/remote_protocol.x | 50 ++-
src/remote_protocol-structs | 21 ++
12 files changed, 960 insertions(+), 1 deletion(-)
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index 2f5b01bbfe..5435ab7fcb 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -5593,6 +5593,16 @@ typedef void
(*virConnectDomainEventJobCompletedCallback)(virConnectPtr conn,
*/
# define VIR_DOMAIN_TUNABLE_BLKDEV_WRITE_IOPS_SEC_MAX_LENGTH
"blkdeviotune.write_iops_sec_max_length"
+/**
+ * VIR_DOMAIN_THROTTLE_GROUP:
+ *
+ * Macro represents the name of throttle group for which the values are updated,
+ * as VIR_TYPED_PARAM_STRING.
+ *
+ * Since: 10.3.0
+ */
+# define VIR_DOMAIN_THROTTLE_GROUP "throttlegroup.name"
+
/**
* virConnectDomainEventTunableCallback:
* @conn: connection object
@@ -6525,4 +6535,23 @@ virDomainGraphicsReload(virDomainPtr domain,
unsigned int type,
unsigned int flags);
+int
+virDomainSetThrottleGroup(virDomainPtr dom,
+ const char *group,
+ virTypedParameterPtr params,
+ int nparams,
+ unsigned int flags);
+int
+virDomainGetThrottleGroup(virDomainPtr dom,
+ const char *group,
+ virTypedParameterPtr params,
+ int *nparams,
+ unsigned int flags);
+
+int
+virDomainDelThrottleGroup(virDomainPtr dom,
+ const char *group,
+ unsigned int flags);
+
+
#endif /* LIBVIRT_DOMAIN_H */
diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h
index 4ce8da078d..2c81fc8ad6 100644
--- a/src/driver-hypervisor.h
+++ b/src/driver-hypervisor.h
@@ -1453,6 +1453,25 @@ typedef int
unsigned int type,
unsigned int flags);
+typedef int
+(*virDrvDomainSetThrottleGroup)(virDomainPtr dom,
+ const char *groupname,
+ virTypedParameterPtr params,
+ int nparams,
+ unsigned int flags);
+
+typedef int
+(*virDrvDomainGetThrottleGroup)(virDomainPtr dom,
+ const char *groupname,
+ virTypedParameterPtr params,
+ int *nparams,
+ unsigned int flags);
+
+typedef int
+(*virDrvDomainDelThrottleGroup)(virDomainPtr dom,
+ const char *groupname,
+ unsigned int flags);
+
typedef struct _virHypervisorDriver virHypervisorDriver;
/**
@@ -1726,4 +1745,7 @@ struct _virHypervisorDriver {
virDrvDomainStartDirtyRateCalc domainStartDirtyRateCalc;
virDrvDomainFDAssociate domainFDAssociate;
virDrvDomainGraphicsReload domainGraphicsReload;
+ virDrvDomainSetThrottleGroup domainSetThrottleGroup;
+ virDrvDomainGetThrottleGroup domainGetThrottleGroup;
+ virDrvDomainDelThrottleGroup domainDelThrottleGroup;
};
diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
index 7c6b93963c..61c67e2392 100644
--- a/src/libvirt-domain.c
+++ b/src/libvirt-domain.c
@@ -14162,3 +14162,191 @@ virDomainGraphicsReload(virDomainPtr domain,
virDispatchError(domain->conn);
return -1;
}
+
+/**
+ * virDomainSetThrottleGroup:
+ * @dom: pointer to domain object
+ * @group: throttle group name
+ * @params: Pointer to blkio parameter objects
+ * @nparams: Number of blkio parameters (this value can be the same or
+ * less than the number of parameters supported)
+ * @flags: bitwise-OR of virDomainModificationImpact
+ *
+ * add or change throttle group.
+ *
+ *
+ * Returns -1 in case of error, 0 in case of success.
+ *
+ * Since: 10.3.0
+ */
+int
+virDomainSetThrottleGroup(virDomainPtr dom,
+ const char *group,
+ virTypedParameterPtr params,
+ int nparams,
+ unsigned int flags)
+{
+ virConnectPtr conn;
+
+ VIR_DOMAIN_DEBUG(dom, "params=%p, nparams=%d, flags=0x%x",
+ params, nparams, flags);
+ VIR_TYPED_PARAMS_DEBUG(params, nparams);
+
+ virResetLastError();
+
+ virCheckDomainReturn(dom, -1);
+ conn = dom->conn;
+
+ virCheckReadOnlyGoto(conn->flags, error);
+ virCheckPositiveArgGoto(nparams, error);
+ virCheckNonNullArgGoto(params, error);
+
+ if (virTypedParameterValidateSet(dom->conn, params, nparams) < 0)
+ goto error;
+
+ if (conn->driver->domainSetThrottleGroup) {
+ int ret;
+ ret = conn->driver->domainSetThrottleGroup(dom, group, params, nparams,
flags);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virReportUnsupportedError();
+
+ error:
+ virDispatchError(dom->conn);
+ return -1;
+}
+
+
+/**
+ * virDomainGetThrottleGroup:
+ * @dom: pointer to domain object
+ * @group: throttle group name
+ * @params: Pointer to blkio parameter object
+ * (return value, allocated by the caller)
+ * @nparams: Pointer to number of blkio parameters
+ * @flags: bitwise-OR of virDomainModificationImpact and virTypedParameterFlags
+ *
+ * Get all parameters for specific throttle group. On input,
+ * @nparams gives the size of the @params array; on output, @nparams
+ * gives how many slots were filled with parameter information, which
+ * might be less but will not exceed the input value.
+ *
+ * As a special case, calling with @params as NULL and @nparams as 0
+ * on input will cause @nparams on output to contain the number of
+ * parameters supported by the hypervisor, either for the given @group
+ * or if @group is NULL, for all possible groups. The
+ * caller should then allocate @params array,
+ * i.e. (sizeof(@virTypedParameter) * @nparams) bytes and call the API
+ * again. See virDomainGetMemoryParameters() for more details.
+ *
+ *
+ * Returns -1 in case of error, 0 in case of success.
+ *
+ * Since: 10.3.0
+ */
+int
+virDomainGetThrottleGroup(virDomainPtr dom,
+ const char *group,
+ virTypedParameterPtr params,
+ int *nparams,
+ unsigned int flags)
+{
+ virConnectPtr conn;
+ int rc;
+
+ VIR_DOMAIN_DEBUG(dom, "params=%p, nparams=%d, flags=0x%x",
+ params, (nparams) ? *nparams : -1, flags);
+
+ virResetLastError();
+
+ virCheckDomainReturn(dom, -1);
+
+ virCheckNonNullArgGoto(nparams, error);
+ virCheckNonNegativeArgGoto(*nparams, error);
+ if (*nparams != 0) {
+ virCheckNonNullArgGoto(params, error);
+ virCheckNonNullArgGoto(group, error);
+ }
+
+ rc = VIR_DRV_SUPPORTS_FEATURE(dom->conn->driver, dom->conn,
+ VIR_DRV_FEATURE_TYPED_PARAM_STRING);
+ if (rc < 0)
+ goto error;
+ if (rc)
+ flags |= VIR_TYPED_PARAM_STRING_OKAY;
+
+ VIR_EXCLUSIVE_FLAGS_GOTO(VIR_DOMAIN_AFFECT_LIVE,
+ VIR_DOMAIN_AFFECT_CONFIG,
+ error);
+
+ conn = dom->conn;
+
+ if (conn->driver->domainGetThrottleGroup) {
+ int ret;
+ ret = conn->driver->domainGetThrottleGroup(dom, group, params, nparams,
flags);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virReportUnsupportedError();
+
+ error:
+ virDispatchError(dom->conn);
+ return -1;
+}
+
+/**
+ * virDomainDelThrottleGroup:
+ * @dom: pointer to domain object
+ * @group: throttle group name
+ * @flags: bitwise-OR of virDomainModificationImpact and virTypedParameterFlags
+ *
+ * Delete specific throttle group
+ *
+ * Returns -1 in case of error, 0 in case of success.
+ *
+ * Since: 10.3.0
+ */
+int
+virDomainDelThrottleGroup(virDomainPtr dom,
+ const char *group,
+ unsigned int flags)
+{
+ virConnectPtr conn;
+ int rc;
+
+ virResetLastError();
+
+ virCheckDomainReturn(dom, -1);
+
+ rc = VIR_DRV_SUPPORTS_FEATURE(dom->conn->driver, dom->conn,
+ VIR_DRV_FEATURE_TYPED_PARAM_STRING);
+ if (rc < 0)
+ goto error;
+ if (rc)
+ flags |= VIR_TYPED_PARAM_STRING_OKAY;
+
+ VIR_EXCLUSIVE_FLAGS_GOTO(VIR_DOMAIN_AFFECT_LIVE,
+ VIR_DOMAIN_AFFECT_CONFIG,
+ error);
+
+ conn = dom->conn;
+
+ if (conn->driver->domainDelThrottleGroup) {
+ int ret;
+ ret = conn->driver->domainDelThrottleGroup(dom, group, flags);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virReportUnsupportedError();
+
+ error:
+ virDispatchError(dom->conn);
+ return -1;
+}
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 84e30b711c..291844d933 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -668,6 +668,15 @@ virDomainTaintMessageTypeFromString;
virDomainTaintMessageTypeToString;
virDomainTaintTypeFromString;
virDomainTaintTypeToString;
+virDomainThrottleFilterDefFree;
+virDomainThrottleFilterFind;
+virDomainThrottleGroupAdd;
+virDomainThrottleGroupByName;
+virDomainThrottleGroupDefCopy;
+virDomainThrottleGroupDefFree;
+virDomainThrottleGroupDel;
+virDomainThrottleGroupFind;
+virDomainThrottleGroupUpdate;
virDomainTimerModeTypeFromString;
virDomainTimerModeTypeToString;
virDomainTimerNameTypeFromString;
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 7a3492d9d7..25560bb501 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -948,4 +948,11 @@ LIBVIRT_10.2.0 {
virDomainGraphicsReload;
} LIBVIRT_10.1.0;
+LIBVIRT_10.3.0 {
+ global:
+ virDomainSetThrottleGroup;
+ virDomainGetThrottleGroup;
+ virDomainDelThrottleGroup;
+} LIBVIRT_10.2.0;
+
# .... define new API here using predicted next version number ....
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 6b869797a8..7d1c1430ab 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -10245,6 +10245,18 @@ qemuDomainDiskByName(virDomainDef *def,
return ret;
}
+virDomainThrottleGroupDef *
+qemuDomainThrottleGroupByName(virDomainDef *def,
+ const char *name)
+{
+ virDomainThrottleGroupDef *ret;
+
+ if (!(ret = virDomainThrottleGroupByName(def, name))) {
+ return NULL;
+ }
+
+ return ret;
+}
int
qemuDomainPrepareChannel(virDomainChrDef *channel,
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index bd37cb245a..6343383bf7 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -880,6 +880,8 @@ int qemuDomainSetPrivatePaths(virQEMUDriver *driver,
virDomainDiskDef *qemuDomainDiskByName(virDomainDef *def, const char *name);
+virDomainThrottleGroupDef *qemuDomainThrottleGroupByName(virDomainDef *def, const char
*name);
+
char *qemuDomainGetMasterKeyFilePath(const char *libDir);
int qemuDomainMasterKeyReadFile(qemuDomainObjPrivate *priv);
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index d01f788aea..097366cefb 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -19995,6 +19995,518 @@ qemuDomainGraphicsReload(virDomainPtr domain,
return ret;
}
+/* wrapper of qemuDomainSetBlockIoTuneDefaults for throttle group since they use the same
data structure */
+static int
+qemuDomainSetThrottleGroupDefaults(virDomainBlockIoTuneInfo *newinfo,
+ virDomainBlockIoTuneInfo *oldinfo,
+ qemuBlockIoTuneSetFlags set_fields)
+{
+ return qemuDomainSetBlockIoTuneDefaults(newinfo, oldinfo, set_fields);
+}
+
+static int
+qemuDomainCheckThrottleGroupReset(const char *groupname,
+ virDomainBlockIoTuneInfo *newiotune)
+{
+ if (virDomainBlockIoTuneInfoHasAny(newiotune))
+ return 0;
+
+ if (newiotune->group_name &&
+ STRNEQ_NULLABLE(newiotune->group_name, groupname)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("creating a new group/updating existing with all parameters
zero is not supported"));
+ return -1;
+ }
+
+ /* all zero means remove any throttling and remove from group for qemu */
+ VIR_FREE(newiotune->group_name);
+
+ return 0;
+}
+
+static int
+qemuDomainSetThrottleGroup(virDomainPtr dom,
+ const char *groupname,
+ virTypedParameterPtr params,
+ int nparams,
+ unsigned int flags)
+{
+ virQEMUDriver *driver = dom->conn->privateData;
+ virDomainObj *vm = NULL;
+ virDomainDef *def = NULL;
+ virDomainDef *persistentDef = NULL;
+ virDomainThrottleGroupDef info = { 0 };
+ virDomainThrottleGroupDef conf_info = { 0 };
+ int ret = -1;
+ size_t i;
+ qemuBlockIoTuneSetFlags set_fields = 0;
+ g_autoptr(virQEMUDriverConfig) cfg = NULL;
+ virObjectEvent *event = NULL;
+ virTypedParameterPtr eventParams = NULL;
+ int eventNparams = 0;
+ int eventMaxparams = 0;
+ virDomainThrottleGroupDef *cur_info;
+ virDomainThrottleGroupDef *conf_cur_info;
+ int rc = 0;
+ g_autoptr(virJSONValue) props = NULL;
+ g_autoptr(virJSONValue) limits = NULL;
+
+
+ virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+ VIR_DOMAIN_AFFECT_CONFIG, -1);
+ if (virTypedParamsValidate(params, nparams,
+ VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC,
+ VIR_TYPED_PARAM_ULLONG,
+ VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC,
+ VIR_TYPED_PARAM_ULLONG,
+ VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC,
+ VIR_TYPED_PARAM_ULLONG,
+ VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC,
+ VIR_TYPED_PARAM_ULLONG,
+ VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC,
+ VIR_TYPED_PARAM_ULLONG,
+ VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC,
+ VIR_TYPED_PARAM_ULLONG,
+ VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC_MAX,
+ VIR_TYPED_PARAM_ULLONG,
+ VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC_MAX,
+ VIR_TYPED_PARAM_ULLONG,
+ VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC_MAX,
+ VIR_TYPED_PARAM_ULLONG,
+ VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC_MAX,
+ VIR_TYPED_PARAM_ULLONG,
+ VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC_MAX,
+ VIR_TYPED_PARAM_ULLONG,
+ VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC_MAX,
+ VIR_TYPED_PARAM_ULLONG,
+ VIR_DOMAIN_BLOCK_IOTUNE_SIZE_IOPS_SEC,
+ VIR_TYPED_PARAM_ULLONG,
+ VIR_DOMAIN_BLOCK_IOTUNE_GROUP_NAME,
+ VIR_TYPED_PARAM_STRING,
+ VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC_MAX_LENGTH,
+ VIR_TYPED_PARAM_ULLONG,
+ VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC_MAX_LENGTH,
+ VIR_TYPED_PARAM_ULLONG,
+ VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC_MAX_LENGTH,
+ VIR_TYPED_PARAM_ULLONG,
+ VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC_MAX_LENGTH,
+ VIR_TYPED_PARAM_ULLONG,
+ VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC_MAX_LENGTH,
+ VIR_TYPED_PARAM_ULLONG,
+ VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC_MAX_LENGTH,
+ VIR_TYPED_PARAM_ULLONG,
+ NULL) < 0)
+ return -1;
+
+ if (!(vm = qemuDomainObjFromDomain(dom)))
+ return -1;
+
+ if (virDomainSetThrottleGroupEnsureACL(dom->conn, vm->def, flags) < 0)
+ goto cleanup;
+
+ cfg = virQEMUDriverGetConfig(driver);
+
+ if (virDomainObjBeginJob(vm, VIR_JOB_MODIFY) < 0)
+ goto cleanup;
+
+ if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
+ goto endjob;
+
+ if (virTypedParamsAddString(&eventParams, &eventNparams,
&eventMaxparams,
+ VIR_DOMAIN_THROTTLE_GROUP, groupname) < 0)
+ goto endjob;
+
+#define SET_THROTTLE_FIELD(FIELD, BOOL, CONST) \
+ if (STREQ(param->field, VIR_DOMAIN_BLOCK_IOTUNE_##CONST)) { \
+ info.FIELD = param->value.ul; \
+ set_fields |= QEMU_BLOCK_IOTUNE_SET_##BOOL; \
+ if (virTypedParamsAddULLong(&eventParams, &eventNparams, \
+ &eventMaxparams, \
+ VIR_DOMAIN_TUNABLE_BLKDEV_##CONST, \
+ param->value.ul) < 0) \
+ goto endjob; \
+ continue; \
+ }
+
+ for (i = 0; i < nparams; i++) {
+ virTypedParameterPtr param = ¶ms[i];
+
+ if (param->value.ul > QEMU_BLOCK_IOTUNE_MAX) {
+ virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED,
+ _("throttle group value must be no more than
%1$llu"),
+ QEMU_BLOCK_IOTUNE_MAX);
+ goto endjob;
+ }
+
+ SET_THROTTLE_FIELD(total_bytes_sec, BYTES, TOTAL_BYTES_SEC);
+ SET_THROTTLE_FIELD(read_bytes_sec, BYTES, READ_BYTES_SEC);
+ SET_THROTTLE_FIELD(write_bytes_sec, BYTES, WRITE_BYTES_SEC);
+ SET_THROTTLE_FIELD(total_iops_sec, IOPS, TOTAL_IOPS_SEC);
+ SET_THROTTLE_FIELD(read_iops_sec, IOPS, READ_IOPS_SEC);
+ SET_THROTTLE_FIELD(write_iops_sec, IOPS, WRITE_IOPS_SEC);
+
+ SET_THROTTLE_FIELD(total_bytes_sec_max, BYTES_MAX,
+ TOTAL_BYTES_SEC_MAX);
+ SET_THROTTLE_FIELD(read_bytes_sec_max, BYTES_MAX,
+ READ_BYTES_SEC_MAX);
+ SET_THROTTLE_FIELD(write_bytes_sec_max, BYTES_MAX,
+ WRITE_BYTES_SEC_MAX);
+ SET_THROTTLE_FIELD(total_iops_sec_max, IOPS_MAX,
+ TOTAL_IOPS_SEC_MAX);
+ SET_THROTTLE_FIELD(read_iops_sec_max, IOPS_MAX,
+ READ_IOPS_SEC_MAX);
+ SET_THROTTLE_FIELD(write_iops_sec_max, IOPS_MAX,
+ WRITE_IOPS_SEC_MAX);
+ SET_THROTTLE_FIELD(size_iops_sec, SIZE_IOPS, SIZE_IOPS_SEC);
+
+ if (STREQ(param->field, VIR_DOMAIN_BLOCK_IOTUNE_GROUP_NAME)) {
+ info.group_name = g_strdup(param->value.s);
+ set_fields |= QEMU_BLOCK_IOTUNE_SET_GROUP_NAME;
+ if (virTypedParamsAddString(&eventParams, &eventNparams,
+ &eventMaxparams,
+ VIR_DOMAIN_TUNABLE_BLKDEV_GROUP_NAME,
+ param->value.s) < 0)
+ goto endjob;
+ continue;
+ }
+
+ SET_THROTTLE_FIELD(total_bytes_sec_max_length, BYTES_MAX_LENGTH,
+ TOTAL_BYTES_SEC_MAX_LENGTH);
+ SET_THROTTLE_FIELD(read_bytes_sec_max_length, BYTES_MAX_LENGTH,
+ READ_BYTES_SEC_MAX_LENGTH);
+ SET_THROTTLE_FIELD(write_bytes_sec_max_length, BYTES_MAX_LENGTH,
+ WRITE_BYTES_SEC_MAX_LENGTH);
+ SET_THROTTLE_FIELD(total_iops_sec_max_length, IOPS_MAX_LENGTH,
+ TOTAL_IOPS_SEC_MAX_LENGTH);
+ SET_THROTTLE_FIELD(read_iops_sec_max_length, IOPS_MAX_LENGTH,
+ READ_IOPS_SEC_MAX_LENGTH);
+ SET_THROTTLE_FIELD(write_iops_sec_max_length, IOPS_MAX_LENGTH,
+ WRITE_IOPS_SEC_MAX_LENGTH);
+ }
+
+#undef SET_THROTTLE_FIELD
+
+ if ((info.total_bytes_sec && info.read_bytes_sec) ||
+ (info.total_bytes_sec && info.write_bytes_sec)) {
+ virReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("total and read/write of bytes_sec cannot be set at the
same time"));
+ goto endjob;
+ }
+
+ if ((info.total_iops_sec && info.read_iops_sec) ||
+ (info.total_iops_sec && info.write_iops_sec)) {
+ virReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("total and read/write of iops_sec cannot be set at the same
time"));
+ goto endjob;
+ }
+
+ if ((info.total_bytes_sec_max && info.read_bytes_sec_max) ||
+ (info.total_bytes_sec_max && info.write_bytes_sec_max)) {
+ virReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("total and read/write of bytes_sec_max cannot be set at the
same time"));
+ goto endjob;
+ }
+
+ if ((info.total_iops_sec_max && info.read_iops_sec_max) ||
+ (info.total_iops_sec_max && info.write_iops_sec_max)) {
+ virReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("total and read/write of iops_sec_max cannot be set at the
same time"));
+ goto endjob;
+ }
+
+ virDomainThrottleGroupDefCopy(&info, &conf_info);
+
+ if (def) {
+ if (qemuDomainCheckThrottleGroupReset(groupname, &info) < 0)
+ goto endjob;
+
+#define CHECK_MAX(val, _bool) \
+ do { \
+ if (info.val##_max) { \
+ if (!info.val) { \
+ if (QEMU_BLOCK_IOTUNE_SET_##_bool) { \
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, \
+ _("cannot reset '%1$s' when
'%2$s' is set"), \
+ #val, #val "_max"); \
+ } else { \
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, \
+ _("value '%1$s' cannot be set if
'%2$s' is not set"), \
+ #val "_max", #val); \
+ } \
+ goto endjob; \
+ } \
+ if (info.val##_max < info.val) { \
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, \
+ _("value '%1$s' cannot be smaller than
'%2$s'"), \
+ #val "_max", #val); \
+ goto endjob; \
+ } \
+ } \
+ } while (false)
+
+ CHECK_MAX(total_bytes_sec, BYTES);
+ CHECK_MAX(read_bytes_sec, BYTES);
+ CHECK_MAX(write_bytes_sec, BYTES);
+ CHECK_MAX(total_iops_sec, IOPS);
+ CHECK_MAX(read_iops_sec, IOPS);
+ CHECK_MAX(write_iops_sec, IOPS);
+
+#undef CHECK_MAX
+
+ cur_info = qemuDomainThrottleGroupByName(def, groupname);
+ if (cur_info != NULL) { // update existing group
+ if (qemuDomainSetThrottleGroupDefaults(&info, cur_info,
+ set_fields) < 0)
+ goto endjob;
+ qemuDomainObjEnterMonitor(vm);
+ rc = qemuMonitorUpdateThrottleGroup(qemuDomainGetMonitor(vm),
+ groupname,
+ &info);
+ qemuDomainObjExitMonitor(vm);
+ if (rc < 0)
+ goto endjob;
+ virDomainThrottleGroupUpdate(def, &info);
+ }else{
+ limits = qemuMonitorThrottleGroupLimits(&info);
+ if (qemuMonitorCreateObjectProps(&props,
+ "throttle-group", groupname,
+ "a:limits", &limits,
+ NULL) < 0)
+ goto endjob;
+ qemuDomainObjEnterMonitor(vm);
+ rc = qemuMonitorAddObject(qemuDomainGetMonitor(vm), &props, NULL);
+ qemuDomainObjExitMonitor(vm);
+ if (rc < 0)
+ goto endjob;
+ virDomainThrottleGroupAdd(def, &info);
+ }
+
+ qemuDomainSaveStatus(vm);
+
+ if (eventNparams) {
+ event = virDomainEventTunableNewFromDom(dom, &eventParams,
eventNparams);
+ virObjectEventStateQueue(driver->domainEventState, event);
+ }
+ }
+
+ if (persistentDef) {
+ conf_cur_info = qemuDomainThrottleGroupByName(persistentDef, groupname);
+
+ if (qemuDomainCheckThrottleGroupReset(groupname, &conf_info) < 0)
+ goto endjob;
+
+ if (conf_cur_info != NULL) {
+ if (qemuDomainSetThrottleGroupDefaults(&conf_info, conf_cur_info,
+ set_fields) < 0)
+ goto endjob;
+ virDomainThrottleGroupUpdate(persistentDef, &conf_info);
+ }else{
+ virDomainThrottleGroupAdd(persistentDef, &conf_info);
+ }
+
+
+ if (virDomainDefSave(persistentDef, driver->xmlopt,
+ cfg->configDir) < 0)
+ goto endjob;
+ }
+
+ ret = 0;
+ endjob:
+ virDomainObjEndJob(vm);
+
+ cleanup:
+ virDomainObjEndAPI(&vm);
+ virTypedParamsFree(eventParams, eventNparams);
+ return ret;
+}
+
+static int
+qemuDomainGetThrottleGroup(virDomainPtr dom,
+ const char *groupname,
+ virTypedParameterPtr params,
+ int *nparams,
+ unsigned int flags)
+{
+ virDomainObj *vm = NULL;
+ virDomainDef *def = NULL;
+ virDomainDef *persistentDef = NULL;
+ virDomainThrottleGroupDef groupDef = { 0 };
+ virDomainThrottleGroupDef *reply = &groupDef;
+ int ret = -1;
+ int maxparams;
+ int rc = 0;
+
+ virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+ VIR_DOMAIN_AFFECT_CONFIG |
+ VIR_TYPED_PARAM_STRING_OKAY, -1);
+
+ /* We don't return strings, and thus trivially support this flag. */
+ flags &= ~VIR_TYPED_PARAM_STRING_OKAY;
+
+ if (!(vm = qemuDomainObjFromDomain(dom)))
+ return -1;
+
+ if (virDomainGetThrottleGroupEnsureACL(dom->conn, vm->def) < 0)
+ goto cleanup;
+
+ if (virDomainObjBeginJob(vm, VIR_JOB_QUERY) < 0)
+ goto cleanup;
+
+ /* the API check guarantees that only one of the definitions will be set */
+ if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
+ goto endjob;
+
+ maxparams = QEMU_NB_BLOCK_IO_TUNE_ALL_PARAMS;
+
+ if (*nparams == 0) {
+ *nparams = maxparams;
+ ret = 0;
+ goto endjob;
+ }
+ if (*nparams < maxparams)
+ maxparams = *nparams;
+
+ if (def) {
+ qemuDomainObjEnterMonitor(vm);
+ rc = qemuMonitorGetThrottleGroup(qemuDomainGetMonitor(vm), groupname, reply);
+ qemuDomainObjExitMonitor(vm);
+
+ if (rc < 0)
+ goto endjob;
+ }
+
+ if (persistentDef) {
+ reply = qemuDomainThrottleGroupByName(persistentDef, groupname);
+ if (reply == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("throttle group '%1$s' was not found in the
domain config"),
+ groupname);
+ goto endjob;
+ }
+ reply->group_name = g_strdup(groupname);
+ }
+
+ *nparams = 0;
+
+#define THROTTLE_GROUP_ASSIGN(name, var) \
+ if (*nparams < maxparams && \
+ virTypedParameterAssign(¶ms[(*nparams)++], \
+ VIR_DOMAIN_BLOCK_IOTUNE_ ## name, \
+ VIR_TYPED_PARAM_ULLONG, \
+ reply->var) < 0) \
+ goto endjob;
+
+ if (*nparams < maxparams) {
+ if (virTypedParameterAssign(¶ms[(*nparams)++],
+ VIR_DOMAIN_BLOCK_IOTUNE_GROUP_NAME,
+ VIR_TYPED_PARAM_STRING,
+ reply->group_name) < 0)
+ goto endjob;
+ }
+
+ THROTTLE_GROUP_ASSIGN(TOTAL_BYTES_SEC, total_bytes_sec);
+ THROTTLE_GROUP_ASSIGN(READ_BYTES_SEC, read_bytes_sec);
+ THROTTLE_GROUP_ASSIGN(WRITE_BYTES_SEC, write_bytes_sec);
+
+ THROTTLE_GROUP_ASSIGN(TOTAL_IOPS_SEC, total_iops_sec);
+ THROTTLE_GROUP_ASSIGN(READ_IOPS_SEC, read_iops_sec);
+ THROTTLE_GROUP_ASSIGN(WRITE_IOPS_SEC, write_iops_sec);
+
+ THROTTLE_GROUP_ASSIGN(TOTAL_BYTES_SEC_MAX, total_bytes_sec_max);
+ THROTTLE_GROUP_ASSIGN(READ_BYTES_SEC_MAX, read_bytes_sec_max);
+ THROTTLE_GROUP_ASSIGN(WRITE_BYTES_SEC_MAX, write_bytes_sec_max);
+
+ THROTTLE_GROUP_ASSIGN(TOTAL_IOPS_SEC_MAX, total_iops_sec_max);
+ THROTTLE_GROUP_ASSIGN(READ_IOPS_SEC_MAX, read_iops_sec_max);
+ THROTTLE_GROUP_ASSIGN(WRITE_IOPS_SEC_MAX, write_iops_sec_max);
+
+ THROTTLE_GROUP_ASSIGN(SIZE_IOPS_SEC, size_iops_sec);
+
+ THROTTLE_GROUP_ASSIGN(TOTAL_BYTES_SEC_MAX_LENGTH, total_bytes_sec_max_length);
+ THROTTLE_GROUP_ASSIGN(READ_BYTES_SEC_MAX_LENGTH, read_bytes_sec_max_length);
+ THROTTLE_GROUP_ASSIGN(WRITE_BYTES_SEC_MAX_LENGTH, write_bytes_sec_max_length);
+
+ THROTTLE_GROUP_ASSIGN(TOTAL_IOPS_SEC_MAX_LENGTH, total_iops_sec_max_length);
+ THROTTLE_GROUP_ASSIGN(READ_IOPS_SEC_MAX_LENGTH, read_iops_sec_max_length);
+ THROTTLE_GROUP_ASSIGN(WRITE_IOPS_SEC_MAX_LENGTH, write_iops_sec_max_length);
+#undef THROTTLE_GROUP_ASSIGN
+
+ ret = 0;
+
+ endjob:
+ virDomainObjEndJob(vm);
+
+ cleanup:
+ virDomainObjEndAPI(&vm);
+ return ret;
+}
+
+static int
+qemuDomainDelThrottleGroup(virDomainPtr dom,
+ const char *groupname,
+ unsigned int flags)
+{
+ virQEMUDriver *driver = dom->conn->privateData;
+ virDomainObj *vm = NULL;
+ virDomainDef *def = NULL;
+ virDomainDef *persistentDef = NULL;
+ g_autoptr(virQEMUDriverConfig) cfg = NULL;
+ int ret = -1;
+
+ virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+ VIR_DOMAIN_AFFECT_CONFIG |
+ VIR_TYPED_PARAM_STRING_OKAY, -1);
+
+ /* We don't return strings, and thus trivially support this flag. */
+ flags &= ~VIR_TYPED_PARAM_STRING_OKAY;
+
+ if (!(vm = qemuDomainObjFromDomain(dom)))
+ return -1;
+
+ cfg = virQEMUDriverGetConfig(driver);
+
+ if (virDomainDelThrottleGroupEnsureACL(dom->conn, vm->def) < 0)
+ goto cleanup;
+
+ if (virDomainObjBeginJob(vm, VIR_JOB_QUERY) < 0)
+ goto cleanup;
+
+ /* the API check guarantees that only one of the definitions will be set */
+ if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0)
+ goto endjob;
+
+
+ if (def) {
+ int rc = 0;
+
+ qemuDomainObjEnterMonitor(vm);
+ rc = qemuMonitorDelObject(qemuDomainGetMonitor(vm), groupname, true);
+ qemuDomainObjExitMonitor(vm);
+
+ if (rc < 0)
+ goto endjob;
+
+ virDomainThrottleGroupDel(def, groupname);
+ qemuDomainSaveStatus(vm);
+ }
+
+ if (persistentDef) {
+ virDomainThrottleGroupDel(persistentDef, groupname);
+ if (virDomainDefSave(persistentDef, driver->xmlopt,
+ cfg->configDir) < 0)
+ goto endjob;
+ }
+
+ ret = 0;
+
+ endjob:
+ virDomainObjEndJob(vm);
+
+ cleanup:
+ virDomainObjEndAPI(&vm);
+ return ret;
+}
+
static virHypervisorDriver qemuHypervisorDriver = {
.name = QEMU_DRIVER_NAME,
.connectURIProbe = qemuConnectURIProbe,
@@ -20245,6 +20757,9 @@ static virHypervisorDriver qemuHypervisorDriver = {
.domainSetLaunchSecurityState = qemuDomainSetLaunchSecurityState, /* 8.0.0 */
.domainFDAssociate = qemuDomainFDAssociate, /* 9.0.0 */
.domainGraphicsReload = qemuDomainGraphicsReload, /* 10.2.0 */
+ .domainSetThrottleGroup = qemuDomainSetThrottleGroup, /* 10.3.0 */
+ .domainGetThrottleGroup = qemuDomainGetThrottleGroup, /* 10.3.0 */
+ .domainDelThrottleGroup = qemuDomainDelThrottleGroup, /* 10.3.0 */
};
diff --git a/src/remote/remote_daemon_dispatch.c b/src/remote/remote_daemon_dispatch.c
index cfc1067e40..7d28d30e22 100644
--- a/src/remote/remote_daemon_dispatch.c
+++ b/src/remote/remote_daemon_dispatch.c
@@ -3614,6 +3614,66 @@ remoteDispatchDomainGetBlockIoTune(virNetServer *server
G_GNUC_UNUSED,
return rv;
}
+static int
+remoteDispatchDomainGetThrottleGroup(virNetServer *server G_GNUC_UNUSED,
+ virNetServerClient *client,
+ virNetMessage *hdr G_GNUC_UNUSED,
+ struct virNetMessageError *rerr,
+ remote_domain_get_throttle_group_args *args,
+ remote_domain_get_throttle_group_ret *ret)
+{
+ virDomainPtr dom = NULL;
+ int rv = -1;
+ virTypedParameterPtr params = NULL;
+ int nparams = 0;
+ virConnectPtr conn = remoteGetHypervisorConn(client);
+
+ if (!conn)
+ goto cleanup;
+
+ if (args->nparams > REMOTE_DOMAIN_THROTTLE_GROUP_PARAMETERS_MAX) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too
large"));
+ goto cleanup;
+ }
+
+ if (args->nparams)
+ params = g_new0(virTypedParameter, args->nparams);
+ nparams = args->nparams;
+
+ if (!(dom = get_nonnull_domain(conn, args->dom)))
+ goto cleanup;
+
+ if (virDomainGetThrottleGroup(dom, args->group ? *args->group : NULL,
+ params, &nparams, args->flags) < 0)
+ goto cleanup;
+
+ /* In this case, we need to send back the number of parameters
+ * supported
+ */
+ if (args->nparams == 0) {
+ ret->nparams = nparams;
+ goto success;
+ }
+
+ /* Serialize the block I/O tuning parameters. */
+ if (virTypedParamsSerialize(params, nparams,
+ REMOTE_DOMAIN_THROTTLE_GROUP_PARAMETERS_MAX,
+ (struct _virTypedParameterRemote **)
&ret->params.params_val,
+ &ret->params.params_len,
+ args->flags) < 0)
+ goto cleanup;
+
+ success:
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virTypedParamsFree(params, nparams);
+ virObjectUnref(dom);
+ return rv;
+}
+
/*-------------------------------------------------------------*/
static int
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 7b73d97b7a..4250729e27 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -2583,6 +2583,49 @@ static int remoteDomainGetBlockIoTune(virDomainPtr domain,
return 0;
}
+static int remoteDomainGetThrottleGroup(virDomainPtr domain,
+ const char *group,
+ virTypedParameterPtr params,
+ int *nparams,
+ unsigned int flags)
+{
+ remote_domain_get_throttle_group_args args = {0};
+ g_auto(remote_domain_get_throttle_group_ret) ret = {0};
+ struct private_data *priv = domain->conn->privateData;
+ VIR_LOCK_GUARD lock = remoteDriverLock(priv);
+
+ make_nonnull_domain(&args.dom, domain);
+ args.group = group ? (char **)&group : NULL;
+ args.nparams = *nparams;
+ args.flags = flags;
+
+ if (call(domain->conn, priv, 0, REMOTE_PROC_DOMAIN_GET_THROTTLE_GROUP,
+ (xdrproc_t) xdr_remote_domain_get_throttle_group_args,
+ (char *) &args,
+ (xdrproc_t) xdr_remote_domain_get_throttle_group_ret,
+ (char *) &ret) == -1) {
+ return -1;
+ }
+
+ /* Handle the case when the caller does not know the number of parameters
+ * and is asking for the number of parameters supported
+ */
+ if (*nparams == 0) {
+ *nparams = ret.nparams;
+ return 0;
+ }
+
+ if (virTypedParamsDeserialize((struct _virTypedParameterRemote *)
ret.params.params_val,
+ ret.params.params_len,
+ REMOTE_DOMAIN_THROTTLE_GROUP_PARAMETERS_MAX,
+ ¶ms,
+ nparams) < 0)
+ return -1;
+
+ return 0;
+
+}
+
static int remoteDomainGetCPUStats(virDomainPtr domain,
virTypedParameterPtr params,
unsigned int nparams,
@@ -7842,6 +7885,9 @@ static virHypervisorDriver hypervisor_driver = {
.domainSetLaunchSecurityState = remoteDomainSetLaunchSecurityState, /* 8.0.0 */
.domainFDAssociate = remoteDomainFDAssociate, /* 9.0.0 */
.domainGraphicsReload = remoteDomainGraphicsReload, /* 10.2.0 */
+ .domainSetThrottleGroup = remoteDomainSetThrottleGroup, /* 10.3.0 */
+ .domainGetThrottleGroup = remoteDomainGetThrottleGroup, /* 10.3.0 */
+ .domainDelThrottleGroup = remoteDomainDelThrottleGroup, /* 10.3.0 */
};
static virNetworkDriver network_driver = {
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index 41c045ff78..a7aa3d2d74 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -113,6 +113,9 @@ const REMOTE_DOMAIN_MEMORY_PARAMETERS_MAX = 16;
/* Upper limit on list of blockio tuning parameters. */
const REMOTE_DOMAIN_BLOCK_IO_TUNE_PARAMETERS_MAX = 32;
+/* Upper limit on list of throttle group parameters. */
+const REMOTE_DOMAIN_THROTTLE_GROUP_PARAMETERS_MAX = 32;
+
/* Upper limit on list of numa parameters. */
const REMOTE_DOMAIN_NUMA_PARAMETERS_MAX = 16;
@@ -1475,6 +1478,31 @@ struct remote_domain_get_block_io_tune_ret {
int nparams;
};
+struct remote_domain_set_throttle_group_args {
+ remote_nonnull_domain dom;
+ remote_nonnull_string group;
+ remote_typed_param params<REMOTE_DOMAIN_THROTTLE_GROUP_PARAMETERS_MAX>;
+ unsigned int flags;
+};
+
+struct remote_domain_get_throttle_group_args {
+ remote_nonnull_domain dom;
+ remote_string group;
+ int nparams;
+ unsigned int flags;
+};
+
+struct remote_domain_get_throttle_group_ret {
+ remote_typed_param params<REMOTE_DOMAIN_THROTTLE_GROUP_PARAMETERS_MAX>;
+ int nparams;
+};
+
+struct remote_domain_del_throttle_group_args {
+ remote_nonnull_domain dom;
+ remote_string group;
+ unsigned int flags;
+};
+
struct remote_domain_get_cpu_stats_args {
remote_nonnull_domain dom;
unsigned int nparams;
@@ -7048,5 +7076,25 @@ enum remote_procedure {
* @generate: both
* @acl: domain:write
*/
- REMOTE_PROC_DOMAIN_GRAPHICS_RELOAD = 448
+ REMOTE_PROC_DOMAIN_GRAPHICS_RELOAD = 448,
+
+ /**
+ * @generate: both
+ * @acl: domain:write
+ * @acl: domain:save:!VIR_DOMAIN_AFFECT_CONFIG|VIR_DOMAIN_AFFECT_LIVE
+ * @acl: domain:save:VIR_DOMAIN_AFFECT_CONFIG
+ */
+ REMOTE_PROC_DOMAIN_SET_THROTTLE_GROUP = 449,
+
+ /**
+ * @generate: none
+ * @acl: domain:read
+ */
+ REMOTE_PROC_DOMAIN_GET_THROTTLE_GROUP = 450,
+
+ /**
+ * @generate: both
+ * @acl: domain:read
+ */
+ REMOTE_PROC_DOMAIN_DEL_THROTTLE_GROUP = 451
};
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index 4d3dc2d249..0319a5690d 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -1050,6 +1050,24 @@ struct remote_domain_get_block_io_tune_ret {
} params;
int nparams;
};
+struct remote_domain_get_throttle_group_ret {
+ struct {
+ u_int params_len;
+ remote_typed_param * params_val;
+ } params;
+ int nparams;
+};
+struct remote_domain_get_throttle_group_args {
+ remote_nonnull_domain dom;
+ remote_string group;
+ int nparams;
+ u_int flags;
+};
+struct remote_domain_del_throttle_group_args {
+ remote_nonnull_domain dom;
+ remote_string group;
+ u_int flags;
+};
struct remote_domain_get_cpu_stats_args {
remote_nonnull_domain dom;
u_int nparams;
@@ -3755,4 +3773,7 @@ enum remote_procedure {
REMOTE_PROC_NETWORK_EVENT_CALLBACK_METADATA_CHANGE = 446,
REMOTE_PROC_NODE_DEVICE_UPDATE = 447,
REMOTE_PROC_DOMAIN_GRAPHICS_RELOAD = 448,
+ REMOTE_PROC_DOMAIN_SET_THROTTLE_GROUP = 449,
+ REMOTE_PROC_DOMAIN_GET_THROTTLE_GROUP = 450,
+ REMOTE_PROC_DOMAIN_DEL_THROTTLE_GROUP = 451,
};
--
2.34.1