[libvirt] [PATCH 0/2] Fix errors on unsuccessful chardev hotplug
by Ján Tomko
Ján Tomko (2):
Fix crash after attempting to hotplug a spicevmc channel
Display nicer error message for unsupported chardev hotplug
src/conf/domain_conf.c | 3 +--
src/qemu/qemu_monitor_json.c | 12 +++++++++---
2 files changed, 10 insertions(+), 5 deletions(-)
--
2.0.4
10 years, 1 month
[libvirt] [PATCH v7 4/7] qemu: Add bps_max and friends qemu driver
by Matthias Gatto
Add support for bps_max and friends in the driver part.
In the part checking if a qemu is running, check if the running binary
support bps_max, if not print an error message, if yes add it to
"info" variable
This patch follow therse patchs: http://www.redhat.com/archives/libvir-list/2014-November/msg00271.html
I've fix the syntax error and the nparams detection problem
Signed-off-by: Matthias Gatto <matthias.gatto(a)outscale.com>
---
include/libvirt/libvirt-domain.h | 56 +++++++++++
src/qemu/qemu_driver.c | 197 ++++++++++++++++++++++++++++++++++++---
src/qemu/qemu_monitor.c | 10 +-
src/qemu/qemu_monitor.h | 6 +-
src/qemu/qemu_monitor_json.c | 11 ++-
src/qemu/qemu_monitor_json.h | 6 +-
tests/qemumonitorjsontest.c | 4 +-
7 files changed, 264 insertions(+), 26 deletions(-)
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index 966a9ae..1fac2a3 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -3251,6 +3251,62 @@ typedef void (*virConnectDomainEventDeviceRemovedCallback)(virConnectPtr conn,
# define VIR_DOMAIN_TUNABLE_BLKDEV_WRITE_IOPS_SEC "blkdeviotune.write_iops_sec"
/**
+ * VIR_DOMAIN_TUNABLE_BLKDEV_TOTAL_BYTES_SEC_MAX:
+ *
+ * Marco represents the total throughput limit in maximum bytes per second,
+ * as VIR_TYPED_PARAM_ULLONG.
+ */
+# define VIR_DOMAIN_TUNABLE_BLKDEV_TOTAL_BYTES_SEC_MAX "blkdeviotune.total_bytes_sec_max"
+
+/**
+ * VIR_DOMAIN_TUNABLE_BLKDEV_READ_BYTES_SEC_MAX:
+ *
+ * Marco represents the read throughput limit in maximum bytes per second,
+ * as VIR_TYPED_PARAM_ULLONG.
+ */
+# define VIR_DOMAIN_TUNABLE_BLKDEV_READ_BYTES_SEC_MAX "blkdeviotune.read_bytes_sec_max"
+
+/**
+ * VIR_DOMAIN_TUNABLE_BLKDEV_WRITE_BYTES_SEC_MAX:
+ *
+ * Macro represents the write throughput limit in maximum bytes per second,
+ * as VIR_TYPED_PARAM_ULLONG.
+ */
+# define VIR_DOMAIN_TUNABLE_BLKDEV_WRITE_BYTES_SEC_MAX "blkdeviotune.write_bytes_sec_max"
+
+/**
+ * VIR_DOMAIN_TUNABLE_BLKDEV_TOTAL_IOPS_SEC_MAX:
+ *
+ * Macro represents the total maximum I/O operations per second,
+ * as VIR_TYPED_PARAM_ULLONG.
+ */
+# define VIR_DOMAIN_TUNABLE_BLKDEV_TOTAL_IOPS_SEC_MAX "blkdeviotune.total_iops_sec_max"
+
+/**
+ * VIR_DOMAIN_TUNABLE_BLKDEV_READ_IOPS_SEC_MAX:
+ *
+ * Macro represents the read maximum I/O operations per second,
+ * as VIR_TYPED_PARAM_ULLONG.
+ */
+# define VIR_DOMAIN_TUNABLE_BLKDEV_READ_IOPS_SEC_MAX "blkdeviotune.read_iops_sec_max"
+
+/**
+ * VIR_DOMAIN_TUNABLE_BLKDEV_WRITE_IOPS_SEC_MAX:
+ *
+ * Macro represents the write maximum I/O operations per second,
+ * as VIR_TYPED_PARAM_ULLONG.
+ */
+# define VIR_DOMAIN_TUNABLE_BLKDEV_WRITE_IOPS_SEC_MAX "blkdeviotune.write_iops_sec_max"
+
+/**
+ * VIR_DOMAIN_TUNABLE_BLKDEV_SIZE_IOPS_SEC:
+ *
+ * Macro represents the size maximum I/O operations per second,
+ * as VIR_TYPED_PARAM_ULLONG.
+ */
+# define VIR_DOMAIN_TUNABLE_BLKDEV_SIZE_IOPS_SEC "blkdeviotune.size_iops_sec"
+
+/**
* virConnectDomainEventTunableCallback:
* @conn: connection object
* @dom: domain on which the event occurred
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 5eccacc..242b30e 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -105,6 +105,7 @@ VIR_LOG_INIT("qemu.qemu_driver");
#define QEMU_NB_MEM_PARAM 3
#define QEMU_NB_BLOCK_IO_TUNE_PARAM 6
+#define QEMU_NB_BLOCK_IO_TUNE_PARAM_MAX 13
#define QEMU_NB_NUMA_PARAM 2
@@ -16520,6 +16521,10 @@ qemuDomainSetBlockIoTune(virDomainPtr dom,
int conf_idx = -1;
bool set_bytes = false;
bool set_iops = false;
+ bool set_bytes_max = false;
+ bool set_iops_max = false;
+ bool set_size_iops = false;
+ bool supportMaxOptions = true;
virQEMUDriverConfigPtr cfg = NULL;
virCapsPtr caps = NULL;
virObjectEventPtr event = NULL;
@@ -16542,6 +16547,20 @@ qemuDomainSetBlockIoTune(virDomainPtr dom,
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,
NULL) < 0)
return -1;
@@ -16634,6 +16653,69 @@ qemuDomainSetBlockIoTune(virDomainPtr dom,
VIR_DOMAIN_TUNABLE_BLKDEV_WRITE_IOPS_SEC,
param->value.ul) < 0)
goto endjob;
+ } else if (STREQ(param->field,
+ VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC_MAX)) {
+ info.total_bytes_sec_max = param->value.ul;
+ set_bytes_max = true;
+ if (virTypedParamsAddULLong(&eventParams, &eventNparams,
+ &eventMaxparams,
+ VIR_DOMAIN_TUNABLE_BLKDEV_TOTAL_BYTES_SEC_MAX,
+ param->value.ul) < 0)
+ goto endjob;
+ } else if (STREQ(param->field,
+ VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC_MAX)) {
+ info.read_bytes_sec_max = param->value.ul;
+ set_bytes_max = true;
+ if (virTypedParamsAddULLong(&eventParams, &eventNparams,
+ &eventMaxparams,
+ VIR_DOMAIN_TUNABLE_BLKDEV_READ_BYTES_SEC_MAX,
+ param->value.ul) < 0)
+ goto endjob;
+ } else if (STREQ(param->field,
+ VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC_MAX)) {
+ info.write_bytes_sec_max = param->value.ul;
+ set_bytes_max = true;
+ if (virTypedParamsAddULLong(&eventParams, &eventNparams,
+ &eventMaxparams,
+ VIR_DOMAIN_TUNABLE_BLKDEV_WRITE_BYTES_SEC_MAX,
+ param->value.ul) < 0)
+ goto endjob;
+ } else if (STREQ(param->field,
+ VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC_MAX)) {
+ info.total_iops_sec_max = param->value.ul;
+ set_iops_max = true;
+ if (virTypedParamsAddULLong(&eventParams, &eventNparams,
+ &eventMaxparams,
+ VIR_DOMAIN_TUNABLE_BLKDEV_TOTAL_IOPS_SEC_MAX,
+ param->value.ul) < 0)
+ goto endjob;
+ } else if (STREQ(param->field,
+ VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC_MAX)) {
+ info.read_iops_sec_max = param->value.ul;
+ set_iops_max = true;
+ if (virTypedParamsAddULLong(&eventParams, &eventNparams,
+ &eventMaxparams,
+ VIR_DOMAIN_TUNABLE_BLKDEV_READ_IOPS_SEC_MAX,
+ param->value.ul) < 0)
+ goto endjob;
+ } else if (STREQ(param->field,
+ VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC_MAX)) {
+ info.write_iops_sec_max = param->value.ul;
+ set_iops_max = true;
+ if (virTypedParamsAddULLong(&eventParams, &eventNparams,
+ &eventMaxparams,
+ VIR_DOMAIN_TUNABLE_BLKDEV_WRITE_IOPS_SEC_MAX,
+ param->value.ul) < 0)
+ goto endjob;
+ } else if (STREQ(param->field,
+ VIR_DOMAIN_BLOCK_IOTUNE_SIZE_IOPS_SEC)) {
+ info.size_iops_sec = param->value.ul;
+ set_size_iops = true;
+ if (virTypedParamsAddULLong(&eventParams, &eventNparams,
+ &eventMaxparams,
+ VIR_DOMAIN_TUNABLE_BLKDEV_SIZE_IOPS_SEC,
+ param->value.ul) < 0)
+ goto endjob;
}
}
@@ -16651,6 +16733,20 @@ qemuDomainSetBlockIoTune(virDomainPtr dom,
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;
+ }
+
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
if ((conf_idx = virDomainDiskIndexByName(persistentDef, disk, true)) < 0) {
virReportError(VIR_ERR_INVALID_ARG,
@@ -16661,6 +16757,7 @@ qemuDomainSetBlockIoTune(virDomainPtr dom,
}
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
+ supportMaxOptions = virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DRIVE_IOTUNE);
if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DRIVE_IOTUNE)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("block I/O throttling not supported with this "
@@ -16668,6 +16765,13 @@ qemuDomainSetBlockIoTune(virDomainPtr dom,
goto endjob;
}
+ if (!supportMaxOptions && (set_iops_max || set_bytes_max)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("a block I/O throttling parameter is not supported with this "
+ "QEMU binary"));
+ goto endjob;
+ }
+
if (!(device = qemuDiskPathToAlias(vm, disk, &idx)))
goto endjob;
@@ -16680,13 +16784,25 @@ qemuDomainSetBlockIoTune(virDomainPtr dom,
info.read_bytes_sec = oldinfo->read_bytes_sec;
info.write_bytes_sec = oldinfo->write_bytes_sec;
}
+ if (!set_bytes_max) {
+ info.total_bytes_sec_max = oldinfo->total_bytes_sec_max;
+ info.read_bytes_sec_max = oldinfo->read_bytes_sec_max;
+ info.write_bytes_sec_max = oldinfo->write_bytes_sec_max;
+ }
if (!set_iops) {
info.total_iops_sec = oldinfo->total_iops_sec;
info.read_iops_sec = oldinfo->read_iops_sec;
info.write_iops_sec = oldinfo->write_iops_sec;
}
+ if (!set_iops_max) {
+ info.total_iops_sec_max = oldinfo->total_iops_sec_max;
+ info.read_iops_sec_max = oldinfo->read_iops_sec_max;
+ info.write_iops_sec_max = oldinfo->write_iops_sec_max;
+ }
+ if (!set_size_iops)
+ info.size_iops_sec = oldinfo->size_iops_sec;
qemuDomainObjEnterMonitor(driver, vm);
- ret = qemuMonitorSetBlockIoThrottle(priv->mon, device, &info);
+ ret = qemuMonitorSetBlockIoThrottle(priv->mon, device, &info, supportMaxOptions);
qemuDomainObjExitMonitor(driver, vm);
if (ret < 0)
goto endjob;
@@ -16730,6 +16846,7 @@ qemuDomainSetBlockIoTune(virDomainPtr dom,
}
endjob:
+
if (!qemuDomainObjEndJob(driver, vm))
vm = NULL;
@@ -16753,13 +16870,14 @@ qemuDomainGetBlockIoTune(virDomainPtr dom,
{
virQEMUDriverPtr driver = dom->conn->privateData;
virDomainObjPtr vm = NULL;
- qemuDomainObjPrivatePtr priv;
+ qemuDomainObjPrivatePtr priv = NULL;
virDomainDefPtr persistentDef = NULL;
virDomainBlockIoTuneInfo reply;
char *device = NULL;
int ret = -1;
size_t i;
virCapsPtr caps = NULL;
+ bool supportMaxOptions = true;
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
VIR_DOMAIN_AFFECT_CONFIG |
@@ -16777,13 +16895,6 @@ qemuDomainGetBlockIoTune(virDomainPtr dom,
if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
goto cleanup;
- if ((*nparams) == 0) {
- /* Current number of parameters supported by QEMU Block I/O Throttling */
- *nparams = QEMU_NB_BLOCK_IO_TUNE_PARAM;
- ret = 0;
- goto cleanup;
- }
-
if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
goto cleanup;
@@ -16791,6 +16902,18 @@ qemuDomainGetBlockIoTune(virDomainPtr dom,
&persistentDef) < 0)
goto endjob;
+ if ((*nparams) == 0) {
+ if (flags & VIR_DOMAIN_AFFECT_LIVE) {
+ priv = vm->privateData;
+ /* If the VM is running, we can check if the current VM can use optional parameters or not */
+ /* We didn't made this check sooner because we need the VM data to do so */
+ supportMaxOptions = virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DRIVE_IOTUNE_MAX);
+ }
+ *nparams = supportMaxOptions ? QEMU_NB_BLOCK_IO_TUNE_PARAM_MAX : QEMU_NB_BLOCK_IO_TUNE_PARAM;
+ ret = 0;
+ goto endjob;
+ }
+
device = qemuDiskPathToAlias(vm, disk, NULL);
if (!device) {
goto endjob;
@@ -16799,7 +16922,7 @@ qemuDomainGetBlockIoTune(virDomainPtr dom,
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
priv = vm->privateData;
qemuDomainObjEnterMonitor(driver, vm);
- ret = qemuMonitorGetBlockIoThrottle(priv->mon, device, &reply);
+ ret = qemuMonitorGetBlockIoThrottle(priv->mon, device, &reply, supportMaxOptions);
qemuDomainObjExitMonitor(driver, vm);
if (ret < 0)
goto endjob;
@@ -16816,7 +16939,7 @@ qemuDomainGetBlockIoTune(virDomainPtr dom,
reply = persistentDef->disks[idx]->blkdeviotune;
}
- for (i = 0; i < QEMU_NB_BLOCK_IO_TUNE_PARAM && i < *nparams; i++) {
+ for (i = 0; i < QEMU_NB_BLOCK_IO_TUNE_PARAM_MAX && i < *nparams; i++) {
virTypedParameterPtr param = ¶ms[i];
switch (i) {
@@ -16862,14 +16985,64 @@ qemuDomainGetBlockIoTune(virDomainPtr dom,
reply.write_iops_sec) < 0)
goto endjob;
break;
+ case 6:
+ if (virTypedParameterAssign(param,
+ VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC_MAX,
+ VIR_TYPED_PARAM_ULLONG,
+ reply.total_bytes_sec_max) < 0)
+ goto endjob;
+ break;
+ case 7:
+ if (virTypedParameterAssign(param,
+ VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC_MAX,
+ VIR_TYPED_PARAM_ULLONG,
+ reply.read_bytes_sec_max) < 0)
+ goto endjob;
+ break;
+ case 8:
+ if (virTypedParameterAssign(param,
+ VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC_MAX,
+ VIR_TYPED_PARAM_ULLONG,
+ reply.write_bytes_sec_max) < 0)
+ goto endjob;
+ break;
+ case 9:
+ if (virTypedParameterAssign(param,
+ VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC_MAX,
+ VIR_TYPED_PARAM_ULLONG,
+ reply.total_iops_sec_max) < 0)
+ goto endjob;
+ break;
+ case 10:
+ if (virTypedParameterAssign(param,
+ VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC_MAX,
+ VIR_TYPED_PARAM_ULLONG,
+ reply.read_iops_sec_max) < 0)
+ goto endjob;
+ break;
+ case 11:
+ if (virTypedParameterAssign(param,
+ VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC_MAX,
+ VIR_TYPED_PARAM_ULLONG,
+ reply.write_iops_sec_max) < 0)
+ goto endjob;
+ break;
+ case 12:
+ if (virTypedParameterAssign(param,
+ VIR_DOMAIN_BLOCK_IOTUNE_SIZE_IOPS_SEC,
+ VIR_TYPED_PARAM_ULLONG,
+ reply.size_iops_sec) < 0)
+ goto endjob;
/* coverity[dead_error_begin] */
default:
break;
}
}
- if (*nparams > QEMU_NB_BLOCK_IO_TUNE_PARAM)
+ if (!supportMaxOptions && *nparams > QEMU_NB_BLOCK_IO_TUNE_PARAM)
*nparams = QEMU_NB_BLOCK_IO_TUNE_PARAM;
+ else if (*nparams > QEMU_NB_BLOCK_IO_TUNE_PARAM_MAX)
+ *nparams = QEMU_NB_BLOCK_IO_TUNE_PARAM_MAX;
ret = 0;
endjob:
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 36ef4e1..276649d 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -3514,14 +3514,15 @@ qemuMonitorBlockJobInfo(qemuMonitorPtr mon,
int qemuMonitorSetBlockIoThrottle(qemuMonitorPtr mon,
const char *device,
- virDomainBlockIoTuneInfoPtr info)
+ virDomainBlockIoTuneInfoPtr info,
+ bool supportMaxOptions)
{
int ret;
VIR_DEBUG("mon=%p, device=%p, info=%p", mon, device, info);
if (mon->json) {
- ret = qemuMonitorJSONSetBlockIoThrottle(mon, device, info);
+ ret = qemuMonitorJSONSetBlockIoThrottle(mon, device, info, supportMaxOptions);
} else {
ret = qemuMonitorTextSetBlockIoThrottle(mon, device, info);
}
@@ -3530,14 +3531,15 @@ int qemuMonitorSetBlockIoThrottle(qemuMonitorPtr mon,
int qemuMonitorGetBlockIoThrottle(qemuMonitorPtr mon,
const char *device,
- virDomainBlockIoTuneInfoPtr reply)
+ virDomainBlockIoTuneInfoPtr reply,
+ bool supportMaxOptions)
{
int ret;
VIR_DEBUG("mon=%p, device=%p, reply=%p", mon, device, reply);
if (mon->json) {
- ret = qemuMonitorJSONGetBlockIoThrottle(mon, device, reply);
+ ret = qemuMonitorJSONGetBlockIoThrottle(mon, device, reply, supportMaxOptions);
} else {
ret = qemuMonitorTextGetBlockIoThrottle(mon, device, reply);
}
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 750b3dc..76c91a3 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -771,11 +771,13 @@ int qemuMonitorOpenGraphics(qemuMonitorPtr mon,
int qemuMonitorSetBlockIoThrottle(qemuMonitorPtr mon,
const char *device,
- virDomainBlockIoTuneInfoPtr info);
+ virDomainBlockIoTuneInfoPtr info,
+ bool supportMaxOptions);
int qemuMonitorGetBlockIoThrottle(qemuMonitorPtr mon,
const char *device,
- virDomainBlockIoTuneInfoPtr reply);
+ virDomainBlockIoTuneInfoPtr reply,
+ bool supportMaxOptions);
int qemuMonitorSystemWakeup(qemuMonitorPtr mon);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 7870664..c506c31 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -4293,7 +4293,8 @@ int qemuMonitorJSONOpenGraphics(qemuMonitorPtr mon,
static int
qemuMonitorJSONBlockIoThrottleInfo(virJSONValuePtr result,
const char *device,
- virDomainBlockIoTuneInfoPtr reply)
+ virDomainBlockIoTuneInfoPtr reply,
+ bool supportMaxOptions ATTRIBUTE_UNUSED)
{
virJSONValuePtr io_throttle;
int ret = -1;
@@ -4364,7 +4365,8 @@ qemuMonitorJSONBlockIoThrottleInfo(virJSONValuePtr result,
int qemuMonitorJSONSetBlockIoThrottle(qemuMonitorPtr mon,
const char *device,
- virDomainBlockIoTuneInfoPtr info)
+ virDomainBlockIoTuneInfoPtr info,
+ bool supportMaxOptions ATTRIBUTE_UNUSED)
{
int ret = -1;
virJSONValuePtr cmd = NULL;
@@ -4404,7 +4406,8 @@ int qemuMonitorJSONSetBlockIoThrottle(qemuMonitorPtr mon,
int qemuMonitorJSONGetBlockIoThrottle(qemuMonitorPtr mon,
const char *device,
- virDomainBlockIoTuneInfoPtr reply)
+ virDomainBlockIoTuneInfoPtr reply,
+ bool supportMaxOptions)
{
int ret = -1;
virJSONValuePtr cmd = NULL;
@@ -4431,7 +4434,7 @@ int qemuMonitorJSONGetBlockIoThrottle(qemuMonitorPtr mon,
}
if (ret == 0)
- ret = qemuMonitorJSONBlockIoThrottleInfo(result, device, reply);
+ ret = qemuMonitorJSONBlockIoThrottleInfo(result, device, reply, supportMaxOptions);
virJSONValueFree(cmd);
virJSONValueFree(result);
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 6cdaf18..3b6159a 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -325,11 +325,13 @@ int qemuMonitorJSONOpenGraphics(qemuMonitorPtr mon,
int qemuMonitorJSONSetBlockIoThrottle(qemuMonitorPtr mon,
const char *device,
- virDomainBlockIoTuneInfoPtr info);
+ virDomainBlockIoTuneInfoPtr info,
+ bool supportMaxOptions);
int qemuMonitorJSONGetBlockIoThrottle(qemuMonitorPtr mon,
const char *device,
- virDomainBlockIoTuneInfoPtr reply);
+ virDomainBlockIoTuneInfoPtr reply,
+ bool supportMaxOptions);
int qemuMonitorJSONSystemWakeup(qemuMonitorPtr mon);
diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c
index ad33c10..1b202fb 100644
--- a/tests/qemumonitorjsontest.c
+++ b/tests/qemumonitorjsontest.c
@@ -1847,7 +1847,7 @@ testQemuMonitorJSONqemuMonitorJSONSetBlockIoThrottle(const void *data)
goto cleanup;
if (qemuMonitorJSONGetBlockIoThrottle(qemuMonitorTestGetMonitor(test),
- "drive-virtio-disk0", &info) < 0)
+ "drive-virtio-disk0", &info, false) < 0)
goto cleanup;
if (memcmp(&info, &expectedInfo, sizeof(info) != 0)) {
@@ -1857,7 +1857,7 @@ testQemuMonitorJSONqemuMonitorJSONSetBlockIoThrottle(const void *data)
}
if (qemuMonitorJSONSetBlockIoThrottle(qemuMonitorTestGetMonitor(test),
- "drive-virtio-disk1", &info) < 0)
+ "drive-virtio-disk1", &info, false) < 0)
goto cleanup;
ret = 0;
--
1.8.3.1
10 years, 1 month
[libvirt] [PATCH V2 0/3] Fix some problems of numatune
by Wang Rui
Fix startup failing with memory mode(strict, preferred or interleave)
in numatune
V1:
https://www.redhat.com/archives/libvir-list/2014-November/msg00057.html
V2 has been revised as Martin' suggestion.
Wang Rui (3):
qemu: don't setup cpuset.mems if memory mode in numatune is not
'strict'
lxc: don't setup cpuset.mems if memory mode in numatune is not
'strict'
qemu: fix domain startup failing with 'strict' mode in numatune
src/lxc/lxc_cgroup.c | 4 ++++
src/qemu/qemu_cgroup.c | 14 +++++++++++---
2 files changed, 15 insertions(+), 3 deletions(-)
--
1.7.12.4
10 years, 1 month
[libvirt] [libvirt-python][PATCH] Add dict check for setTime and allow pass 'seconds' parameter
by Michal Privoznik
From: Luyao Huang <lhuang(a)redhat.com>
When pass None or a empty dictionary to time, it will report
error. This commit allows a one-element dictionary which contains
just 'seconds' field, which results in the same as passing 0 for
'nseconds' field. Moreover, dict is checked for unknown fields.
Signed-off-by: Luyao Huang <lhuang(a)redhat.com>
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
libvirt-override-virDomain.py | 4 ++--
libvirt-override.c | 39 +++++++++++++++++++++++----------------
2 files changed, 25 insertions(+), 18 deletions(-)
diff --git a/libvirt-override-virDomain.py b/libvirt-override-virDomain.py
index a50ec0d..fa5f75f 100644
--- a/libvirt-override-virDomain.py
+++ b/libvirt-override-virDomain.py
@@ -67,8 +67,8 @@
return ret
def setTime(self, time=None, flags=0):
- """Set guest time to the given value. @time is a dict conatining
- 'seconds' field for seconds and 'nseconds' field for nanosecons """
+ """Set guest time to the given value. @time is a dict containing
+ 'seconds' field for seconds and 'nseconds' field for nanoseconds """
ret = libvirtmod.virDomainSetTime(self._o, time, flags)
if ret == -1: raise libvirtError ('virDomainSetTime() failed', dom=self)
return ret
diff --git a/libvirt-override.c b/libvirt-override.c
index c01e52f..57f0ccf 100644
--- a/libvirt-override.c
+++ b/libvirt-override.c
@@ -7785,12 +7785,14 @@ static PyObject *
libvirt_virDomainSetTime(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
PyObject *py_retval = NULL;
PyObject *pyobj_domain;
+ PyObject *pyobj_seconds;
+ PyObject *pyobj_nseconds;
PyObject *py_dict;
virDomainPtr domain;
long long seconds = 0;
unsigned int nseconds = 0;
unsigned int flags;
- ssize_t py_dict_size;
+ ssize_t py_dict_size = 0;
int c_retval;
if (!PyArg_ParseTuple(args, (char*)"OOI:virDomainSetTime",
@@ -7798,26 +7800,31 @@ libvirt_virDomainSetTime(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
return NULL;
domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
- py_dict_size = PyDict_Size(py_dict);
-
- if (py_dict_size == 2) {
- PyObject *pyobj_seconds, *pyobj_nseconds;
-
- if (!(pyobj_seconds = PyDict_GetItemString(py_dict, "seconds")) ||
- (libvirt_longlongUnwrap(pyobj_seconds, &seconds) < 0)) {
- PyErr_Format(PyExc_LookupError, "malformed or missing 'seconds'");
+ if (PyDict_Check(py_dict)) {
+ py_dict_size = PyDict_Size(py_dict);
+ if ((pyobj_seconds = PyDict_GetItemString(py_dict, "seconds"))) {
+ if (libvirt_longlongUnwrap(pyobj_seconds, &seconds) < 0) {
+ PyErr_Format(PyExc_LookupError, "malformed 'seconds'");
+ goto cleanup;
+ }
+ } else {
+ PyErr_Format(PyExc_LookupError, "Dictionary must contains 'seconds'");
goto cleanup;
}
- if (!(pyobj_nseconds = PyDict_GetItemString(py_dict, "nseconds")) ||
- (libvirt_uintUnwrap(pyobj_nseconds, &nseconds) < 0)) {
- PyErr_Format(PyExc_LookupError, "malformed or missing 'nseconds'");
+ if ((pyobj_nseconds = PyDict_GetItemString(py_dict, "nseconds"))) {
+ if (libvirt_uintUnwrap(pyobj_nseconds, &nseconds) < 0) {
+ PyErr_Format(PyExc_LookupError, "malformed 'nseconds'");
+ goto cleanup;
+ }
+ } else if (py_dict_size > 1) {
+ PyErr_Format(PyExc_LookupError, "Dictionary contains unknown key");
goto cleanup;
}
- } else if (py_dict_size > 0) {
- PyErr_Format(PyExc_LookupError, "Dictionary must contain "
- "'seconds' and 'nseconds'");
- goto cleanup;
+ } else if (py_dict != Py_None || !flags) {
+ PyErr_Format(PyExc_TypeError, "time must be a dictionary "
+ "or None with flags set");
+ return NULL;
}
LIBVIRT_BEGIN_ALLOW_THREADS;
--
2.0.4
10 years, 1 month
[libvirt] [PATCH] selinux: ignore missing imagelabel in SetSavedStateLabel
by Ján Tomko
If we have no imagelabel to set (e.g. the domain was created
by qemu-attach where we don't generate an imagelabel) return
success instead of crashing.
https://bugzilla.redhat.com/show_bug.cgi?id=1161831
---
src/security/security_selinux.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index f96be50..db0df7d 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -1970,7 +1970,7 @@ virSecuritySELinuxSetSavedStateLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
virSecurityLabelDefPtr secdef;
secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
- if (!secdef || !secdef->relabel)
+ if (!secdef || !secdef->relabel || !secdef->imagelabel)
return 0;
return virSecuritySELinuxSetFilecon(savefile, secdef->imagelabel);
--
2.0.4
10 years, 1 month
[libvirt] [PATCH] Fix invalid log, misused option types and a typo
by Hao Liu
This patch fixes the following issues.
1) When an invalid wwn is introduced, libvirt reports
"Malformed wwn: %s". The template won't be replaced.
2) "target" option for dompmsuspend and "xml" option for
save-image-define are required options and should use
VSH_OT_DATA instead of VSH_OT_STRING as an option type.
3) A typo.
Signed-off-by: Hao Liu <hliu(a)redhat.com>
---
src/util/virutil.c | 4 ++--
tools/virsh-domain.c | 4 ++--
tools/virsh-host.c | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/util/virutil.c b/src/util/virutil.c
index 1116fda..c178515 100644
--- a/src/util/virutil.c
+++ b/src/util/virutil.c
@@ -1549,8 +1549,8 @@ virValidateWWN(const char *wwn)
}
if (i != 16 || p[i]) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("Malformed wwn: %s"));
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Malformed wwn: %s"), wwn);
return false;
}
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 13a904f..8e743f1 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -3228,7 +3228,7 @@ static const vshCmdOptDef opts_dom_pm_suspend[] = {
.help = N_("duration in seconds")
},
{.name = "target",
- .type = VSH_OT_STRING,
+ .type = VSH_OT_DATA,
.flags = VSH_OFLAG_REQ,
.help = N_("mem(Suspend-to-RAM), "
"disk(Suspend-to-Disk), "
@@ -4268,7 +4268,7 @@ static const vshCmdOptDef opts_save_image_define[] = {
.help = N_("saved state file to modify")
},
{.name = "xml",
- .type = VSH_OT_STRING,
+ .type = VSH_OT_DATA,
.flags = VSH_OFLAG_REQ,
.help = N_("filename containing updated XML for the target")
},
diff --git a/tools/virsh-host.c b/tools/virsh-host.c
index 4a3ff28..28b160d 100644
--- a/tools/virsh-host.c
+++ b/tools/virsh-host.c
@@ -497,7 +497,7 @@ cmdAllocpages(vshControl *ctl, const vshCmd *cmd)
pageSizes[0] = VIR_DIV_UP(tmp, 1024);
if (vshCommandOptULongLong(cmd, "pagecount", &pageCounts[0]) < 0) {
- vshError(ctl, "%s", _("pagecount hat to be a number"));
+ vshError(ctl, "%s", _("pagecount has to be a number"));
return false;
}
--
1.8.3.1
10 years, 1 month
[libvirt] [python v3 PATCH] Add dict check for setTime and allow pass 'seconds' parameter
by Luyao Huang
When pass None or a empty dictionary to time, it will
report error.Allow a one-element dictionary which
contains 'seconds',setting JUST seconds will do the
sane thing of passing 0 for nseconds, instead of
erroring out.If dict have a unkown key, it will report error.
Signed-off-by: Luyao Huang <lhuang(a)redhat.com>
---
libvirt-override-virDomain.py | 6 +++---
libvirt-override.c | 41 +++++++++++++++++++++++++++++------------
2 files changed, 32 insertions(+), 15 deletions(-)
diff --git a/libvirt-override-virDomain.py b/libvirt-override-virDomain.py
index a50ec0d..2a4c4c9 100644
--- a/libvirt-override-virDomain.py
+++ b/libvirt-override-virDomain.py
@@ -66,9 +66,9 @@
if ret == -1: raise libvirtError ('virDomainGetTime() failed', dom=self)
return ret
- def setTime(self, time=None, flags=0):
- """Set guest time to the given value. @time is a dict conatining
- 'seconds' field for seconds and 'nseconds' field for nanosecons """
+ def setTime(self, time, flags=0):
+ """Set guest time to the given value. @time is a dict containing
+ 'seconds' field for seconds and 'nseconds' field for nanoseconds """
ret = libvirtmod.virDomainSetTime(self._o, time, flags)
if ret == -1: raise libvirtError ('virDomainSetTime() failed', dom=self)
return ret
diff --git a/libvirt-override.c b/libvirt-override.c
index a53b46f..1d1714a 100644
--- a/libvirt-override.c
+++ b/libvirt-override.c
@@ -7784,6 +7784,8 @@ static PyObject *
libvirt_virDomainSetTime(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
PyObject *py_retval = NULL;
PyObject *pyobj_domain;
+ PyObject *pyobj_seconds;
+ PyObject *pyobj_nseconds;
PyObject *py_dict;
virDomainPtr domain;
long long seconds = 0;
@@ -7797,25 +7799,40 @@ libvirt_virDomainSetTime(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
return NULL;
domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
- py_dict_size = PyDict_Size(py_dict);
+ if (!PyDict_Check(py_dict)) {
+ PyErr_Format(PyExc_TypeError, "time must be dict");
+ return NULL;
+ }
- if (py_dict_size == 2) {
- PyObject *pyobj_seconds, *pyobj_nseconds;
+ py_dict_size = PyDict_Size(py_dict);
- if (!(pyobj_seconds = PyDict_GetItemString(py_dict, "seconds")) ||
- (libvirt_longlongUnwrap(pyobj_seconds, &seconds) < 0)) {
- PyErr_Format(PyExc_LookupError, "malformed or missing 'seconds'");
+ if ((pyobj_seconds = PyDict_GetItemString(py_dict, "seconds")) != NULL) {
+ if (libvirt_longlongUnwrap(pyobj_seconds, &seconds) < 0) {
+ PyErr_Format(PyExc_LookupError, "malformed 'seconds'");
goto cleanup;
}
+ } else {
+ PyErr_Format(PyExc_LookupError, "Dictionary must contains "
+ "'seconds'");
+ goto cleanup;
+ }
- if (!(pyobj_nseconds = PyDict_GetItemString(py_dict, "nseconds")) ||
- (libvirt_uintUnwrap(pyobj_nseconds, &nseconds) < 0)) {
- PyErr_Format(PyExc_LookupError, "malformed or missing 'nseconds'");
+ if ((pyobj_nseconds = PyDict_GetItemString(py_dict, "nseconds")) != NULL) {
+ if (libvirt_uintUnwrap(pyobj_nseconds, &nseconds) < 0) {
+ PyErr_Format(PyExc_LookupError, "malformed 'nseconds'");
goto cleanup;
}
- } else if (py_dict_size > 0) {
- PyErr_Format(PyExc_LookupError, "Dictionary must contain "
- "'seconds' and 'nseconds'");
+ } else if (py_dict_size == 1) {
+ nseconds = 0;
+ } else {
+ PyErr_Format(PyExc_LookupError, "Dictionary contains "
+ "unknown key");
+ goto cleanup;
+ }
+
+ if (py_dict_size > 2) {
+ PyErr_Format(PyExc_LookupError, "Dictionary contains "
+ "unknown key");
goto cleanup;
}
--
1.8.3.1
10 years, 1 month
[libvirt] LSN-2014-0007: CVE-2014-7823 virDomainGetXMLDesc leaks VNC passwords
by Eric Blake
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
Libvirt Security Notice: LSN-2014-0007
======================================
Summary: virDomainGetXMLDesc leaks VNC passwords
Reported on: 20141031
Published on: 20141105
Fixed on: 20141106
Reported by: Eric Blake <eblake(a)redhat.com>
Patched by: Eric Blake <eblake(a)redhat.com>
See also: CVE-2014-7823
Description
- -----------
At the time the VIR_DOMAIN_XML_MIGRATABLE flag was added to the
virDomainGetXMLDesc API, the qemu implementation chose to make the
flag always imply the VIR_DOMAIN_XML_SECURE flag. The secure flag
had been previously deemed unsafe to use from a read-only
connection; however, because the new migratable flag is not
restricted against use by read-only clients, a client can use the
new flag to bypass the restrictions placed on the use of the old
flag.
Impact
- ------
A read-only client can trigger an information leak of data that
should normally require the use of VIR_DOMAIN_XML_SECURE to access.
Fortunately, the only data in this category is the value of an
optional VNC password.
Workaround
- ----------
VNC passwords are notoriously weak (they are capped at an 8 byte
maximum length; the VNC protocol sends them in plaintext over the
network; and FIPS mode execution prohibits the use of a VNC
password), so it is recommended that users not create domains with a
VNC password in the first place. Domains that do not use VNC
passwords do not suffer from information leaks; the use of SPICE
connections is recommended not only because it avoids the leak, but
also because SPICE provides better features than VNC for a guest
graphics device. It is also possible to prevent the leak by denying
access to read-only clients; for builds of libvirt that support
fine-grained ACLs, this course of action requires ensuring that no
user is granted the 'read' ACL privilege without also having the
'read_secure' privilege.
Affected product
- ----------------
Name: libvirt
Repository: git://libvirt.org/git/libvirt.git
http://libvirt.org/git/?p=libvirt.git
Branch: master
Broken in: v1.0.0
Broken in: v1.0.1
Broken in: v1.0.2
Broken in: v1.0.3
Broken in: v1.0.4
Broken in: v1.0.5
Broken in: v1.0.6
Broken in: v1.1.0
Broken in: v1.1.1
Broken in: v1.1.2
Broken in: v1.1.3
Broken in: v1.1.4
Broken in: v1.2.0
Broken in: v1.2.1
Broken in: v1.2.2
Broken in: v1.2.3
Broken in: v1.2.4
Broken in: v1.2.5
Broken in: v1.2.6
Broken in: v1.2.7
Broken in: v1.2.8
Broken in: v1.2.9
Broken in: v1.2.10
Fixed in: v1.2.11
Broken by: 28f8dfdcccd4c0f69063ef741545b37d8a7f7935
Fixed by: b1674ad5a97441b7e1bd5f5ebaff498ef2fbb11b
Branch: v1.0.2-maint
Broken by: 28f8dfdcccd4c0f69063ef741545b37d8a7f7935
Fixed by: 7b334c1660e926da7c0644c945263ce40a80443f
Branch: v1.0.3-maint
Broken by: 28f8dfdcccd4c0f69063ef741545b37d8a7f7935
Fixed by: 220c6b867ca81f9027a7da54d5bc44b43c742d2a
Branch: v1.0.4-maint
Broken by: 28f8dfdcccd4c0f69063ef741545b37d8a7f7935
Fixed by: 3b7ce055e37e92c34090fcfcc0b6eaa860aa94a9
Branch: v1.0.5-maint
Broken in: v1.0.5.1
Broken in: v1.0.5.2
Broken in: v1.0.5.3
Broken in: v1.0.5.4
Broken in: v1.0.5.5
Broken in: v1.0.5.6
Broken in: v1.0.5.7
Broken in: v1.0.5.8
Broken in: v1.0.5.9
Broken by: 28f8dfdcccd4c0f69063ef741545b37d8a7f7935
Fixed by: 107f1ff20edc805433cade910a00328158b1c231
Branch: v1.0.6-maint
Broken by: 28f8dfdcccd4c0f69063ef741545b37d8a7f7935
Fixed by: 333c95c9f3fb1e3c42b37f79b7f186511e8f8264
Branch: v1.1.0-maint
Broken by: 28f8dfdcccd4c0f69063ef741545b37d8a7f7935
Fixed by: 3d751cdcdbfac95b4a39a7db1b6e12e20838cb65
Branch: v1.1.1-maint
Broken by: 28f8dfdcccd4c0f69063ef741545b37d8a7f7935
Fixed by: f8c771335998f4d7a91b03c11526d819ee470dfc
Branch: v1.1.2-maint
Broken by: 28f8dfdcccd4c0f69063ef741545b37d8a7f7935
Fixed by: 520ecab4ca09859d4de39cad7ae2e34272e0437e
Branch: v1.1.3-maint
Broken in: v1.1.3.1
Broken in: v1.1.3.2
Broken in: v1.1.3.3
Broken in: v1.1.3.4
Broken in: v1.1.3.5
Broken in: v1.1.3.6
Broken by: 28f8dfdcccd4c0f69063ef741545b37d8a7f7935
Fixed by: bdbcf66ae72f82d45faa889a1208444f83f5756b
Branch: v1.1.4-maint
Broken by: 28f8dfdcccd4c0f69063ef741545b37d8a7f7935
Fixed by: 4e3856c06a3362a17a5aff0b59c4bfffbd97d105
Branch: v1.2.0-maint
Broken by: 28f8dfdcccd4c0f69063ef741545b37d8a7f7935
Fixed by: 757292bfb33b610daff0936d2205a90d5d787a1a
Branch: v1.2.1-maint
Broken by: 28f8dfdcccd4c0f69063ef741545b37d8a7f7935
Fixed by: 3adae530f549448cecfb6212a2e48bf4b04931bd
Branch: v1.2.2-maint
Broken by: 28f8dfdcccd4c0f69063ef741545b37d8a7f7935
Fixed by: bd78e6f6362d2484b931f112506dfde9d053fcde
Branch: v1.2.3-maint
Broken by: 28f8dfdcccd4c0f69063ef741545b37d8a7f7935
Fixed by: 2a924d876c146913b5309c5919900f29b2850012
Branch: v1.2.4-maint
Broken by: 28f8dfdcccd4c0f69063ef741545b37d8a7f7935
Fixed by: 8c083ff081dfd6b3e6ed2053e98c8bdd780db834
Branch: v1.2.5-maint
Broken by: 28f8dfdcccd4c0f69063ef741545b37d8a7f7935
Fixed by: 2cfd147c49d696a3641145ac8edb9e49a85a515d
Branch: v1.2.6-maint
Broken by: 28f8dfdcccd4c0f69063ef741545b37d8a7f7935
Fixed by: 59fff7ff9866227f4be3224bac581e95f3c53bb1
Branch: v1.2.7-maint
Broken by: 28f8dfdcccd4c0f69063ef741545b37d8a7f7935
Fixed by: 0ea4cd2f4a5b87647a6ebf13038049badd3222c8
Branch: v1.2.8-maint
Broken by: 28f8dfdcccd4c0f69063ef741545b37d8a7f7935
Fixed by: c7500ce36fc4654c41e92a8194771122110a3e66
Branch: v1.2.9-maint
Broken by: 28f8dfdcccd4c0f69063ef741545b37d8a7f7935
Fixed by: 744ddb15e0feaf2d6603a88dc8ffc3a7eb0a452d
Branch: v1.2.10-maint
Broken by: 28f8dfdcccd4c0f69063ef741545b37d8a7f7935
Fixed by: 11219f40f3d6132de7cf72287f136bae3747ad53
- --
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
Comment: Public key at http://people.redhat.com/eblake/eblake.gpg
iQEcBAEBCAAGBQJUYQl6AAoJEKeha0olJ0NqioEH/jsMB2X5/nscAYiLytJ6jrJc
lgpmkuli0elYFlpdcj2aar0WsK2RQv9chuasc5Y4hWDslYhzPGkVBkTHceAbds3l
OAhotaob3NBhFGM9p5xoTCDKWTCGVkiSOOUFTyK5amDpUiA0AkHA7B8y1pA0kAY7
+rmXLUQtDcUCEpi7hZgD/9P3cD9CnVpNCBP6m0vUJoWPmyC+KzgETdfuqlRpmD1h
l0a/fGpaPXZkIaaomyGniimffFyxHZVlHnJHC9BBnVnCtBC/G1n2yUJmqBYTDIPd
C6UKZ78/kkOtRfdjVxGlR8USXEIINW+nvYPjVGcUL+zf0H0FE2wEZ5UGie6pfMs=
=6rpO
-----END PGP SIGNATURE-----
10 years, 1 month