All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/8] libxl: domain statistics support
@ 2015-11-10 15:34 Joao Martins
  2015-11-10 15:34 ` [PATCH v2 1/8] libxl: implement virDomainGetCPUStats Joao Martins
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: Joao Martins @ 2015-11-10 15:34 UTC (permalink / raw)
  To: libvir-list; +Cc: jfehlig, Joao Martins, xen-devel

Hey,

This series bring support for various statistics about domains
regarding CPU, Memory, Network Interfaces, Block and Jobs. Not all of
the statistics are implemented: qdisk support is missing in this series
and some of the memory statistics aren't available.

With this series we further implement 7 more functions of libvirt APIs.
It is organized as follows:

 * Patch 1, 2: implements cpu/memory statistics.
 * Patch 3: implements network statistics
 * Patch 4: adds helper method virDiskNameParse as an extension
            to virDiskNameToIndex (New)
 * Patch 5: VBD block statistics. QDisk will follow up in a separate
            series regarding QEMU monitor integration.
 * Patch 6: implement fetching all domain statistics
 * Patch 7, 8: implements Job information statistics.

Overall it looks big but 70% of the patch is due to #5 and #6 but doesn't
add necessarily more complexity to the driver I believe. Patch #7 and #8
are of special importance because GetJobInfo and GetJobStats are now used
in Openstack Kilo to monitor live-migration progress. These two patches
together with the p2p migration I sent earlier let us sucessfully
live-migrate with Openstack Kilo. Furthermore with this series we get to
support nova diagnostics.

Tested this series on 4.4.3 and 4.5 setups plus Openstack Kilo.

Individual patches contain the changelog and comments addressed since v1.

Thanks!

Joao Martins (8):
  libxl: implement virDomainGetCPUStats
  libxl: implement virDomainMemorystats
  libxl: implement virDomainInterfaceStats
  util: add virDiskNameParse to handle disk and partition idx
  libxl: implement virDomainBlockStats
  libxl: implement virConnectGetAllDomainStats
  libxl: implement virDomainGetJobInfo
  libxl: implement virDomainGetJobStats

 configure.ac             |   2 +-
 src/libvirt_private.syms |   1 +
 src/libxl/libxl_domain.c |  43 +++
 src/libxl/libxl_domain.h |   6 +
 src/libxl/libxl_driver.c | 960 +++++++++++++++++++++++++++++++++++++++++++++++
 src/util/virutil.c       |  41 +-
 src/util/virutil.h       |   1 +
 tests/utiltest.c         |  56 +++
 8 files changed, 1105 insertions(+), 5 deletions(-)

-- 
2.1.4

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v2 1/8] libxl: implement virDomainGetCPUStats
  2015-11-10 15:34 [PATCH v2 0/8] libxl: domain statistics support Joao Martins
@ 2015-11-10 15:34 ` Joao Martins
  2015-11-10 15:34 ` [PATCH v2 2/8] libxl: implement virDomainMemorystats Joao Martins
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Joao Martins @ 2015-11-10 15:34 UTC (permalink / raw)
  To: libvir-list; +Cc: jfehlig, Joao Martins, xen-devel

Introduce support for domainGetCPUStats API call and consequently
allow us to use `virsh cpu-stats`. The latter returns a more brief
output than the one provided by`virsh vcpuinfo`.

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
---
Changes since v1:
 - Remove libxl_vcpuinfo_dispose() in favor or using
 libxl_vcpuinfo_list_free(), and also removing VIR_FREE call
 - Dispose libxl_dominfo after succesfull call to
 libxl_domain_info()
 - Fixed identation of parameters
 - Bump version to 1.2.22
---
 src/libxl/libxl_driver.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 110 insertions(+)

diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
index fcdcbdb..50f6e34 100644
--- a/src/libxl/libxl_driver.c
+++ b/src/libxl/libxl_driver.c
@@ -73,6 +73,8 @@ VIR_LOG_INIT("libxl.libxl_driver");
 #define LIBXL_CONFIG_FORMAT_XM "xen-xm"
 #define LIBXL_CONFIG_FORMAT_SEXPR "xen-sxpr"
 
+#define LIBXL_NB_TOTAL_CPU_STAT_PARAM 1
+
 #define HYPERVISOR_CAPABILITIES "/proc/xen/capabilities"
 #define HYPERVISOR_XENSTORED "/dev/xen/xenstored"
 
@@ -4641,6 +4643,113 @@ libxlDomainIsUpdated(virDomainPtr dom)
 }
 
 static int
+libxlDomainGetTotalCPUStats(libxlDriverPrivatePtr driver,
+                            virDomainObjPtr vm,
+                            virTypedParameterPtr params,
+                            unsigned int nparams)
+{
+    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
+    libxl_dominfo d_info;
+    int ret = -1;
+
+    if (nparams == 0)
+        return LIBXL_NB_TOTAL_CPU_STAT_PARAM;
+
+    if (libxl_domain_info(cfg->ctx, &d_info, vm->def->id) != 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("libxl_domain_info failed for domain '%d'"),
+                       vm->def->id);
+        return ret;
+    }
+
+    if (virTypedParameterAssign(&params[0], VIR_DOMAIN_CPU_STATS_CPUTIME,
+                                VIR_TYPED_PARAM_ULLONG, d_info.cpu_time) < 0)
+        nparams = ret;
+
+    libxl_dominfo_dispose(&d_info);
+    return nparams;
+}
+
+static int
+libxlDomainGetPerCPUStats(libxlDriverPrivatePtr driver,
+                          virDomainObjPtr vm,
+                          virTypedParameterPtr params,
+                          unsigned int nparams,
+                          int start_cpu,
+                          unsigned int ncpus)
+{
+    libxl_vcpuinfo *vcpuinfo;
+    int maxcpu, hostcpus;
+    size_t i;
+    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
+    int ret = -1;
+
+    if (nparams == 0 && ncpus != 0)
+        return LIBXL_NB_TOTAL_CPU_STAT_PARAM;
+    else if (nparams == 0)
+        return vm->def->maxvcpus;
+
+    if ((vcpuinfo = libxl_list_vcpu(cfg->ctx, vm->def->id, &maxcpu,
+                                    &hostcpus)) == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Failed to list vcpus for domain '%d' with libxenlight"),
+                       vm->def->id);
+        return ret;
+    }
+
+    for (i = start_cpu; i < maxcpu && i < ncpus; ++i) {
+        if (virTypedParameterAssign(&params[(i-start_cpu)],
+                                    VIR_DOMAIN_CPU_STATS_CPUTIME,
+                                    VIR_TYPED_PARAM_ULLONG,
+                                    vcpuinfo[i].vcpu_time) < 0)
+            goto cleanup;
+    }
+    ret = nparams;
+
+ cleanup:
+    libxl_vcpuinfo_list_free(vcpuinfo, maxcpu);
+    return ret;
+}
+
+static int
+libxlDomainGetCPUStats(virDomainPtr dom,
+                       virTypedParameterPtr params,
+                       unsigned int nparams,
+                       int start_cpu,
+                       unsigned int ncpus,
+                       unsigned int flags)
+{
+    libxlDriverPrivatePtr driver = dom->conn->privateData;
+    virDomainObjPtr vm = NULL;
+    int ret = -1;
+
+    virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);
+
+    if (!(vm = libxlDomObjFromDomain(dom)))
+        goto cleanup;
+
+    if (virDomainGetCPUStatsEnsureACL(dom->conn, vm->def) < 0)
+        goto cleanup;
+
+    if (!virDomainObjIsActive(vm)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       "%s", _("domain is not running"));
+        goto cleanup;
+    }
+
+    if (start_cpu == -1)
+        ret = libxlDomainGetTotalCPUStats(driver, vm, params, nparams);
+    else
+        ret = libxlDomainGetPerCPUStats(driver, vm, params, nparams,
+                                          start_cpu, ncpus);
+
+ cleanup:
+    if (vm)
+        virObjectUnlock(vm);
+    return ret;
+}
+
+static int
 libxlConnectDomainEventRegisterAny(virConnectPtr conn, virDomainPtr dom, int eventID,
                                    virConnectDomainEventGenericCallback callback,
                                    void *opaque, virFreeCallback freecb)
@@ -5233,6 +5342,7 @@ static virHypervisorDriver libxlHypervisorDriver = {
 #endif
     .nodeGetFreeMemory = libxlNodeGetFreeMemory, /* 0.9.0 */
     .nodeGetCellsFreeMemory = libxlNodeGetCellsFreeMemory, /* 1.1.1 */
+    .domainGetCPUStats = libxlDomainGetCPUStats, /* 1.2.22 */
     .connectDomainEventRegister = libxlConnectDomainEventRegister, /* 0.9.0 */
     .connectDomainEventDeregister = libxlConnectDomainEventDeregister, /* 0.9.0 */
     .domainManagedSave = libxlDomainManagedSave, /* 0.9.2 */
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 2/8] libxl: implement virDomainMemorystats
  2015-11-10 15:34 [PATCH v2 0/8] libxl: domain statistics support Joao Martins
  2015-11-10 15:34 ` [PATCH v2 1/8] libxl: implement virDomainGetCPUStats Joao Martins
@ 2015-11-10 15:34 ` Joao Martins
  2015-11-10 15:34 ` [PATCH v2 3/8] libxl: implement virDomainInterfaceStats Joao Martins
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Joao Martins @ 2015-11-10 15:34 UTC (permalink / raw)
  To: libvir-list; +Cc: jfehlig, Joao Martins, xen-devel

Introduce support for domainMemoryStats API call, which
consequently enables the use of `virsh dommemstat` command to
query for memory statistics of a domain. We support
the following statistics: balloon info, available and currently
in use. swap-in, swap-out, major-faults, minor-faults require
cooperation of the guest and thus currently not supported.

We build on the data returned from libxl_domain_info and deliver
it in the virDomainMemoryStat format.

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
---
Changes since v1:
 - Cleanup properly after error fetching domain stats
 - Dispose libxl_dominfo after succesfull call to
 libxl_domain_info()
 - Bump version to 1.2.22
---
 src/libxl/libxl_driver.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 70 insertions(+)

diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
index 50f6e34..f4fc7bc 100644
--- a/src/libxl/libxl_driver.c
+++ b/src/libxl/libxl_driver.c
@@ -4749,6 +4749,75 @@ libxlDomainGetCPUStats(virDomainPtr dom,
     return ret;
 }
 
+#define LIBXL_SET_MEMSTAT(TAG, VAL) \
+        if (i < nr_stats) { \
+            stats[i].tag = TAG; \
+            stats[i].val = VAL; \
+            i++; \
+        }
+
+static int
+libxlDomainMemoryStats(virDomainPtr dom,
+                       virDomainMemoryStatPtr stats,
+                       unsigned int nr_stats,
+                       unsigned int flags)
+{
+    libxlDriverPrivatePtr driver = dom->conn->privateData;
+    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
+    virDomainObjPtr vm;
+    libxl_dominfo d_info;
+    unsigned mem, maxmem;
+    size_t i = 0;
+    int ret = -1;
+
+    virCheckFlags(0, -1);
+
+    if (!(vm = libxlDomObjFromDomain(dom)))
+        goto cleanup;
+
+    if (virDomainMemoryStatsEnsureACL(dom->conn, vm->def) < 0)
+        goto cleanup;
+
+    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_QUERY) < 0)
+        goto cleanup;
+
+    if (!virDomainObjIsActive(vm)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       "%s", _("domain is not running"));
+        goto endjob;
+    }
+
+    if (libxl_domain_info(cfg->ctx, &d_info, vm->def->id) != 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("libxl_domain_info failed for domain '%d'"),
+                       vm->def->id);
+        goto endjob;
+    }
+    mem = d_info.current_memkb;
+    maxmem = d_info.max_memkb;
+
+    LIBXL_SET_MEMSTAT(VIR_DOMAIN_MEMORY_STAT_ACTUAL_BALLOON, maxmem - mem);
+    LIBXL_SET_MEMSTAT(VIR_DOMAIN_MEMORY_STAT_AVAILABLE, maxmem);
+    LIBXL_SET_MEMSTAT(VIR_DOMAIN_MEMORY_STAT_RSS, mem);
+
+    ret = i;
+
+    libxl_dominfo_dispose(&d_info);
+
+ endjob:
+    if (!libxlDomainObjEndJob(driver, vm)) {
+        virObjectUnlock(vm);
+        vm = NULL;
+    }
+
+ cleanup:
+    if (vm)
+        virObjectUnlock(vm);
+    return ret;
+}
+
+#undef LIBXL_SET_MEMSTAT
+
 static int
 libxlConnectDomainEventRegisterAny(virConnectPtr conn, virDomainPtr dom, int eventID,
                                    virConnectDomainEventGenericCallback callback,
@@ -5342,6 +5411,7 @@ static virHypervisorDriver libxlHypervisorDriver = {
 #endif
     .nodeGetFreeMemory = libxlNodeGetFreeMemory, /* 0.9.0 */
     .nodeGetCellsFreeMemory = libxlNodeGetCellsFreeMemory, /* 1.1.1 */
+    .domainMemoryStats = libxlDomainMemoryStats, /* 1.2.22 */
     .domainGetCPUStats = libxlDomainGetCPUStats, /* 1.2.22 */
     .connectDomainEventRegister = libxlConnectDomainEventRegister, /* 0.9.0 */
     .connectDomainEventDeregister = libxlConnectDomainEventDeregister, /* 0.9.0 */
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 3/8] libxl: implement virDomainInterfaceStats
  2015-11-10 15:34 [PATCH v2 0/8] libxl: domain statistics support Joao Martins
  2015-11-10 15:34 ` [PATCH v2 1/8] libxl: implement virDomainGetCPUStats Joao Martins
  2015-11-10 15:34 ` [PATCH v2 2/8] libxl: implement virDomainMemorystats Joao Martins
@ 2015-11-10 15:34 ` Joao Martins
  2015-11-10 15:34 ` [PATCH v2 4/8] util: add virDiskNameParse to handle disk and partition idx Joao Martins
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Joao Martins @ 2015-11-10 15:34 UTC (permalink / raw)
  To: libvir-list; +Cc: jfehlig, Joao Martins, xen-devel

Introduce support for domainInterfaceStats API call for querying
network interface statistics. Consequently it also enables the
use of `virsh domifstat <dom> <interface name>` command.

After succesful guest creation we fill the network
interfaces names based on domain, device id and append suffix
if it's emulated in the following form: vif<domid>.<devid>[-emu]. Because
we need the devid from domain config (which is filled by libxl on domain
create)  we cannot do generate the names in console callback. We also
skip this part in case the name of the interface is manually inserted
by adminstrator.

For getting the interface statistics we resort to virNetInterfaceStats
and let libvirt handle the platform specific nits. Note that the latter
is not yet supported in FreeBSD.

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
---
Changes since v1:
 - Fill <virDomainNetDef>.ifname after domain start with generated
 name from libxl  based on domain id and devid returned by libxl.
 After that path validation don interfaceStats is enterily based
 on ifname pretty much like the other drivers.
 - Modify commit message reflecting the changes mentioned in
 the previous item.
 - Bump version to 1.2.22
---
 src/libxl/libxl_domain.c | 15 +++++++++++++++
 src/libxl/libxl_driver.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 63 insertions(+)

diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c
index 40dcea1..4fbb3fc 100644
--- a/src/libxl/libxl_domain.c
+++ b/src/libxl/libxl_domain.c
@@ -901,6 +901,7 @@ libxlDomainStart(libxlDriverPrivatePtr driver, virDomainObjPtr vm,
     virDomainDefPtr def = NULL;
     virObjectEventPtr event = NULL;
     libxlSavefileHeader hdr;
+    ssize_t i;
     int ret = -1;
     uint32_t domid = 0;
     char *dom_xml = NULL;
@@ -1023,6 +1024,20 @@ libxlDomainStart(libxlDriverPrivatePtr driver, virDomainObjPtr vm,
      */
     vm->def->id = domid;
 
+    for (i = 0; i < vm->def->nnets; i++) {
+        virDomainNetDefPtr net = vm->def->nets[i];
+        libxl_device_nic *x_nic = &d_config.nics[i];
+        const char *suffix =
+            x_nic->nictype != LIBXL_NIC_TYPE_VIF ? "-emu" : "";
+
+        if (net->ifname)
+            continue;
+
+        if (virAsprintf(&net->ifname, "vif%d.%d%s",
+                        domid, x_nic->devid, suffix) < 0)
+            continue;
+    }
+
     /* Always enable domain death events */
     if (libxl_evenable_domain_death(cfg->ctx, vm->def->id, 0, &priv->deathW))
         goto cleanup_dom;
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
index f4fc7bc..9a5a74c 100644
--- a/src/libxl/libxl_driver.c
+++ b/src/libxl/libxl_driver.c
@@ -58,6 +58,7 @@
 #include "virhostdev.h"
 #include "network/bridge_driver.h"
 #include "locking/domain_lock.h"
+#include "virstats.h"
 
 #define VIR_FROM_THIS VIR_FROM_LIBXL
 
@@ -4643,6 +4644,52 @@ libxlDomainIsUpdated(virDomainPtr dom)
 }
 
 static int
+libxlDomainInterfaceStats(virDomainPtr dom,
+                          const char *path,
+                          virDomainInterfaceStatsPtr stats)
+{
+    libxlDriverPrivatePtr driver = dom->conn->privateData;
+    virDomainObjPtr vm;
+    ssize_t i;
+    int ret = -1;
+
+    if (!(vm = libxlDomObjFromDomain(dom)))
+        goto cleanup;
+
+    if (virDomainInterfaceStatsEnsureACL(dom->conn, vm->def) < 0)
+        goto cleanup;
+
+    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_QUERY) < 0)
+        goto cleanup;
+
+    if (!virDomainObjIsActive(vm)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       "%s", _("domain is not running"));
+        goto endjob;
+    }
+
+    /* Check the path is one of the domain's network interfaces. */
+    for (i = 0; i < vm->def->nnets; i++) {
+        if (vm->def->nets[i]->ifname &&
+            STREQ(vm->def->nets[i]->ifname, path)) {
+            ret = virNetInterfaceStats(path, stats);
+            break;
+        }
+    }
+
+ endjob:
+    if (!libxlDomainObjEndJob(driver, vm)) {
+        virObjectUnlock(vm);
+        vm = NULL;
+    }
+
+ cleanup:
+    if (vm)
+        virObjectUnlock(vm);
+    return ret;
+}
+
+static int
 libxlDomainGetTotalCPUStats(libxlDriverPrivatePtr driver,
                             virDomainObjPtr vm,
                             virTypedParameterPtr params,
@@ -5411,6 +5458,7 @@ static virHypervisorDriver libxlHypervisorDriver = {
 #endif
     .nodeGetFreeMemory = libxlNodeGetFreeMemory, /* 0.9.0 */
     .nodeGetCellsFreeMemory = libxlNodeGetCellsFreeMemory, /* 1.1.1 */
+    .domainInterfaceStats = libxlDomainInterfaceStats, /* 1.2.22 */
     .domainMemoryStats = libxlDomainMemoryStats, /* 1.2.22 */
     .domainGetCPUStats = libxlDomainGetCPUStats, /* 1.2.22 */
     .connectDomainEventRegister = libxlConnectDomainEventRegister, /* 0.9.0 */
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 4/8] util: add virDiskNameParse to handle disk and partition idx
  2015-11-10 15:34 [PATCH v2 0/8] libxl: domain statistics support Joao Martins
                   ` (2 preceding siblings ...)
  2015-11-10 15:34 ` [PATCH v2 3/8] libxl: implement virDomainInterfaceStats Joao Martins
@ 2015-11-10 15:34 ` Joao Martins
  2015-11-10 15:34 ` [PATCH v2 5/8] libxl: implement virDomainBlockStats Joao Martins
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Joao Martins @ 2015-11-10 15:34 UTC (permalink / raw)
  To: libvir-list; +Cc: jfehlig, Joao Martins, xen-devel

Introduce a new helper function "virDiskNameParse" which extends
virDiskNameToIndex but handling both disk index and partition index.
Also rework virDiskNameToIndex to be based on virDiskNameParse.
A test is also added for this function testing both valid and
invalid disk names.

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
---
 src/libvirt_private.syms |  1 +
 src/util/virutil.c       | 41 +++++++++++++++++++++++++++++++----
 src/util/virutil.h       |  1 +
 tests/utiltest.c         | 56 ++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 95 insertions(+), 4 deletions(-)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index a835f18..6913d7c 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -149,6 +149,7 @@ virDomainCapsNew;
 # conf/domain_conf.h
 virBlkioDeviceArrayClear;
 virDiskNameToBusDeviceIndex;
+virDiskNameParse;
 virDiskNameToIndex;
 virDomainActualNetDefFree;
 virDomainBlockedReasonTypeFromString;
diff --git a/src/util/virutil.c b/src/util/virutil.c
index cddc78a..76591be 100644
--- a/src/util/virutil.c
+++ b/src/util/virutil.c
@@ -537,14 +537,17 @@ const char *virEnumToString(const char *const*types,
 }
 
 /* Translates a device name of the form (regex) /^[fhv]d[a-z]+[0-9]*$/
- * into the corresponding index (e.g. sda => 0, hdz => 25, vdaa => 26)
- * Note that any trailing string of digits is simply ignored.
+ * into the corresponding index and partition number
+ * (e.g. sda0 => (0,0), hdz2 => (25,2), vdaa12 => (26,12))
  * @param name The name of the device
- * @return name's index, or -1 on failure
+ * @param disk The disk index to be returned
+ * @param partition The partition index to be returned
+ * @return 0 on success, or -1 on failure
  */
-int virDiskNameToIndex(const char *name)
+int virDiskNameParse(const char *name, int *disk, int *partition)
 {
     const char *ptr = NULL;
+    char *rem;
     int idx = 0;
     static char const* const drive_prefix[] = {"fd", "hd", "vd", "sd", "xvd", "ubd"};
     size_t i;
@@ -573,6 +576,36 @@ int virDiskNameToIndex(const char *name)
     if (ptr[n_digits] != '\0')
         return -1;
 
+    *disk = idx;
+
+    /* Convert trailing digits into our partition index */
+    if (partition) {
+        *partition = 0;
+
+        /* Shouldn't start by zero */
+        if (n_digits > 1 && *ptr == '0')
+            return -1;
+
+        if (n_digits && virStrToLong_i(ptr, &rem, 10, partition) < 0)
+            return -1;
+    }
+
+    return 0;
+}
+
+/* Translates a device name of the form (regex) /^[fhv]d[a-z]+[0-9]*$/
+ * into the corresponding index (e.g. sda => 0, hdz => 25, vdaa => 26)
+ * Note that any trailing string of digits is simply ignored.
+ * @param name The name of the device
+ * @return name's index, or -1 on failure
+ */
+int virDiskNameToIndex(const char *name)
+{
+    int idx;
+
+    if (virDiskNameParse(name, &idx, NULL))
+        idx = -1;
+
     return idx;
 }
 
diff --git a/src/util/virutil.h b/src/util/virutil.h
index 53025f7..02387e0 100644
--- a/src/util/virutil.h
+++ b/src/util/virutil.h
@@ -67,6 +67,7 @@ int virDoubleToStr(char **strp, double number)
 char *virFormatIntDecimal(char *buf, size_t buflen, int val)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
 
+int virDiskNameParse(const char *name, int *disk, int *partition);
 int virDiskNameToIndex(const char* str);
 char *virIndexToDiskName(int idx, const char *prefix);
 
diff --git a/tests/utiltest.c b/tests/utiltest.c
index 98c689d..a8f9060 100644
--- a/tests/utiltest.c
+++ b/tests/utiltest.c
@@ -23,6 +23,23 @@ static const char* diskNames[] = {
     "sdia", "sdib", "sdic", "sdid", "sdie", "sdif", "sdig", "sdih", "sdii", "sdij", "sdik", "sdil", "sdim", "sdin", "sdio", "sdip", "sdiq", "sdir", "sdis", "sdit", "sdiu", "sdiv", "sdiw", "sdix", "sdiy", "sdiz"
 };
 
+struct testDiskName
+{
+    const char *name;
+    int idx;
+    int partition;
+};
+
+static struct testDiskName diskNamesPart[] = {
+    {"sda0",          0,           0},
+    {"sdb10",         1,          10},
+    {"sdc2147483647", 2,  2147483647},
+};
+
+static const char* diskNamesInvalid[] = {
+    "sda00", "sda01", "sdb-1"
+};
+
 static int
 testIndexToDiskName(const void *data ATTRIBUTE_UNUSED)
 {
@@ -79,6 +96,44 @@ testDiskNameToIndex(const void *data ATTRIBUTE_UNUSED)
 
 
 
+static int
+testDiskNameParse(const void *data ATTRIBUTE_UNUSED)
+{
+    size_t i;
+    int idx;
+    int partition;
+    struct testDiskName *disk = NULL;
+
+    for (i = 0; i < ARRAY_CARDINALITY(diskNamesPart); ++i) {
+        disk = &diskNamesPart[i];
+        if (virDiskNameParse(disk->name, &idx, &partition))
+            return -1;
+
+        if (disk->idx != idx) {
+            VIR_TEST_DEBUG("\nExpect [%d]\n", disk->idx);
+            VIR_TEST_DEBUG("Actual [%d]\n", idx);
+            return -1;
+        }
+
+        if (disk->partition != partition) {
+            VIR_TEST_DEBUG("\nExpect [%d]\n", disk->partition);
+            VIR_TEST_DEBUG("Actual [%d]\n", partition);
+            return -1;
+        }
+    }
+
+    for (i = 0; i < ARRAY_CARDINALITY(diskNamesInvalid); ++i) {
+        if (!virDiskNameParse(diskNamesInvalid[i], &idx, &partition)) {
+            VIR_TEST_DEBUG("Should Fail [%s]\n", diskNamesInvalid[i]);
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+
+
 struct testVersionString
 {
     const char *string;
@@ -220,6 +275,7 @@ mymain(void)
 
     DO_TEST(IndexToDiskName);
     DO_TEST(DiskNameToIndex);
+    DO_TEST(DiskNameParse);
     DO_TEST(ParseVersionString);
     DO_TEST(RoundValueToPowerOfTwo);
     DO_TEST(OverflowCheckMacro);
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 5/8] libxl: implement virDomainBlockStats
  2015-11-10 15:34 [PATCH v2 0/8] libxl: domain statistics support Joao Martins
                   ` (3 preceding siblings ...)
  2015-11-10 15:34 ` [PATCH v2 4/8] util: add virDiskNameParse to handle disk and partition idx Joao Martins
@ 2015-11-10 15:34 ` Joao Martins
  2015-11-10 15:34 ` [PATCH v2 6/8] libxl: implement virConnectGetAllDomainStats Joao Martins
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Joao Martins @ 2015-11-10 15:34 UTC (permalink / raw)
  To: libvir-list; +Cc: jfehlig, Joao Martins, xen-devel

Introduce initial support for domainBlockStats API call that
allow us to query block device statistics. openstack nova
uses this API call to query block statistics, alongside
virDomainMemoryStats and virDomainInterfaceStats.  Note that
this patch only introduces it for VBD for starters. QDisk
will come in a separate patch series.

A new statistics data structure is introduced to fit common
statistics among others specific to the underlying block
backends. For the VBD statistics on linux these are exported
via sysfs on the path:

"/sys/bus/xen-backend/devices/vbd-<domid>-<devid>/statistics"

To calculate the block devno libxlDiskPathToID is introduced.
Each backend implements its own function to extract statistics
and let there be handled the different platforms. An alternative
would be to reuse libvirt xen driver function.

VBD stats are exposed in reqs and number of sectors from
blkback, and it's up to us to convert it to sector sizes.
The sector size is gathered through xenstore in the device
backend entry "physical-sector-size". This adds up an extra
dependency namely of xenstore for doing the xs_read.

BlockStatsFlags variant is also implemented which has the
added benefit of getting the number of flush requests.

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
---
Changes since v1:
 - Fix identation issues
 - Set ret to LIBXL_VBD_SECTOR_SIZE
 - Reuse VIR_STRDUP error instead of doing virReportError
 when we fail to set stats->backend
 - Change virAsprintf(...) error checking
 - Change error to VIR_ERR_OPERATION_FAILED when xenstore path
 does not exist and when failing to read stat.
 - Resolve issues with 'make syntax-check' with cppi installed.
 - Remove libxlDiskPathMatches in favor of using virutil
 virDiskNameParse to fetch disk and partition index.
 - Rename libxlDiskPathParse to libxlDiskPathToID and rework
 function to just convert disk and partition index to devno.
 - Bump version to 1.2.22
---
 configure.ac             |   2 +-
 src/libxl/libxl_driver.c | 375 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 376 insertions(+), 1 deletion(-)

diff --git a/configure.ac b/configure.ac
index f481c50..10c56e5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -896,7 +896,7 @@ if test "$with_libxl" != "no" ; then
         LIBS="$LIBS $LIBXL_LIBS"
         AC_CHECK_LIB([xenlight], [libxl_ctx_alloc], [
             with_libxl=yes
-            LIBXL_LIBS="$LIBXL_LIBS -lxenlight -lxenctrl"
+            LIBXL_LIBS="$LIBXL_LIBS -lxenlight -lxenctrl -lxenstore"
         ],[
             if test "$with_libxl" = "yes"; then
                 fail=1
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
index 9a5a74c..ba1d67b 100644
--- a/src/libxl/libxl_driver.c
+++ b/src/libxl/libxl_driver.c
@@ -59,6 +59,7 @@
 #include "network/bridge_driver.h"
 #include "locking/domain_lock.h"
 #include "virstats.h"
+#include <xenstore.h>
 
 #define VIR_FROM_THIS VIR_FROM_LIBXL
 
@@ -75,6 +76,7 @@ VIR_LOG_INIT("libxl.libxl_driver");
 #define LIBXL_CONFIG_FORMAT_SEXPR "xen-sxpr"
 
 #define LIBXL_NB_TOTAL_CPU_STAT_PARAM 1
+#define LIBXL_NB_TOTAL_BLK_STAT_PARAM 6
 
 #define HYPERVISOR_CAPABILITIES "/proc/xen/capabilities"
 #define HYPERVISOR_XENSTORED "/dev/xen/xenstored"
@@ -103,6 +105,25 @@ struct _libxlOSEventHookInfo {
     int id;
 };
 
+/* Object used to store disk statistics across multiple xen backends */
+typedef struct _libxlBlockStats libxlBlockStats;
+typedef libxlBlockStats *libxlBlockStatsPtr;
+struct _libxlBlockStats {
+    long long rd_req;
+    long long rd_bytes;
+    long long wr_req;
+    long long wr_bytes;
+    long long f_req;
+
+    char *backend;
+    union {
+        struct {
+            long long ds_req;
+            long long oo_req;
+        } vbd;
+    } u;
+};
+
 /* Function declarations */
 static int
 libxlDomainManagedSaveLoad(virDomainObjPtr vm,
@@ -4644,6 +4665,358 @@ libxlDomainIsUpdated(virDomainPtr dom)
 }
 
 static int
+libxlDiskPathToID(const char *virtpath)
+{
+    static char const* drive_prefix[] = {"xvd", "hd", "sd"};
+    int disk, partition, chrused;
+    int fmt, id;
+    char *r;
+    size_t i;
+
+    fmt = id = -1;
+
+    /* Find any disk prefixes we know about */
+    for (i = 0; i < ARRAY_CARDINALITY(drive_prefix); i++) {
+        if (STRPREFIX(virtpath, drive_prefix[i]) &&
+            !virDiskNameParse(virtpath, &disk, &partition)) {
+            fmt = i;
+            break;
+        }
+    }
+
+    /* Handle it same way as xvd */
+    if (fmt < 0 &&
+        (sscanf(virtpath, "d%ip%i%n", &disk, &partition, &chrused) >= 2
+         && chrused == strlen(virtpath)))
+        fmt = 0;
+
+    /* Test indexes ranges and calculate the device id */
+    switch (fmt) {
+    case 0: /* xvd */
+        if (disk <= 15 && partition <= 15)
+            id = (202 << 8) | (disk << 4) | partition;
+        else if ((disk <= ((1<<20)-1)) || partition <= 255)
+            id = (1 << 28) | (disk << 8) | partition;
+        break;
+    case 1: /* hd */
+        if (disk <= 3 && partition <= 63)
+            id = ((disk < 2 ? 3 : 22) << 8) | ((disk & 1) << 6) | partition;
+        break;
+    case 2: /* sd */
+        if (disk <= 15 && (partition <= 15))
+            id = (8 << 8) | (disk << 4) | partition;
+        break;
+    default:
+        errno = virStrToLong_i(virtpath, &r, 0, &id);
+        if (errno || *r || id > INT_MAX)
+            id = -1;
+        break;
+    }
+    return id;
+}
+
+#define LIBXL_VBD_SECTOR_SIZE 512
+
+static int
+libxlDiskSectorSize(int domid, int devno)
+{
+    char *path, *val;
+    struct xs_handle *handle;
+    int ret = LIBXL_VBD_SECTOR_SIZE;
+    unsigned int len;
+
+    handle = xs_daemon_open_readonly();
+    if (!handle) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "%s", _("cannot read sector size"));
+        return ret;
+    }
+
+    if (virAsprintf(&path, "/local/domain/%d/device/vbd/%d/backend",
+                    domid, devno) < 0)
+        goto close;
+
+    if ((val = xs_read(handle, XBT_NULL, path, &len)) == NULL)
+        goto cleanup;
+
+    VIR_FREE(path);
+    if (virAsprintf(&path, "%s/physical-sector-size", val) < 0) {
+        VIR_FREE(val);
+        goto close;
+    }
+
+    VIR_FREE(val);
+    if ((val = xs_read(handle, XBT_NULL, path, &len)) == NULL)
+        goto cleanup;
+
+    if (sscanf(val, "%d", &ret) != 1)
+        ret = LIBXL_VBD_SECTOR_SIZE;
+
+    VIR_FREE(val);
+
+ cleanup:
+    VIR_FREE(path);
+ close:
+    xs_daemon_close(handle);
+    return ret;
+}
+
+static int
+libxlDomainBlockStatsVBD(virDomainObjPtr vm,
+                         const char *dev,
+                         libxlBlockStatsPtr stats)
+{
+    int ret = -1;
+    int devno = libxlDiskPathToID(dev);
+    int size = libxlDiskSectorSize(vm->def->id, devno);
+#ifdef __linux__
+    char *path, *name, *val;
+    unsigned long long stat;
+
+    path = name = val = NULL;
+    if (devno < 0) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       "%s", _("cannot find device number"));
+        return ret;
+    }
+    if (VIR_STRDUP(stats->backend, "vbd") < 0)
+        return ret;
+
+    if (virAsprintf(&path, "/sys/bus/xen-backend/devices/vbd-%d-%d/statistics",
+                    vm->def->id, devno) < 0)
+        return ret;
+
+    if (!virFileExists(path)) {
+        virReportError(VIR_ERR_OPERATION_FAILED,
+                       "%s", _("cannot open bus path"));
+        goto cleanup;
+    }
+
+# define LIBXL_SET_VBDSTAT(FIELD, VAR, MUL)           \
+    if ((virAsprintf(&name, "%s/"FIELD, path) < 0) || \
+        (virFileReadAll(name, 256, &val) < 0) ||      \
+        (sscanf(val, "%llu", &stat) != 1)) {          \
+        virReportError(VIR_ERR_OPERATION_FAILED,     \
+                       _("cannot read %s"), name);    \
+        goto cleanup;                                 \
+    }                                                 \
+    VAR += (stat * MUL);                              \
+    VIR_FREE(name);                                   \
+    VIR_FREE(val);
+
+    LIBXL_SET_VBDSTAT("f_req",  stats->f_req,  1)
+    LIBXL_SET_VBDSTAT("wr_req", stats->wr_req, 1)
+    LIBXL_SET_VBDSTAT("rd_req", stats->rd_req, 1)
+    LIBXL_SET_VBDSTAT("wr_sect", stats->wr_bytes, size)
+    LIBXL_SET_VBDSTAT("rd_sect", stats->rd_bytes, size)
+
+    LIBXL_SET_VBDSTAT("ds_req", stats->u.vbd.ds_req, size)
+    LIBXL_SET_VBDSTAT("oo_req", stats->u.vbd.oo_req, 1)
+    ret = 0;
+
+ cleanup:
+    VIR_FREE(name);
+    VIR_FREE(path);
+    VIR_FREE(val);
+
+# undef LIBXL_SET_VBDSTAT
+
+#else
+    virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
+                   "%s", _("platform unsupported"));
+#endif
+    return ret;
+}
+
+static int
+libxlDomainBlockStatsGatherSingle(virDomainObjPtr vm,
+                                  const char *path,
+                                  libxlBlockStatsPtr stats)
+{
+    virDomainDiskDefPtr disk;
+    const char *disk_drv;
+    int ret = -1, disk_fmt;
+
+    if (!(disk = virDomainDiskByName(vm->def, path, false))) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("invalid path: %s"), path);
+        return ret;
+    }
+
+    disk_fmt = virDomainDiskGetFormat(disk);
+    if (!(disk_drv = virDomainDiskGetDriver(disk)))
+        disk_drv = "qemu";
+
+    if (STREQ(disk_drv, "phy")) {
+        if (disk_fmt != VIR_STORAGE_FILE_RAW &&
+            disk_fmt != VIR_STORAGE_FILE_NONE) {
+            virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
+                           _("unsupported format %s"),
+                           virStorageFileFormatTypeToString(disk_fmt));
+            return ret;
+        }
+
+        ret = libxlDomainBlockStatsVBD(vm, path, stats);
+    } else {
+            virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
+                           _("unsupported disk driver %s"),
+                           disk_drv);
+            return ret;
+    }
+    return ret;
+}
+
+static int
+libxlDomainBlockStatsGather(virDomainObjPtr vm,
+                            const char *path,
+                            libxlBlockStatsPtr stats)
+{
+    int ret = -1;
+    if (*path) {
+        if (libxlDomainBlockStatsGatherSingle(vm, path, stats) < 0)
+            return ret;
+    } else {
+        size_t i;
+        for (i = 0; i < vm->def->ndisks; ++i) {
+            if (libxlDomainBlockStatsGatherSingle(vm, vm->def->disks[i]->dst,
+                                                  stats) < 0)
+                return ret;
+        }
+    }
+    return 0;
+}
+
+static int
+libxlDomainBlockStats(virDomainPtr dom,
+                      const char *path,
+                      virDomainBlockStatsPtr stats)
+{
+    libxlDriverPrivatePtr driver = dom->conn->privateData;
+    virDomainObjPtr vm;
+    libxlBlockStats blkstats;
+    int ret = -1;
+
+    if (!(vm = libxlDomObjFromDomain(dom)))
+        goto cleanup;
+
+    if (virDomainBlockStatsEnsureACL(dom->conn, vm->def) < 0)
+        goto cleanup;
+
+    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_QUERY) < 0)
+        goto cleanup;
+
+    if (!virDomainObjIsActive(vm)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       "%s", _("domain is not running"));
+        goto endjob;
+    }
+
+    memset(&blkstats, 0, sizeof(libxlBlockStats));
+    if ((ret = libxlDomainBlockStatsGather(vm, path, &blkstats)) < 0)
+        goto endjob;
+
+    stats->rd_req = blkstats.rd_req;
+    stats->rd_bytes = blkstats.rd_bytes;
+    stats->wr_req = blkstats.wr_req;
+    stats->wr_bytes = blkstats.wr_bytes;
+    if (STREQ_NULLABLE(blkstats.backend, "vbd"))
+        stats->errs = blkstats.u.vbd.oo_req;
+    else
+        stats->errs = -1;
+
+ endjob:
+    if (!libxlDomainObjEndJob(driver, vm)) {
+        virObjectUnlock(vm);
+        vm = NULL;
+    }
+
+ cleanup:
+    if (vm)
+        virObjectUnlock(vm);
+    return ret;
+}
+
+static int
+libxlDomainBlockStatsFlags(virDomainPtr dom,
+                           const char *path,
+                           virTypedParameterPtr params,
+                           int *nparams,
+                           unsigned int flags)
+{
+    libxlDriverPrivatePtr driver = dom->conn->privateData;
+    virDomainObjPtr vm;
+    libxlBlockStats blkstats;
+    int nstats;
+    int ret = -1;
+
+    virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);
+
+    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;
+
+    if (!(vm = libxlDomObjFromDomain(dom)))
+        goto cleanup;
+
+    if (virDomainBlockStatsFlagsEnsureACL(dom->conn, vm->def) < 0)
+        goto cleanup;
+
+    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_QUERY) < 0)
+        goto cleanup;
+
+    if (!virDomainObjIsActive(vm)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       "%s", _("domain is not running"));
+        goto endjob;
+    }
+
+    /* return count of supported stats */
+    if (*nparams == 0) {
+        *nparams = LIBXL_NB_TOTAL_BLK_STAT_PARAM;
+        ret = 0;
+        goto endjob;
+    }
+
+    memset(&blkstats, 0, sizeof(libxlBlockStats));
+    if ((ret = libxlDomainBlockStatsGather(vm, path, &blkstats)) < 0)
+        goto endjob;
+
+    nstats = 0;
+
+#define LIBXL_BLKSTAT_ASSIGN_PARAM(VAR, NAME)                              \
+    if (nstats < *nparams && (blkstats.VAR) != -1) {                       \
+        if (virTypedParameterAssign(params + nstats, NAME,                 \
+                                    VIR_TYPED_PARAM_LLONG, (blkstats.VAR)) < 0) \
+            goto endjob;                                                   \
+        nstats++;                                                          \
+    }
+
+    LIBXL_BLKSTAT_ASSIGN_PARAM(wr_bytes, VIR_DOMAIN_BLOCK_STATS_WRITE_BYTES);
+    LIBXL_BLKSTAT_ASSIGN_PARAM(wr_req, VIR_DOMAIN_BLOCK_STATS_WRITE_REQ);
+
+    LIBXL_BLKSTAT_ASSIGN_PARAM(rd_bytes, VIR_DOMAIN_BLOCK_STATS_READ_BYTES);
+    LIBXL_BLKSTAT_ASSIGN_PARAM(rd_req, VIR_DOMAIN_BLOCK_STATS_READ_REQ);
+
+    LIBXL_BLKSTAT_ASSIGN_PARAM(f_req, VIR_DOMAIN_BLOCK_STATS_FLUSH_REQ);
+
+    if (STREQ_NULLABLE(blkstats.backend, "vbd"))
+        LIBXL_BLKSTAT_ASSIGN_PARAM(u.vbd.oo_req, VIR_DOMAIN_BLOCK_STATS_ERRS);
+
+    *nparams = nstats;
+
+#undef LIBXL_BLKSTAT_ASSIGN_PARAM
+
+ endjob:
+    if (!libxlDomainObjEndJob(driver, vm)) {
+        virObjectUnlock(vm);
+        vm = NULL;
+    }
+
+ cleanup:
+    if (vm)
+        virObjectUnlock(vm);
+    return ret;
+}
+
+static int
 libxlDomainInterfaceStats(virDomainPtr dom,
                           const char *path,
                           virDomainInterfaceStatsPtr stats)
@@ -5458,6 +5831,8 @@ static virHypervisorDriver libxlHypervisorDriver = {
 #endif
     .nodeGetFreeMemory = libxlNodeGetFreeMemory, /* 0.9.0 */
     .nodeGetCellsFreeMemory = libxlNodeGetCellsFreeMemory, /* 1.1.1 */
+    .domainBlockStats = libxlDomainBlockStats, /* 1.2.22 */
+    .domainBlockStatsFlags = libxlDomainBlockStatsFlags, /* 1.2.22 */
     .domainInterfaceStats = libxlDomainInterfaceStats, /* 1.2.22 */
     .domainMemoryStats = libxlDomainMemoryStats, /* 1.2.22 */
     .domainGetCPUStats = libxlDomainGetCPUStats, /* 1.2.22 */
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 6/8] libxl: implement virConnectGetAllDomainStats
  2015-11-10 15:34 [PATCH v2 0/8] libxl: domain statistics support Joao Martins
                   ` (4 preceding siblings ...)
  2015-11-10 15:34 ` [PATCH v2 5/8] libxl: implement virDomainBlockStats Joao Martins
@ 2015-11-10 15:34 ` Joao Martins
  2015-11-10 15:34 ` [PATCH v2 7/8] libxl: implement virDomainGetJobInfo Joao Martins
  2015-11-10 15:34 ` [PATCH v2 8/8] libxl: implement virDomainGetJobStats Joao Martins
  7 siblings, 0 replies; 9+ messages in thread
From: Joao Martins @ 2015-11-10 15:34 UTC (permalink / raw)
  To: libvir-list; +Cc: jfehlig, Joao Martins, xen-devel

Introduce support for connectGetAllDomainStats call that
allow us to _all_ domain(s) statistics including network, block,
cpus and memory. Changes are rather mechanical and mostly
take care of the format to export the data.

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
---
Changes since v1:
 - Rework flags checking on libxlDomainGetStats
 for VIR_DOMAIN_STATS_{VCPU,INTERFACE,BLOCK}
 - Removed path since we are reusing <virDomainNetDef>.ifname
 - Init dominfo and dispose it on cleanup.
 - Fixed VIR_FREE issue that was reported with make syntax-check"
 - Bump version to 1.2.22
---
 src/libxl/libxl_driver.c | 266 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 266 insertions(+)

diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
index ba1d67b..8db6536 100644
--- a/src/libxl/libxl_driver.c
+++ b/src/libxl/libxl_driver.c
@@ -5238,6 +5238,271 @@ libxlDomainMemoryStats(virDomainPtr dom,
 
 #undef LIBXL_SET_MEMSTAT
 
+#define LIBXL_RECORD_UINT(error, key, value, ...) \
+do { \
+    char param_name[VIR_TYPED_PARAM_FIELD_LENGTH]; \
+    snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, \
+             key, ##__VA_ARGS__); \
+    if (virTypedParamsAddUInt(&tmp->params, \
+                              &tmp->nparams, \
+                              &maxparams, \
+                              param_name, \
+                              value) < 0) \
+        goto error;                       \
+} while (0)
+
+#define LIBXL_RECORD_LL(error, key, value, ...) \
+do { \
+    char param_name[VIR_TYPED_PARAM_FIELD_LENGTH]; \
+    snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, \
+             key, ##__VA_ARGS__); \
+    if (virTypedParamsAddLLong(&tmp->params, \
+                               &tmp->nparams, \
+                               &maxparams, \
+                               param_name, \
+                               value) < 0) \
+        goto error;                         \
+} while (0)
+
+#define LIBXL_RECORD_ULL(error, key, value, ...) \
+do { \
+    char param_name[VIR_TYPED_PARAM_FIELD_LENGTH]; \
+    snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, \
+             key, ##__VA_ARGS__); \
+    if (virTypedParamsAddULLong(&tmp->params, \
+                                &tmp->nparams, \
+                                &maxparams, \
+                                param_name, \
+                                value) < 0) \
+        goto error;                         \
+} while (0)
+
+#define LIBXL_RECORD_STR(error, key, value, ...) \
+do { \
+    char param_name[VIR_TYPED_PARAM_FIELD_LENGTH]; \
+    snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, \
+             key, ##__VA_ARGS__); \
+    if (virTypedParamsAddString(&tmp->params, \
+                                &tmp->nparams, \
+                                &maxparams, \
+                                param_name, \
+                                value) < 0) \
+        goto error;                         \
+} while (0)
+
+static int
+libxlDomainGetStats(virConnectPtr conn,
+                    virDomainObjPtr dom,
+                    unsigned int stats,
+                    virDomainStatsRecordPtr *record)
+{
+    libxlDriverPrivatePtr driver = conn->privateData;
+    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
+    virDomainStatsRecordPtr tmp;
+    libxl_dominfo d_info;
+    libxl_vcpuinfo *vcpuinfo = NULL;
+    int maxcpu, hostcpus;
+    unsigned long long mem, maxmem;
+    int maxparams = 0;
+    int ret = -1;
+    size_t i, state;
+    unsigned int domflags = stats & (VIR_DOMAIN_STATS_BALLOON |
+                                     VIR_DOMAIN_STATS_CPU_TOTAL);
+
+    if (VIR_ALLOC(tmp) < 0)
+        return ret;
+
+    libxl_dominfo_init(&d_info);
+
+    mem = virDomainDefGetMemoryInitial(dom->def);
+    maxmem = virDomainDefGetMemoryActual(dom->def);
+    d_info.cpu_time = 0;
+
+    if (domflags && virDomainObjIsActive(dom) &&
+        !libxl_domain_info(cfg->ctx, &d_info, dom->def->id)) {
+        mem = d_info.current_memkb;
+        maxmem = d_info.max_memkb;
+    }
+
+    if (stats & VIR_DOMAIN_STATS_STATE) {
+        LIBXL_RECORD_UINT(cleanup, "state.reason", dom->state.reason);
+        LIBXL_RECORD_UINT(cleanup, "state.state", dom->state.state);
+    }
+
+    if (stats & VIR_DOMAIN_STATS_BALLOON) {
+        LIBXL_RECORD_ULL(cleanup, "balloon.current", mem);
+        LIBXL_RECORD_ULL(cleanup, "balloon.maximum", maxmem);
+    }
+
+    if (stats & VIR_DOMAIN_STATS_CPU_TOTAL)
+        LIBXL_RECORD_ULL(cleanup, "cpu.time", d_info.cpu_time);
+
+    if (stats & VIR_DOMAIN_STATS_VCPU) {
+        vcpuinfo = libxl_list_vcpu(cfg->ctx, dom->def->id, &maxcpu, &hostcpus);
+
+        for (i = 0; i < dom->def->vcpus; i++) {
+            if (!vcpuinfo)
+                state = VIR_VCPU_OFFLINE;
+            else if (vcpuinfo[i].running)
+                state = VIR_VCPU_RUNNING;
+            else if (vcpuinfo[i].blocked)
+                state = VIR_VCPU_BLOCKED;
+            else
+                state = VIR_VCPU_OFFLINE;
+
+            LIBXL_RECORD_UINT(cleanup_vcpu, "vcpu.%zu.state", state, i);
+
+            /* vcputime is shown only if the VM is active */
+            if (!virDomainObjIsActive(dom))
+                continue;
+
+            LIBXL_RECORD_ULL(cleanup_vcpu, "vcpu.%zu.time", vcpuinfo[i].vcpu_time, i);
+        }
+
+        if (vcpuinfo)
+            libxl_vcpuinfo_list_free(vcpuinfo, maxcpu);
+    }
+
+    if (stats & VIR_DOMAIN_STATS_INTERFACE) {
+        for (i = 0; i < dom->def->nnets; i++) {
+            virDomainNetDefPtr net = dom->def->nets[i];
+            struct _virDomainInterfaceStats netstats;
+
+            if (!virDomainObjIsActive(dom) || !net->ifname)
+                continue;
+
+            if ((ret = virNetInterfaceStats(net->ifname, &netstats)) < 0)
+                continue;
+
+            LIBXL_RECORD_ULL(cleanup, "net.%zu.rx.bytes", netstats.rx_bytes, i);
+            LIBXL_RECORD_ULL(cleanup, "net.%zu.rx.pkts",  netstats.rx_packets,  i);
+            LIBXL_RECORD_ULL(cleanup, "net.%zu.rx.drop",  netstats.rx_drop, i);
+            LIBXL_RECORD_ULL(cleanup, "net.%zu.rx.errs",  netstats.rx_errs,  i);
+            LIBXL_RECORD_ULL(cleanup, "net.%zu.tx.bytes", netstats.tx_bytes, i);
+            LIBXL_RECORD_ULL(cleanup, "net.%zu.tx.pkts",  netstats.tx_packets,  i);
+            LIBXL_RECORD_ULL(cleanup, "net.%zu.tx.drop",  netstats.tx_drop, i);
+            LIBXL_RECORD_ULL(cleanup, "net.%zu.tx.errs",  netstats.tx_errs,  i);
+            LIBXL_RECORD_STR(cleanup, "net.%zu.name", net->ifname, i);
+        }
+
+        LIBXL_RECORD_UINT(cleanup, "net.count", dom->def->nnets);
+    }
+
+    if (stats & VIR_DOMAIN_STATS_BLOCK) {
+        for (i = 0; i < dom->def->ndisks; i++) {
+            virDomainDiskDefPtr disk = dom->def->disks[i];
+            struct _libxlBlockStats blkstats;
+
+            if (!virDomainObjIsActive(dom))
+                continue;
+
+            memset(&blkstats, 0, sizeof(libxlBlockStats));
+            if ((ret = libxlDomainBlockStatsGather(dom, disk->dst, &blkstats)) < 0)
+                continue;
+
+            LIBXL_RECORD_LL(cleanup, "block.%zu.rd.reqs",  blkstats.rd_req, i);
+            LIBXL_RECORD_LL(cleanup, "block.%zu.rd.bytes", blkstats.rd_bytes, i);
+            LIBXL_RECORD_LL(cleanup, "block.%zu.wr.reqs",  blkstats.wr_req, i);
+            LIBXL_RECORD_LL(cleanup, "block.%zu.wr.bytes", blkstats.wr_bytes, i);
+            LIBXL_RECORD_LL(cleanup, "block.%zu.fl.reqs",  blkstats.f_req, i);
+
+            if (STREQ_NULLABLE(blkstats.backend, "vbd")) {
+                LIBXL_RECORD_LL(cleanup, "block.%zu.discard.reqs", blkstats.u.vbd.ds_req, i);
+                LIBXL_RECORD_LL(cleanup, "block.%zu.errs", blkstats.u.vbd.oo_req, i);
+            }
+            LIBXL_RECORD_STR(cleanup, "block.%zu.name", disk->dst, i);
+            LIBXL_RECORD_STR(cleanup, "block.%zu.path", disk->src->path, i);
+        }
+
+        LIBXL_RECORD_UINT(cleanup, "block.count", dom->def->ndisks);
+    }
+
+    if (!(tmp->dom = virGetDomain(conn, dom->def->name, dom->def->uuid)))
+        goto cleanup;
+
+    *record = tmp;
+    return 0;
+
+ cleanup_vcpu:
+    if (vcpuinfo)
+        libxl_vcpuinfo_list_free(vcpuinfo, maxcpu);
+ cleanup:
+    libxl_dominfo_dispose(&d_info);
+    virTypedParamsFree(tmp->params, tmp->nparams);
+    VIR_FREE(tmp);
+    return ret;
+}
+
+static int
+libxlConnectGetAllDomainStats(virConnectPtr conn,
+                              virDomainPtr *doms,
+                              unsigned int ndoms,
+                              unsigned int stats,
+                              virDomainStatsRecordPtr **retStats,
+                              unsigned int flags)
+{
+    libxlDriverPrivatePtr driver = conn->privateData;
+    virDomainObjPtr *vms = NULL;
+    virDomainObjPtr vm;
+    size_t nvms;
+    virDomainStatsRecordPtr *tmpstats = NULL;
+    int nstats = 0;
+    size_t i;
+    int ret = -1;
+    unsigned int lflags = flags & (VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE |
+                                   VIR_CONNECT_LIST_DOMAINS_FILTERS_PERSISTENT |
+                                   VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE);
+
+    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE |
+                  VIR_CONNECT_LIST_DOMAINS_FILTERS_PERSISTENT |
+                  VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE, -1);
+
+    if (virConnectGetAllDomainStatsEnsureACL(conn) < 0)
+        return -1;
+
+    if (ndoms) {
+        if (virDomainObjListConvert(driver->domains, conn, doms, ndoms, &vms,
+                                    &nvms, virConnectGetAllDomainStatsCheckACL,
+                                    lflags, true) < 0)
+            return -1;
+    } else {
+        if (virDomainObjListCollect(driver->domains, conn, &vms, &nvms,
+                                    virConnectGetAllDomainStatsCheckACL,
+                                    lflags) < 0)
+            return -1;
+    }
+
+    if (VIR_ALLOC_N(tmpstats, nvms + 1) < 0)
+        return -1;
+
+    for (i = 0; i < nvms; i++) {
+        virDomainStatsRecordPtr tmp = NULL;
+        vm = vms[i];
+
+        virObjectLock(vm);
+
+        if (libxlDomainGetStats(conn, vm, stats, &tmp) < 0) {
+            virObjectUnlock(vm);
+            goto cleanup;
+        }
+
+        if (tmp)
+            tmpstats[nstats++] = tmp;
+
+        virObjectUnlock(vm);
+    }
+
+    *retStats = tmpstats;
+    tmpstats = NULL;
+
+    ret = nstats;
+
+ cleanup:
+    virDomainStatsRecordListFree(tmpstats);
+    virObjectListFreeCount(vms, nvms);
+    return ret;
+}
+
 static int
 libxlConnectDomainEventRegisterAny(virConnectPtr conn, virDomainPtr dom, int eventID,
                                    virConnectDomainEventGenericCallback callback,
@@ -5836,6 +6101,7 @@ static virHypervisorDriver libxlHypervisorDriver = {
     .domainInterfaceStats = libxlDomainInterfaceStats, /* 1.2.22 */
     .domainMemoryStats = libxlDomainMemoryStats, /* 1.2.22 */
     .domainGetCPUStats = libxlDomainGetCPUStats, /* 1.2.22 */
+    .connectGetAllDomainStats = libxlConnectGetAllDomainStats, /* 1.2.22 */
     .connectDomainEventRegister = libxlConnectDomainEventRegister, /* 0.9.0 */
     .connectDomainEventDeregister = libxlConnectDomainEventDeregister, /* 0.9.0 */
     .domainManagedSave = libxlDomainManagedSave, /* 0.9.2 */
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 7/8] libxl: implement virDomainGetJobInfo
  2015-11-10 15:34 [PATCH v2 0/8] libxl: domain statistics support Joao Martins
                   ` (5 preceding siblings ...)
  2015-11-10 15:34 ` [PATCH v2 6/8] libxl: implement virConnectGetAllDomainStats Joao Martins
@ 2015-11-10 15:34 ` Joao Martins
  2015-11-10 15:34 ` [PATCH v2 8/8] libxl: implement virDomainGetJobStats Joao Martins
  7 siblings, 0 replies; 9+ messages in thread
From: Joao Martins @ 2015-11-10 15:34 UTC (permalink / raw)
  To: libvir-list; +Cc: jfehlig, Joao Martins, xen-devel

Introduce support for domainGetJobInfo to get info about the
ongoing job. If the job is active it will update the
timeElapsed which is computed with the "started" field added to
struct libxlDomainJobObj.  For now we support just the very basic
info and all jobs have VIR_DOMAIN_JOB_UNBOUNDED (i.e. no completion
time estimation) plus timeElapsed computed.

Openstack Kilo uses the Job API to monitor live-migration
progress which is currently nonexistent in libxl driver and
therefore leads to a crash in the nova compute node. Right
now, migration doesn't use jobs in the source node and will
return VIR_DOMAIN_JOB_NONE. Though nova handles this case and
will migrate it properly instead of crashing.

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
---
Changes since v1:
 - s/inexistent/nonexistent/g in commit message
 - s/estimed/estimated/g
 - Bump version to 1.2.22
---
 src/libxl/libxl_domain.c | 28 ++++++++++++++++++++++++++++
 src/libxl/libxl_domain.h |  6 ++++++
 src/libxl/libxl_driver.c | 38 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 72 insertions(+)

diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c
index 4fbb3fc..0411e9b 100644
--- a/src/libxl/libxl_domain.c
+++ b/src/libxl/libxl_domain.c
@@ -74,6 +74,10 @@ libxlDomainObjInitJob(libxlDomainObjPrivatePtr priv)
     if (virCondInit(&priv->job.cond) < 0)
         return -1;
 
+    if (VIR_ALLOC(priv->job.current) < 0)
+        return -1;
+
+    memset(priv->job.current, 0, sizeof(*(priv->job.current)));
     return 0;
 }
 
@@ -90,6 +94,7 @@ static void
 libxlDomainObjFreeJob(libxlDomainObjPrivatePtr priv)
 {
     ignore_value(virCondDestroy(&priv->job.cond));
+    VIR_FREE(priv->job.current);
 }
 
 /* Give up waiting for mutex after 30 seconds */
@@ -131,6 +136,8 @@ libxlDomainObjBeginJob(libxlDriverPrivatePtr driver ATTRIBUTE_UNUSED,
     VIR_DEBUG("Starting job: %s", libxlDomainJobTypeToString(job));
     priv->job.active = job;
     priv->job.owner = virThreadSelfID();
+    priv->job.started = now;
+    priv->job.current->type = VIR_DOMAIN_JOB_UNBOUNDED;
 
     return 0;
 
@@ -179,6 +186,27 @@ libxlDomainObjEndJob(libxlDriverPrivatePtr driver ATTRIBUTE_UNUSED,
     return virObjectUnref(obj);
 }
 
+int
+libxlDomainJobUpdateTime(struct libxlDomainJobObj *job)
+{
+    virDomainJobInfoPtr jobInfo = job->current;
+    unsigned long long now;
+
+    if (!job->started)
+        return 0;
+
+    if (virTimeMillisNow(&now) < 0)
+        return -1;
+
+    if (now < job->started) {
+        job->started = 0;
+        return 0;
+    }
+
+    jobInfo->timeElapsed = now - job->started;
+    return 0;
+}
+
 static void *
 libxlDomainObjPrivateAlloc(void)
 {
diff --git a/src/libxl/libxl_domain.h b/src/libxl/libxl_domain.h
index 44b3e0b..1c1eba3 100644
--- a/src/libxl/libxl_domain.h
+++ b/src/libxl/libxl_domain.h
@@ -53,6 +53,8 @@ struct libxlDomainJobObj {
     virCond cond;                       /* Use to coordinate jobs */
     enum libxlDomainJob active;         /* Currently running job */
     int owner;                          /* Thread which set current job */
+    unsigned long long started;         /* When the job started */
+    virDomainJobInfoPtr current;        /* Statistics for the current job */
 };
 
 typedef struct _libxlDomainObjPrivate libxlDomainObjPrivate;
@@ -88,6 +90,10 @@ libxlDomainObjEndJob(libxlDriverPrivatePtr driver,
                      virDomainObjPtr obj)
     ATTRIBUTE_RETURN_CHECK;
 
+int
+libxlDomainJobUpdateTime(struct libxlDomainJobObj *job)
+    ATTRIBUTE_RETURN_CHECK;
+
 void
 libxlDomainEventQueue(libxlDriverPrivatePtr driver,
                       virObjectEventPtr event);
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
index 8db6536..b0b6ea7 100644
--- a/src/libxl/libxl_driver.c
+++ b/src/libxl/libxl_driver.c
@@ -5236,6 +5236,43 @@ libxlDomainMemoryStats(virDomainPtr dom,
     return ret;
 }
 
+static int
+libxlDomainGetJobInfo(virDomainPtr dom,
+                      virDomainJobInfoPtr info)
+{
+    libxlDomainObjPrivatePtr priv;
+    virDomainObjPtr vm;
+    int ret = -1;
+
+    if (!(vm = libxlDomObjFromDomain(dom)))
+        goto cleanup;
+
+    if (virDomainGetJobInfoEnsureACL(dom->conn, vm->def) < 0)
+        goto cleanup;
+
+    priv = vm->privateData;
+    if (!priv->job.active) {
+        memset(info, 0, sizeof(*info));
+        info->type = VIR_DOMAIN_JOB_NONE;
+        ret = 0;
+        goto cleanup;
+    }
+
+    /* In libxl we don't have an estimated completion time
+     * thus we always set to unbounded and update time
+     * for the active job. */
+    if (libxlDomainJobUpdateTime(&priv->job) < 0)
+        goto cleanup;
+
+    memcpy(info, priv->job.current, sizeof(virDomainJobInfo));
+    ret = 0;
+
+ cleanup:
+    if (vm)
+        virObjectUnlock(vm);
+    return ret;
+}
+
 #undef LIBXL_SET_MEMSTAT
 
 #define LIBXL_RECORD_UINT(error, key, value, ...) \
@@ -6096,6 +6133,7 @@ static virHypervisorDriver libxlHypervisorDriver = {
 #endif
     .nodeGetFreeMemory = libxlNodeGetFreeMemory, /* 0.9.0 */
     .nodeGetCellsFreeMemory = libxlNodeGetCellsFreeMemory, /* 1.1.1 */
+    .domainGetJobInfo = libxlDomainGetJobInfo, /* 1.2.22 */
     .domainBlockStats = libxlDomainBlockStats, /* 1.2.22 */
     .domainBlockStatsFlags = libxlDomainBlockStatsFlags, /* 1.2.22 */
     .domainInterfaceStats = libxlDomainInterfaceStats, /* 1.2.22 */
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 8/8] libxl: implement virDomainGetJobStats
  2015-11-10 15:34 [PATCH v2 0/8] libxl: domain statistics support Joao Martins
                   ` (6 preceding siblings ...)
  2015-11-10 15:34 ` [PATCH v2 7/8] libxl: implement virDomainGetJobInfo Joao Martins
@ 2015-11-10 15:34 ` Joao Martins
  7 siblings, 0 replies; 9+ messages in thread
From: Joao Martins @ 2015-11-10 15:34 UTC (permalink / raw)
  To: libvir-list; +Cc: jfehlig, Joao Martins, xen-devel

Introduces support for domainGetJobStats which has the same
info as domainGetJobInfo but in a slightly different format.
Another difference is that virDomainGetJobStats can also
retrieve info on the most recently completed job. Though so
far this is only used in the source node to know if the
migration has been completed. But because we don't support
completed jobs we will deliver an error.

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
---
Changes since v1:
 - Fixed indentation on libxlDomainGetJobStats()
 - s/estimed/estimated/g
 - Bump version to 1.2.22
---
 src/libxl/libxl_driver.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
index b0b6ea7..dda14c2 100644
--- a/src/libxl/libxl_driver.c
+++ b/src/libxl/libxl_driver.c
@@ -5273,6 +5273,58 @@ libxlDomainGetJobInfo(virDomainPtr dom,
     return ret;
 }
 
+static int
+libxlDomainGetJobStats(virDomainPtr dom,
+                       int *type,
+                       virTypedParameterPtr *params,
+                       int *nparams,
+                       unsigned int flags)
+{
+    libxlDomainObjPrivatePtr priv;
+    virDomainObjPtr vm;
+    virDomainJobInfoPtr jobInfo;
+    int ret = -1;
+    int maxparams = 0;
+
+    /* VIR_DOMAIN_JOB_STATS_COMPLETED not supported yet */
+    virCheckFlags(0, -1);
+
+    if (!(vm = libxlDomObjFromDomain(dom)))
+        goto cleanup;
+
+    if (virDomainGetJobStatsEnsureACL(dom->conn, vm->def) < 0)
+        goto cleanup;
+
+    priv = vm->privateData;
+    jobInfo = priv->job.current;
+    if (!priv->job.active) {
+        *type = VIR_DOMAIN_JOB_NONE;
+        *params = NULL;
+        *nparams = 0;
+        ret = 0;
+        goto cleanup;
+    }
+
+    /* In libxl we don't have an estimated completion time
+     * thus we always set to unbounded and update time
+     * for the active job. */
+    if (libxlDomainJobUpdateTime(&priv->job) < 0)
+        goto cleanup;
+
+    if (virTypedParamsAddULLong(params, nparams, &maxparams,
+                                VIR_DOMAIN_JOB_TIME_ELAPSED,
+                                jobInfo->timeElapsed) < 0)
+        goto cleanup;
+
+    *type = jobInfo->type;
+    ret = 0;
+
+ cleanup:
+    if (vm)
+        virObjectUnlock(vm);
+    return ret;
+}
+
 #undef LIBXL_SET_MEMSTAT
 
 #define LIBXL_RECORD_UINT(error, key, value, ...) \
@@ -6134,6 +6186,7 @@ static virHypervisorDriver libxlHypervisorDriver = {
     .nodeGetFreeMemory = libxlNodeGetFreeMemory, /* 0.9.0 */
     .nodeGetCellsFreeMemory = libxlNodeGetCellsFreeMemory, /* 1.1.1 */
     .domainGetJobInfo = libxlDomainGetJobInfo, /* 1.2.22 */
+    .domainGetJobStats = libxlDomainGetJobStats, /* 1.2.22 */
     .domainBlockStats = libxlDomainBlockStats, /* 1.2.22 */
     .domainBlockStatsFlags = libxlDomainBlockStatsFlags, /* 1.2.22 */
     .domainInterfaceStats = libxlDomainInterfaceStats, /* 1.2.22 */
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2015-11-10 15:34 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-11-10 15:34 [PATCH v2 0/8] libxl: domain statistics support Joao Martins
2015-11-10 15:34 ` [PATCH v2 1/8] libxl: implement virDomainGetCPUStats Joao Martins
2015-11-10 15:34 ` [PATCH v2 2/8] libxl: implement virDomainMemorystats Joao Martins
2015-11-10 15:34 ` [PATCH v2 3/8] libxl: implement virDomainInterfaceStats Joao Martins
2015-11-10 15:34 ` [PATCH v2 4/8] util: add virDiskNameParse to handle disk and partition idx Joao Martins
2015-11-10 15:34 ` [PATCH v2 5/8] libxl: implement virDomainBlockStats Joao Martins
2015-11-10 15:34 ` [PATCH v2 6/8] libxl: implement virConnectGetAllDomainStats Joao Martins
2015-11-10 15:34 ` [PATCH v2 7/8] libxl: implement virDomainGetJobInfo Joao Martins
2015-11-10 15:34 ` [PATCH v2 8/8] libxl: implement virDomainGetJobStats Joao Martins

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.