[libvirt] [PATCH v3] parallels: add block device statistics to driver
by Nikolay Shirokovskiy
Statistics provided through PCS SDK. As we have only async interface in SDK we
need to be subscribed to statistics in order to get it. Trivial solution on
every stat request to subscribe, wait event and then unsubscribe will lead to
significant delays in case of a number of successive requests, as the event
will be delivered on next PCS server notify cycle. On the other hand we don't
want to keep unnesessary subscribtion. So we take an hibrid solution to
subcsribe on first request and then keep a subscription while requests are
active. We populate cache of statistics on subscribtion events and use this
cache to serve libvirts requests.
* Cache details.
Cache is just handle to last arrived event, we call this cache
as if this handle is valid it is used to serve synchronous
statistics requests. We use number of successive events count
to detect that user lost interest to statistics. We reset this
count to 0 on every request. If more than PARALLELS_STATISTICS_DROP_COUNT
successive events arrive we unsubscribe. Special value of -1
of this counter is used to differentiate between subscribed/unsubscribed state
to protect from delayed events.
Values of PARALLELS_STATISTICS_DROP_COUNT and PARALLELS_STATISTICS_TIMEOUT are
just drop-ins, choosen without special consideration.
* Thread safety issues
Use parallelsDomObjFromDomainRef in parallelsDomainBlockStats as
we could wait on domain lock down on stack in prlsdkGetStatsParam
and if we won't keep reference we could get dangling pointer
on return from wait.
Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy(a)parallels.com>
---
src/parallels/parallels_driver.c | 106 +++++++++++++++++++++
src/parallels/parallels_sdk.c | 189 ++++++++++++++++++++++++++++++++++++++
src/parallels/parallels_sdk.h | 2 +
src/parallels/parallels_utils.c | 28 ++++++
src/parallels/parallels_utils.h | 18 ++++
5 files changed, 343 insertions(+), 0 deletions(-)
diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c
index 4b87213..33c112e 100644
--- a/src/parallels/parallels_driver.c
+++ b/src/parallels/parallels_driver.c
@@ -51,6 +51,7 @@
#include "nodeinfo.h"
#include "virstring.h"
#include "cpu/cpu.h"
+#include "virtypedparam.h"
#include "parallels_driver.h"
#include "parallels_utils.h"
@@ -1179,6 +1180,109 @@ parallelsDomainGetMaxMemory(virDomainPtr domain)
return ret;
}
+static int
+parallelsDomainBlockStats(virDomainPtr domain, const char *path,
+ virDomainBlockStatsPtr stats)
+{
+ virDomainObjPtr dom = NULL;
+ int ret = -1;
+ size_t i;
+ int idx;
+
+ if (!(dom = parallelsDomObjFromDomainRef(domain)))
+ return -1;
+
+ if (*path) {
+ if ((idx = virDomainDiskIndexByName(dom->def, path, false)) < 0) {
+ virReportError(VIR_ERR_INVALID_ARG, _("invalid path: %s"), path);
+ goto cleanup;
+ }
+ if (prlsdkGetBlockStats(dom, dom->def->disks[idx], stats) < 0)
+ goto cleanup;
+ } else {
+ virDomainBlockStatsStruct s;
+
+#define PARALLELS_ZERO_STATS(VAR, TYPE, NAME) \
+ stats->VAR = 0;
+
+ PARALLELS_BLOCK_STATS_FOREACH(PARALLELS_ZERO_STATS)
+
+#undef PARALLELS_ZERO_STATS
+
+ for (i = 0; i < dom->def->ndisks; i++) {
+ if (prlsdkGetBlockStats(dom, dom->def->disks[i], &s) < 0)
+ goto cleanup;
+
+#define PARALLELS_SUM_STATS(VAR, TYPE, NAME) \
+ if (s.VAR != -1) \
+ stats->VAR += s.VAR;
+
+ PARALLELS_BLOCK_STATS_FOREACH(PARALLELS_SUM_STATS)
+
+#undef PARALLELS_SUM_STATS
+ }
+ }
+ stats->errs = -1;
+ ret = 0;
+
+ cleanup:
+ if (dom)
+ virDomainObjEndAPI(&dom);
+
+ return ret;
+}
+
+static int
+parallelsDomainBlockStatsFlags(virDomainPtr domain,
+ const char *path,
+ virTypedParameterPtr params,
+ int *nparams,
+ unsigned int flags)
+{
+ virDomainBlockStatsStruct stats;
+ int ret = -1;
+ size_t i;
+
+ virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);
+ /* We don't return strings, and thus trivially support this flag. */
+ flags &= ~VIR_TYPED_PARAM_STRING_OKAY;
+
+ if (parallelsDomainBlockStats(domain, path, &stats) < 0)
+ goto cleanup;
+
+ if (*nparams == 0) {
+#define PARALLELS_COUNT_STATS(VAR, TYPE, NAME) \
+ if ((stats.VAR) != -1) \
+ ++*nparams;
+
+ PARALLELS_BLOCK_STATS_FOREACH(PARALLELS_COUNT_STATS)
+
+#undef PARALLELS_COUNT_STATS
+ ret = 0;
+ goto cleanup;
+ }
+
+ i = 0;
+#define PARALLELS_BLOCK_STATS_ASSIGN_PARAM(VAR, TYPE, NAME) \
+ if (i < *nparams && (stats.VAR) != -1) { \
+ if (virTypedParameterAssign(params + i, TYPE, \
+ VIR_TYPED_PARAM_LLONG, (stats.VAR)) < 0) \
+ goto cleanup; \
+ i++; \
+ }
+
+ PARALLELS_BLOCK_STATS_FOREACH(PARALLELS_BLOCK_STATS_ASSIGN_PARAM)
+
+#undef PARALLELS_BLOCK_STATS_ASSIGN_PARAM
+
+ *nparams = i;
+ ret = 0;
+
+ cleanup:
+ return ret;
+}
+
+
static virHypervisorDriver parallelsDriver = {
.name = "Parallels",
.connectOpen = parallelsConnectOpen, /* 0.10.0 */
@@ -1228,6 +1332,8 @@ static virHypervisorDriver parallelsDriver = {
.domainManagedSave = parallelsDomainManagedSave, /* 1.2.14 */
.domainManagedSaveRemove = parallelsDomainManagedSaveRemove, /* 1.2.14 */
.domainGetMaxMemory = parallelsDomainGetMaxMemory, /* 1.2.15 */
+ .domainBlockStats = parallelsDomainBlockStats, /* 1.2.17 */
+ .domainBlockStatsFlags = parallelsDomainBlockStatsFlags, /* 1.2.17 */
};
static virConnectDriver parallelsConnectDriver = {
diff --git a/src/parallels/parallels_sdk.c b/src/parallels/parallels_sdk.c
index d5a9790..8c52fce 100644
--- a/src/parallels/parallels_sdk.c
+++ b/src/parallels/parallels_sdk.c
@@ -21,6 +21,7 @@
*/
#include <config.h>
+#include <stdarg.h>
#include "virerror.h"
#include "viralloc.h"
@@ -29,6 +30,7 @@
#include "virlog.h"
#include "datatypes.h"
#include "domain_conf.h"
+#include "virtime.h"
#include "parallels_sdk.h"
@@ -407,6 +409,8 @@ prlsdkDomObjFreePrivate(void *p)
return;
PrlHandle_Free(pdom->sdkdom);
+ PrlHandle_Free(pdom->cache.stats);
+ virCondDestroy(&pdom->cache.cond);
VIR_FREE(pdom->uuid);
VIR_FREE(pdom->home);
VIR_FREE(p);
@@ -1260,6 +1264,13 @@ prlsdkLoadDomain(parallelsConnPtr privconn,
* to NULL temporarily */
pdom->uuid = NULL;
+ pdom->cache.stats = PRL_INVALID_HANDLE;
+ pdom->cache.count = -1;
+ if (virCondInit(&pdom->cache.cond) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot initialize condition"));
+ goto error;
+ }
+
if (prlsdkGetDomainIds(sdkdom, &def->name, def->uuid) < 0)
goto error;
@@ -1635,6 +1646,51 @@ prlsdkHandleVmRemovedEvent(parallelsConnPtr privconn,
return pret;
}
+#define PARALLELS_STATISTICS_DROP_COUNT 3
+
+static PRL_RESULT
+prlsdkHandlePerfEvent(parallelsConnPtr privconn,
+ PRL_HANDLE event,
+ unsigned char *uuid)
+{
+ virDomainObjPtr dom = NULL;
+ parallelsDomObjPtr privdom = NULL;
+ PRL_HANDLE job = PRL_INVALID_HANDLE;
+
+ dom = virDomainObjListFindByUUID(privconn->domains, uuid);
+ if (dom == NULL)
+ goto cleanup;
+ privdom = dom->privateData;
+
+ // delayed event after unsubscribe
+ if (privdom->cache.count == -1)
+ goto cleanup;
+
+ PrlHandle_Free(privdom->cache.stats);
+ privdom->cache.stats = PRL_INVALID_HANDLE;
+
+ if (privdom->cache.count > PARALLELS_STATISTICS_DROP_COUNT) {
+ job = PrlVm_UnsubscribeFromPerfStats(privdom->sdkdom);
+ if (PRL_FAILED(waitJob(job)))
+ goto cleanup;
+ // change state to unsubscribed
+ privdom->cache.count = -1;
+ } else {
+ ++privdom->cache.count;
+ privdom->cache.stats = event;
+ // thus we get own of event handle
+ event = PRL_INVALID_HANDLE;
+ virCondSignal(&privdom->cache.cond);
+ }
+
+ cleanup:
+ PrlHandle_Free(event);
+ if (dom)
+ virObjectUnlock(dom);
+
+ return PRL_ERR_SUCCESS;
+}
+
static PRL_RESULT
prlsdkHandleVmEvent(parallelsConnPtr privconn, PRL_HANDLE prlEvent)
{
@@ -1665,6 +1721,11 @@ prlsdkHandleVmEvent(parallelsConnPtr privconn, PRL_HANDLE prlEvent)
case PET_DSP_EVT_VM_UNREGISTERED:
return prlsdkHandleVmRemovedEvent(privconn, uuid);
break;
+ case PET_DSP_EVT_VM_PERFSTATS:
+ prlsdkHandlePerfEvent(privconn, prlEvent, uuid);
+ // above function takes own of event
+ prlEvent = PRL_INVALID_HANDLE;
+ break;
default:
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Can't handle event of type %d"), prlEventType);
@@ -1714,6 +1775,7 @@ prlsdkEventsHandler(PRL_HANDLE prlEvent, PRL_VOID_PTR opaque)
return pret;
}
+
int prlsdkSubscribeToPCSEvents(parallelsConnPtr privconn)
{
PRL_RESULT pret = PRL_ERR_UNINITIALIZED;
@@ -3450,3 +3512,130 @@ prlsdkDomainManagedSaveRemove(virDomainObjPtr dom)
return 0;
}
+
+static int
+prlsdkExtractStatsParam(PRL_HANDLE sdkstats, const char *name, long long *val)
+{
+ PRL_HANDLE param = PRL_INVALID_HANDLE;
+ PRL_RESULT pret;
+ PRL_INT64 pval = 0;
+ int ret = -1;
+
+ pret = PrlEvent_GetParamByName(sdkstats, name, ¶m);
+ if (pret == PRL_ERR_NO_DATA) {
+ *val = -1;
+ ret = 0;
+ goto cleanup;
+ } else if (PRL_FAILED(pret)) {
+ logPrlError(pret);
+ goto cleanup;
+ }
+ pret = PrlEvtPrm_ToInt64(param, &pval);
+ prlsdkCheckRetGoto(pret, cleanup);
+
+ *val = pval;
+ ret = 0;
+
+ cleanup:
+ PrlHandle_Free(param);
+ return ret;
+}
+
+#define PARALLELS_STATISTICS_TIMEOUT (60 * 1000)
+
+static int
+prlsdkGetStatsParam(virDomainObjPtr dom, const char *name, long long *val)
+{
+ parallelsDomObjPtr privdom = dom->privateData;
+ PRL_HANDLE job = PRL_INVALID_HANDLE;
+ unsigned long long now;
+
+ if (privdom->cache.stats != PRL_INVALID_HANDLE) {
+ // reset count to keep subscribtion
+ privdom->cache.count = 0;
+ return prlsdkExtractStatsParam(privdom->cache.stats, name, val);
+ }
+
+ if (privdom->cache.count == -1) {
+ job = PrlVm_SubscribeToPerfStats(privdom->sdkdom, NULL);
+ if (PRL_FAILED(waitJob(job)))
+ goto error;
+ }
+
+ // change state to subscribed in case of unsubscribed
+ // or reset count so we stop unsubscribe attempts
+ privdom->cache.count = 0;
+
+ if (virTimeMillisNow(&now) < 0) {
+ virReportSystemError(errno, "%s", _("Unable to get current time"));
+ goto error;
+ }
+
+ while (privdom->cache.stats == PRL_INVALID_HANDLE) {
+ if (virCondWaitUntil(&privdom->cache.cond, &dom->parent.lock,
+ now + PARALLELS_STATISTICS_TIMEOUT) < 0) {
+ if (errno == ETIMEDOUT) {
+ virReportError(VIR_ERR_OPERATION_TIMEOUT, "%s",
+ _("Timeout on waiting statistics event."));
+ goto error;
+ } else {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Unable to wait on monitor condition"));
+ goto error;
+ }
+ }
+ }
+
+ return prlsdkExtractStatsParam(privdom->cache.stats, name, val);
+ error:
+ return -1;
+}
+
+int
+prlsdkGetBlockStats(virDomainObjPtr dom, virDomainDiskDefPtr disk, virDomainBlockStatsPtr stats)
+{
+ virDomainDeviceDriveAddressPtr address;
+ int idx;
+ const char *prefix;
+ int ret = -1;
+ char *name = NULL;
+
+ address = &disk->info.addr.drive;
+ switch (disk->bus) {
+ case VIR_DOMAIN_DISK_BUS_IDE:
+ prefix = "ide";
+ idx = address->bus * 2 + address->unit;
+ break;
+ case VIR_DOMAIN_DISK_BUS_SATA:
+ prefix = "sata";
+ idx = address->unit;
+ break;
+ case VIR_DOMAIN_DISK_BUS_SCSI:
+ prefix = "scsi";
+ idx = address->unit;
+ break;
+ default:
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unknown disk bus: %X"), disk->bus);
+ goto cleanup;
+ }
+
+
+#define PRLSDK_GET_STAT_PARAM(VAL, TYPE, NAME) \
+ if (virAsprintf(&name, "devices.%s%d.%s", prefix, idx, NAME) < 0) \
+ goto cleanup; \
+ if (prlsdkGetStatsParam(dom, name, &stats->VAL) < 0) \
+ goto cleanup; \
+ VIR_FREE(name);
+
+ PARALLELS_BLOCK_STATS_FOREACH(PRLSDK_GET_STAT_PARAM)
+
+#undef PRLSDK_GET_STAT_PARAM
+
+ ret = 0;
+
+ cleanup:
+
+ VIR_FREE(name);
+ return ret;
+}
diff --git a/src/parallels/parallels_sdk.h b/src/parallels/parallels_sdk.h
index 3f17fc8..afa6745 100644
--- a/src/parallels/parallels_sdk.h
+++ b/src/parallels/parallels_sdk.h
@@ -64,3 +64,5 @@ int
prlsdkAttachVolume(virDomainObjPtr dom, virDomainDiskDefPtr disk);
int
prlsdkDetachVolume(virDomainObjPtr dom, virDomainDiskDefPtr disk);
+int
+prlsdkGetBlockStats(virDomainObjPtr dom, virDomainDiskDefPtr disk, virDomainBlockStatsPtr stats);
diff --git a/src/parallels/parallels_utils.c b/src/parallels/parallels_utils.c
index ff9d47d..540986b 100644
--- a/src/parallels/parallels_utils.c
+++ b/src/parallels/parallels_utils.c
@@ -64,6 +64,34 @@ parallelsDomObjFromDomain(virDomainPtr domain)
}
+/**
+ * parallelsDomObjFromDomainRef:
+ * @domain: Domain pointer that has to be looked up
+ *
+ * This function looks up @domain and returns the appropriate virDomainObjPtr
+ * that has to be released by calling virDomainObjEndAPI().
+ *
+ * Returns the domain object with incremented reference counter which is locked
+ * on success, NULL otherwise.
+ */
+virDomainObjPtr
+parallelsDomObjFromDomainRef(virDomainPtr domain)
+{
+ virDomainObjPtr vm;
+ parallelsConnPtr privconn = domain->conn->privateData;
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+
+ vm = virDomainObjListFindByUUIDRef(privconn->domains, domain->uuid);
+ if (!vm) {
+ virUUIDFormat(domain->uuid, uuidstr);
+ virReportError(VIR_ERR_NO_DOMAIN,
+ _("no domain with matching uuid '%s' (%s)"),
+ uuidstr, domain->name);
+ return NULL;
+ }
+
+ return vm;
+}
static int
parallelsDoCmdRun(char **outbuf, const char *binary, va_list list)
diff --git a/src/parallels/parallels_utils.h b/src/parallels/parallels_utils.h
index 2d1d405..cdf6082 100644
--- a/src/parallels/parallels_utils.h
+++ b/src/parallels/parallels_utils.h
@@ -73,11 +73,22 @@ struct _parallelsConn {
typedef struct _parallelsConn parallelsConn;
typedef struct _parallelsConn *parallelsConnPtr;
+struct _parallelsContersCache {
+ PRL_HANDLE stats;
+ virCond cond;
+ // -1 - unsubscribed
+ // > -1 - subscribed
+ int count;
+};
+
+typedef struct _parallelsContersCache parallelsContersCache;
+
struct parallelsDomObj {
int id;
char *uuid;
char *home;
PRL_HANDLE sdkdom;
+ parallelsContersCache cache;
};
typedef struct parallelsDomObj *parallelsDomObjPtr;
@@ -91,6 +102,7 @@ int parallelsNetworkClose(virConnectPtr conn);
extern virNetworkDriver parallelsNetworkDriver;
virDomainObjPtr parallelsDomObjFromDomain(virDomainPtr domain);
+virDomainObjPtr parallelsDomObjFromDomainRef(virDomainPtr domain);
virJSONValuePtr parallelsParseOutput(const char *binary, ...)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_SENTINEL;
@@ -106,4 +118,10 @@ virStorageVolPtr parallelsStorageVolLookupByPathLocked(virConnectPtr conn,
int parallelsStorageVolDefRemove(virStoragePoolObjPtr privpool,
virStorageVolDefPtr privvol);
+#define PARALLELS_BLOCK_STATS_FOREACH(OP) \
+ OP(rd_req, VIR_DOMAIN_BLOCK_STATS_READ_REQ, "read_requests") \
+ OP(rd_bytes, VIR_DOMAIN_BLOCK_STATS_READ_BYTES, "read_total") \
+ OP(wr_req, VIR_DOMAIN_BLOCK_STATS_WRITE_REQ, "write_requests") \
+ OP(wr_bytes, VIR_DOMAIN_BLOCK_STATS_WRITE_BYTES, "write_total")
+
#endif
--
1.7.1
10 years
[libvirt] [PATCH v2 0/5] RPC JSON (de)serialization and fixes
by Martin Kletzander
I took the liberty of changing Daniel's version and fix it up a bit.
I've split it into multiple patches, removed unneeded functions, and
fixed it for building without avahi.
First version here:
https://www.redhat.com/archives/libvir-list/2015-May/msg00812.html
Daniel P. Berrange (4):
rpc: add testing of RPC JSON (de)serialization
rpc: Make virNetServerAddClient function dynamic
rpc: Don't use unrelated value as privateData of client
rpc: Fix reference counting around virNetSocketAddIOCallback
Martin Kletzander (1):
mdns: Set error when failing due to missing avahi
src/libvirt_remote.syms | 1 +
src/rpc/virnetserver.c | 4 +-
src/rpc/virnetserver.h | 3 +
src/rpc/virnetserverclient.c | 13 +-
src/rpc/virnetservermdns.c | 8 +-
src/rpc/virnetserverservice.c | 6 +-
tests/Makefile.am | 7 +
tests/virnetserverdata/README | 14 +
.../virnetserverdata/input-data-anon-clients.json | 62 +++++
.../input-data-initial-nomdns.json | 61 +++++
tests/virnetserverdata/input-data-initial.json | 62 +++++
.../virnetserverdata/output-data-anon-clients.json | 62 +++++
.../output-data-initial-nomdns.json | 62 +++++
tests/virnetserverdata/output-data-initial.json | 63 +++++
tests/virnetservertest.c | 284 +++++++++++++++++++++
15 files changed, 698 insertions(+), 14 deletions(-)
create mode 100644 tests/virnetserverdata/README
create mode 100644 tests/virnetserverdata/input-data-anon-clients.json
create mode 100644 tests/virnetserverdata/input-data-initial-nomdns.json
create mode 100644 tests/virnetserverdata/input-data-initial.json
create mode 100644 tests/virnetserverdata/output-data-anon-clients.json
create mode 100644 tests/virnetserverdata/output-data-initial-nomdns.json
create mode 100644 tests/virnetserverdata/output-data-initial.json
create mode 100644 tests/virnetservertest.c
--
2.4.2
10 years
[libvirt] [PATCH 0/4] Fix some issues is FS backend
by John Ferlan
https://bugzilla.redhat.com/show_bug.cgi?id=1181087
Patch 1 was just found by inspection
Patch 2 sets up for the the eventual fix
Patch 3 Adjusts the error message to make it clearer what the problem is
Patch 4 Adds a check in the checkPool path for valid FS storage pool config
before checking for IsMounted and declaring "isActive = true"
John Ferlan (4):
storage: Remove extraneous @conn from function comments
storage: Refactor storage pool type checks
storage: FS backend adjust error message on error path
storage: Add check for valid FS types in checkPool callback
src/storage/storage_backend_fs.c | 97 ++++++++++++++++++++--------------------
1 file changed, 48 insertions(+), 49 deletions(-)
--
2.1.0
10 years
[libvirt] [PATCH] qemu: monitor: Add memory balloon support for virtio-ccw
by Boris Fiuczynski
The search for the memory ballon driver object is extended by a
second known name "virtio-ballon-ccw" in support for virtio-ccw.
Signed-off-by: Boris Fiuczynski <fiuczy(a)linux.vnet.ibm.com>
Reviewed-by: Christian Borntraeger <borntraeger(a)de.ibm.com>
---
src/qemu/qemu_monitor.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index f959b74..1a88329 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -1141,9 +1141,9 @@ qemuMonitorFindObjectPath(qemuMonitorPtr mon,
/**
- * Search the qom objects for the balloon driver object by it's known name
- * of "virtio-balloon-pci". The entry for the driver will be found by using
- * function "qemuMonitorFindObjectPath".
+ * Search the qom objects for the balloon driver object by it's known names
+ * of "virtio-balloon-pci" or "virtio-ballon-ccw". The entry for the driver
+ * will be found by using function "qemuMonitorFindObjectPath".
*
* Once found, check the entry to ensure it has the correct property listed.
* If it does not, then obtaining statistics from QEMU will not be possible.
@@ -1183,7 +1183,8 @@ qemuMonitorFindBalloonObjectPath(qemuMonitorPtr mon,
return -1;
}
- if (qemuMonitorFindObjectPath(mon, curpath, "virtio-balloon-pci", &path) < 0)
+ if (qemuMonitorFindObjectPath(mon, curpath, "virtio-balloon-pci", &path) < 0 &&
+ qemuMonitorFindObjectPath(mon, curpath, "virtio-balloon-ccw", &path) < 0)
return -1;
nprops = qemuMonitorJSONGetObjectListPaths(mon, path, &bprops);
--
2.3.0
10 years
[libvirt] [PATCH] remote: fix odd comma operator
by Eric Blake
Commit 1882c0bd accidentally used ',' instead of ';'; oddly
enough, the result was still syntactically valid (yes, C is
a fun language). But it made me do a double take; it's better
to use idiomatic syntax.
* daemon/remote.c (remoteRelayDomainEventDeviceAdded): Fix
harmless typo.
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
Pushing under the trivial rule.
daemon/remote.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/daemon/remote.c b/daemon/remote.c
index e259a76..e9e2dca 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -1068,7 +1068,7 @@ remoteRelayDomainEventDeviceAdded(virConnectPtr conn,
return -1;
make_nonnull_domain(&data.dom, dom);
- data.callbackID = callback->callbackID,
+ data.callbackID = callback->callbackID;
remoteDispatchObjectEventSend(callback->client, remoteProgram,
REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_ADDED,
--
2.4.2
10 years
[libvirt] [PATCH 0/4] Add support for vhost-user with multi-queue
by Martin Kletzander
Also some tiny clean-up.
Martin Kletzander (2):
conf: Ignore multiqueue with one queue.
qemu: Add capability for vhost-user multiqueue
Maxime Leroy (2):
docs: Clarify that attribute name is not used for vhostuser
qemu: add multiqueue vhost-user support
docs/formatdomain.html.in | 16 ++++++++++++++--
src/conf/domain_conf.c | 3 ++-
src/qemu/qemu_capabilities.c | 6 ++++++
src/qemu/qemu_capabilities.h | 1 +
src/qemu/qemu_command.c | 15 ++++++++++++++-
...tuser.args => qemuxml2argv-net-vhostuser-multiq.args} | 6 +++++-
...ostuser.xml => qemuxml2argv-net-vhostuser-multiq.xml} | 6 ++++++
.../qemuxml2argv-tap-vhost-incorrect.xml | 6 ++++++
tests/qemuxml2argvtest.c | 3 +++
.../qemuxml2xmlout-tap-vhost-incorrect.xml | 6 ++++++
10 files changed, 63 insertions(+), 5 deletions(-)
copy tests/qemuxml2argvdata/{qemuxml2argv-net-vhostuser.args => qemuxml2argv-net-vhostuser-multiq.args} (75%)
copy tests/qemuxml2argvdata/{qemuxml2argv-net-vhostuser.xml => qemuxml2argv-net-vhostuser-multiq.xml} (87%)
--
2.4.2
10 years
[libvirt] [libvirt-glib v2] storage-pool: API to get/set autostart flag
by Zeeshan Ali (Khattak)
Add binding for virStoragePoolGetAutostart & virStoragePoolSetAutostart.
---
libvirt-gobject/libvirt-gobject-storage-pool.c | 51 ++++++++++++++++++++++++++
libvirt-gobject/libvirt-gobject-storage-pool.h | 5 +++
libvirt-gobject/libvirt-gobject.sym | 6 +++
3 files changed, 62 insertions(+)
diff --git a/libvirt-gobject/libvirt-gobject-storage-pool.c b/libvirt-gobject/libvirt-gobject-storage-pool.c
index f3eac0d..7f26b1b 100644
--- a/libvirt-gobject/libvirt-gobject-storage-pool.c
+++ b/libvirt-gobject/libvirt-gobject-storage-pool.c
@@ -1048,6 +1048,57 @@ gboolean gvir_storage_pool_delete (GVirStoragePool *pool,
return TRUE;
}
+/**
+ * gvir_storage_pool_get_autostart:
+ * @pool: the storage pool
+ * @err: return location for any #GError
+ *
+ * Return value: #True if autostart is enabled, #False otherwise.
+ */
+gboolean gvir_storage_pool_get_autostart(GVirStoragePool *pool,
+ GError **err)
+{
+ int ret;
+
+ g_return_val_if_fail(GVIR_IS_STORAGE_POOL(pool), FALSE);
+ g_return_val_if_fail(err == NULL || *err == NULL, FALSE);
+
+ if (virStoragePoolGetAutostart(pool->priv->handle, &ret)) {
+ gvir_set_error_literal(err, GVIR_STORAGE_POOL_ERROR,
+ 0,
+ "Failed to get autostart flag from storage pool");
+ }
+
+ return !!ret;
+}
+
+/**
+ * gvir_storage_pool_set_autostart:
+ * @pool: the storage pool
+ * @autostart: Whether or not to autostart
+ * @err: return location for any #GError
+ *
+ * Sets whether or not storage pool @pool is started automatically on boot.
+ *
+ * Return value: #TRUE on success, #FALSE otherwise.
+ */
+gboolean gvir_storage_pool_set_autostart(GVirStoragePool *pool,
+ gboolean autostart,
+ GError **err)
+{
+ g_return_val_if_fail(GVIR_IS_STORAGE_POOL(pool), FALSE);
+ g_return_val_if_fail(err == NULL || *err == NULL, FALSE);
+
+ if (virStoragePoolSetAutostart(pool->priv->handle, autostart)) {
+ gvir_set_error_literal(err, GVIR_STORAGE_POOL_ERROR,
+ 0,
+ "Failed to set autostart flag on storage pool");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static void
gvir_storage_pool_delete_helper(GSimpleAsyncResult *res,
GObject *object,
diff --git a/libvirt-gobject/libvirt-gobject-storage-pool.h b/libvirt-gobject/libvirt-gobject-storage-pool.h
index f8529f0..f7f879c 100644
--- a/libvirt-gobject/libvirt-gobject-storage-pool.h
+++ b/libvirt-gobject/libvirt-gobject-storage-pool.h
@@ -166,6 +166,11 @@ void gvir_storage_pool_delete_async (GVirStoragePool *pool,
gboolean gvir_storage_pool_delete_finish(GVirStoragePool *pool,
GAsyncResult *result,
GError **err);
+gboolean gvir_storage_pool_get_autostart(GVirStoragePool *pool,
+ GError **err);
+gboolean gvir_storage_pool_set_autostart(GVirStoragePool *pool,
+ gboolean autostart,
+ GError **err);
G_END_DECLS
diff --git a/libvirt-gobject/libvirt-gobject.sym b/libvirt-gobject/libvirt-gobject.sym
index 927cad9..dcda675 100644
--- a/libvirt-gobject/libvirt-gobject.sym
+++ b/libvirt-gobject/libvirt-gobject.sym
@@ -265,4 +265,10 @@ LIBVIRT_GOBJECT_0.2.0 {
gvir_domain_open_graphics_fd;
} LIBVIRT_GOBJECT_0.1.9;
+LIBVIRT_GOBJECT_0.2.1 {
+ global:
+ gvir_storage_pool_get_autostart;
+ gvir_storage_pool_set_autostart;
+} LIBVIRT_GOBJECT_0.2.0;
+
# .... define new API here using predicted next version number ....
--
2.4.2
10 years
[libvirt] [PATCH v5 0/9] qemu: Add quorum support to libvirt
by Matthias Gatto
The purpose of these patches is to introduce quorum for libvirt
I've try to follow this proposal:
http://www.redhat.com/archives/libvir-list/2014-May/msg00533.html
This feature ask for 6 task:
1) Allow a _virStorageSource to contain more than one backing store.
Because all the actual libvirt code use the backingStore field
as a pointer and we needs want to change that, I've decide to encapsulate
the backingStore field to simplifie the array manipulation.
2) Add the missing field a quorum need in _virStorageSource and
the VIR_STORAGE_TYPE_QUORUM and VIR_STORAGE_FILE_QUORUM in
their respectives enums.
3) Parse and format the xml
Because a quorum allows to have more than one backing store at the same level
we need to change virDomainDiskDefFormat and virDomainDiskDefParseXML
to call virDomainDiskBackingStoreFormat and virDomainDiskBackingStoreParse
in a loop.
virDomainDiskBackingStoreFormat and virDomainDiskBackingStoreParse can
call themself recursively in a loop because a quorum can contain another
quorum
4) Add nodename
We need to add nodename support in _virStorageSource because qemu
use them for their child.
5) Build qemu string
As for the xml, we have to call the function which create quorum recursively.
But this task have the problem explained here:
http://www.redhat.com/archives/libvir-list/2014-October/msg00529.html
The _virStorageSource missing some informations that can be passed to
a child, and therefore this version of quorum is incomplet.
6) Allow to hotplug/change a disk in a quorum
This part is not present in these patches because for this task
we have to use blockdev-add, and currently libvirt use
device_add for hotpluging that doesn't allow to hotplug quorum childs.
There is 3 way to handle this problem:
1) create a virDomainBlockDevAdd function in libvirt witch call
blockdev-add.
2) use blockdev-add instead of device_add in qemuMonitorJSONAddDevice
3) write a hack which uses blockdev-add when only attaching quorum
(but i'm pretty sure this solution is not the good one)
V2:
-Rebase on master
-Add Documentation
V3:
-Transforme the backingStore field in virStorageSource into
an array of pointer instead of a pointer
-Modify virStorageSourceSetBackingStore to allow it to expand
the backingStore size.
V4:
-Rebase on master
V5:
-Rebase on master
-patch 1-4/9: use patchs from John Ferlan
-patch 4/9: check return of virStorageSourceSetBackingStore
-patch 5/9: report type of error on virStorageSourceSetBackingStore
Matthias Gatto (9):
virstoragefile: Add virStorageSourceGetBackingStore
virstoragefile: Always use virStorageSourceGetBackingStore to get
backing store
virstoragefile: Add virStorageSourceSetBackingStore
virstoragefile: Always use virStorageSourceSetBackingStore to set
backing store
virstoragefile: change backingStore to backingStores.
virstoragefile: Add quorum in virstoragefile
domain_conf: Read and Write quorum config
qemu: Add quorum support in qemuBuildDriveDevStr
virstoragefile: Add node-name
docs/formatdomain.html.in | 30 +++++-
docs/schemas/domaincommon.rng | 26 ++++-
docs/schemas/storagecommon.rng | 1 +
docs/schemas/storagevol.rng | 1 +
src/conf/domain_conf.c | 195 ++++++++++++++++++++++++++--------
src/conf/storage_conf.c | 23 ++--
src/libvirt_private.syms | 2 +
src/qemu/qemu_cgroup.c | 4 +-
src/qemu/qemu_command.c | 114 ++++++++++++++++++++
src/qemu/qemu_domain.c | 2 +-
src/qemu/qemu_driver.c | 39 ++++---
src/qemu/qemu_migration.c | 1 +
src/qemu/qemu_monitor_json.c | 4 +-
src/security/security_dac.c | 2 +-
src/security/security_selinux.c | 4 +-
src/security/virt-aa-helper.c | 2 +-
src/storage/storage_backend.c | 22 ++--
src/storage/storage_backend_fs.c | 38 ++++---
src/storage/storage_backend_gluster.c | 11 +-
src/storage/storage_backend_logical.c | 15 ++-
src/storage/storage_driver.c | 3 +-
src/util/virstoragefile.c | 122 ++++++++++++++++++---
src/util/virstoragefile.h | 13 ++-
tests/virstoragetest.c | 18 ++--
24 files changed, 551 insertions(+), 141 deletions(-)
--
2.3.5
10 years
[libvirt] [PATCH] parallels: implement attach/detach network.
by Mikhail Feoktistov
Support nova commands interface-attach and interface-detach.
For containers only.
---
src/parallels/parallels_driver.c | 16 ++++
src/parallels/parallels_sdk.c | 144 +++++++++++++++++++++++++++++++++++++-
src/parallels/parallels_sdk.h | 4 +
3 files changed, 161 insertions(+), 3 deletions(-)
diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c
index e385f3d..a49a030 100644
--- a/src/parallels/parallels_driver.c
+++ b/src/parallels/parallels_driver.c
@@ -1050,6 +1050,14 @@ static int parallelsDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
goto cleanup;
}
break;
+ case VIR_DOMAIN_DEVICE_NET:
+ ret = prlsdkAttachNet(privdom, privconn, dev->data.net);
+ if (ret) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("network attach failed"));
+ goto cleanup;
+ }
+ break;
default:
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
_("device type '%s' cannot be attached"),
@@ -1133,6 +1141,14 @@ static int parallelsDomainDetachDeviceFlags(virDomainPtr dom, const char *xml,
goto cleanup;
}
break;
+ case VIR_DOMAIN_DEVICE_NET:
+ ret = prlsdkDetachNet(privdom, privconn, dev->data.net);
+ if (ret) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("network detach failed"));
+ goto cleanup;
+ }
+ break;
default:
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
_("device type '%s' cannot be detached"),
diff --git a/src/parallels/parallels_sdk.c b/src/parallels/parallels_sdk.c
index 6e293f7..a1c9131 100644
--- a/src/parallels/parallels_sdk.c
+++ b/src/parallels/parallels_sdk.c
@@ -2751,6 +2751,12 @@ static int prlsdkAddNet(PRL_HANDLE sdkdom,
pret = PrlVmDevNet_SetMacAddress(sdknet, macstr);
prlsdkCheckRetGoto(pret, cleanup);
+ pret = PrlVmDevNet_SetConfigureWithDhcp(sdknet, true);
+ prlsdkCheckRetGoto(pret, cleanup);
+
+ pret = PrlVmDevNet_SetAutoApply(sdknet, true);
+ prlsdkCheckRetGoto(pret, cleanup);
+
if (isCt) {
if (net->model)
VIR_WARN("Setting network adapter for containers is not "
@@ -2821,14 +2827,15 @@ static int prlsdkAddNet(PRL_HANDLE sdkdom,
return ret;
}
-static void prlsdkDelNet(parallelsConnPtr privconn, virDomainNetDefPtr net)
+static int prlsdkDelNet(parallelsConnPtr privconn, virDomainNetDefPtr net)
{
+ int ret = -1;
PRL_RESULT pret;
PRL_HANDLE vnet = PRL_INVALID_HANDLE;
PRL_HANDLE job = PRL_INVALID_HANDLE;
if (net->type != VIR_DOMAIN_NET_TYPE_BRIDGE)
- return;
+ return 0;
pret = PrlVirtNet_Create(&vnet);
prlsdkCheckRetGoto(pret, cleanup);
@@ -2836,12 +2843,142 @@ static void prlsdkDelNet(parallelsConnPtr privconn, virDomainNetDefPtr net)
pret = PrlVirtNet_SetNetworkId(vnet, net->data.network.name);
prlsdkCheckRetGoto(pret, cleanup);
- PrlSrv_DeleteVirtualNetwork(privconn->server, vnet, 0);
+ job = PrlSrv_DeleteVirtualNetwork(privconn->server, vnet, 0);
if (PRL_FAILED(pret = waitJob(job)))
goto cleanup;
+ ret = 0;
+
cleanup:
PrlHandle_Free(vnet);
+ return ret;
+}
+
+int prlsdkAttachNet(virDomainObjPtr dom, parallelsConnPtr privconn, virDomainNetDefPtr net)
+{
+ int ret = -1;
+ parallelsDomObjPtr privdom = dom->privateData;
+ PRL_HANDLE job = PRL_INVALID_HANDLE;
+
+ if (!IS_CT(dom->def)) {
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+ _("network device cannot be attached"));
+ goto cleanup;
+ }
+
+ job = PrlVm_BeginEdit(privdom->sdkdom);
+ if (PRL_FAILED(waitJob(job)))
+ goto cleanup;
+
+ ret = prlsdkAddNet(privdom->sdkdom, privconn, net, IS_CT(dom->def));
+ if (ret == 0) {
+ job = PrlVm_CommitEx(privdom->sdkdom, PVCF_DETACH_HDD_BUNDLE);
+ if (PRL_FAILED(waitJob(job))) {
+ ret = -1;
+ goto cleanup;
+ }
+ }
+
+ cleanup:
+ return ret;
+}
+
+static int
+prlsdkGetNetIndex(PRL_HANDLE sdkdom, virDomainNetDefPtr net)
+{
+ int idx = -1;
+ PRL_RESULT pret;
+ PRL_UINT32 netCount;
+ PRL_UINT32 i;
+ PRL_HANDLE adapter = PRL_INVALID_HANDLE;
+ PRL_UINT32 len;
+ char adapterMac[PRL_MAC_STRING_BUFNAME];
+ char netMac[PRL_MAC_STRING_BUFNAME];
+
+ prlsdkFormatMac(&net->mac, netMac);
+ pret = PrlVmCfg_GetNetAdaptersCount(sdkdom, &netCount);
+ prlsdkCheckRetGoto(pret, cleanup);
+
+ for (i = 0; i < netCount; ++i) {
+
+ pret = PrlVmCfg_GetNetAdapter(sdkdom, i, &adapter);
+ prlsdkCheckRetGoto(pret, cleanup);
+
+ len = sizeof(adapterMac);
+ memset(adapterMac, 0, sizeof(adapterMac));
+ pret = PrlVmDevNet_GetMacAddress(adapter, adapterMac, &len);
+ prlsdkCheckRetGoto(pret, cleanup);
+
+ if (memcmp(adapterMac, netMac, PRL_MAC_STRING_BUFNAME)) {
+
+ PrlHandle_Free(adapter);
+ adapter = PRL_INVALID_HANDLE;
+ continue;
+ }
+
+ idx = i;
+ break;
+ }
+
+ cleanup:
+ PrlHandle_Free(adapter);
+ return idx;
+}
+
+static int prlsdkDelNetAdapter(PRL_HANDLE sdkdom, int idx)
+{
+ int ret = -1;
+ PRL_RESULT pret;
+ PRL_HANDLE sdknet = PRL_INVALID_HANDLE;
+
+ pret = PrlVmCfg_GetNetAdapter(sdkdom, idx, &sdknet);
+ prlsdkCheckRetGoto(pret, cleanup);
+
+ pret = PrlVmDev_Remove(sdknet);
+ prlsdkCheckRetGoto(pret, cleanup);
+
+ ret = 0;
+
+ cleanup:
+ PrlHandle_Free(sdknet);
+ return ret;
+}
+
+int prlsdkDetachNet(virDomainObjPtr dom, parallelsConnPtr privconn, virDomainNetDefPtr net)
+{
+ int ret = -1, idx = -1;
+ parallelsDomObjPtr privdom = dom->privateData;
+ PRL_HANDLE job = PRL_INVALID_HANDLE;
+
+ if (!IS_CT(dom->def)) {
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+ _("network device cannot be detached"));
+ goto cleanup;
+ }
+
+ idx = prlsdkGetNetIndex(privdom->sdkdom, net);
+ if (idx < 0)
+ goto cleanup;
+
+ job = PrlVm_BeginEdit(privdom->sdkdom);
+ if (PRL_FAILED(waitJob(job)))
+ goto cleanup;
+
+ ret = prlsdkDelNet(privconn, net);
+ if (ret != 0)
+ goto cleanup;
+
+ ret = prlsdkDelNetAdapter(privdom->sdkdom, idx);
+ if (ret == 0) {
+ job = PrlVm_CommitEx(privdom->sdkdom, PVCF_DETACH_HDD_BUNDLE);
+ if (PRL_FAILED(waitJob(job))) {
+ ret = -1;
+ goto cleanup;
+ }
+ }
+
+ cleanup:
+ return ret;
}
static int prlsdkDelDisk(PRL_HANDLE sdkdom, int idx)
@@ -3076,6 +3213,7 @@ prlsdkGetDiskIndex(PRL_HANDLE sdkdom, virDomainDiskDefPtr disk)
pret = PrlVmCfg_GetHardDisk(sdkdom, i, &hdd);
prlsdkCheckRetGoto(pret, cleanup);
+ buflen = 0;
pret = PrlVmDev_GetFriendlyName(hdd, 0, &buflen);
prlsdkCheckRetGoto(pret, cleanup);
diff --git a/src/parallels/parallels_sdk.h b/src/parallels/parallels_sdk.h
index 3f17fc8..a2c156e 100644
--- a/src/parallels/parallels_sdk.h
+++ b/src/parallels/parallels_sdk.h
@@ -64,3 +64,7 @@ int
prlsdkAttachVolume(virDomainObjPtr dom, virDomainDiskDefPtr disk);
int
prlsdkDetachVolume(virDomainObjPtr dom, virDomainDiskDefPtr disk);
+int
+prlsdkAttachNet(virDomainObjPtr dom, parallelsConnPtr privconn, virDomainNetDefPtr net);
+int
+prlsdkDetachNet(virDomainObjPtr dom, parallelsConnPtr privconn, virDomainNetDefPtr net);
--
1.7.1
10 years
[libvirt] [PATCHv3] qemu: fix unsuitable error report when get memory stats
by Wang Yufei
From: Zhang Bo <oscar.zhangbo(a)huawei.com>
when we run the command 'virsh dommemstat xxx',
althrough memballoon's model is set 'none' in vm's XML,
it still reports an error in libvirtd.log.
error : qemuMonitorFindBalloonObjectPath:1042 : internal error: Cannot determine balloon device path
Apparently, if we don't set memballoon, we don't need to
set balloon device path.
Signed-off-by: Wang Yufei <james.wangyufei(a)huawei.com>
Signed-off-by: Zhang Bo <oscar.zhangbo(a)huawei.com>
---
src/qemu/qemu_monitor.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index f959b74..8c3c6f3 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -1169,8 +1169,10 @@ qemuMonitorFindBalloonObjectPath(qemuMonitorPtr mon,
if (mon->balloonpath) {
return 0;
} else if (mon->ballooninit) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("Cannot determine balloon device path"));
+ if (vm->def->memballoon &&
+ vm->def->memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_NONE)
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Cannot determine balloon device path"));
return -1;
}
--
1.7.12.4
10 years