[libvirt] [PATCH] virConnectListAllDomains (version 3, still no Xen)

Richard W.M. Jones rjones at redhat.com
Wed Sep 3 15:58:17 UTC 2008


This is a third version of the virConnectListAllDomains patch.  The
API is now slightly different from previous proposals.  We only allow
filtering on All/Active/Inactive, and not by a long list of
fine-grained states.  The reason is twofold: (1) a simpler
implementation and (2) doubtful that anyone would actually use the
fine-grained filtering feature.

The new API is shown below.

I have tested this out with mlvirsh and virt-top and of course in the
remote case there is a substantial saving in terms of round-trip
times, although it's hard to precisely measure what the difference is
when I've got only a couple of guests running.

There is still no Xen-specific implementation, but note that in the
remote case you get some of the benefit anyway.

Rich.

----------------------------------------------------------------------
/**
 * virConnectListAllDomains:
 * @conn: pointer to the hypervisor connection
 * @domains: pointer to returned array of domain pointers (must not be NULL)
 * @infos: pointer to returned array of virDomainInfo structures (may be NULL)
 * @stateflags: state of domains of interest
 * @flags: other flags (always 0)
 *
 * This call returns the list of all domains, active or inactive,
 * and their virDomainInfo structures.
 *
 * This call is usually more efficient than using the old method
 * of calling virConnectListDomains and virConnectListDefinedDomains
 * and then loading each domain and its info.  This call is supported
 * for all hypervisor types.  (If the backend driver doesn't support it
 * directly, then the call is emulated for you).
 *
 * @stateflags allows only the domains of interest to be
 * returned.  Callers must pass one of:
 * VIR_DOMAIN_LIST_ACTIVE to return running domains,
 * VIR_DOMAIN_LIST_INACTIVE to return defined but not running domains,
 * VIR_DOMAIN_LIST_ALL to return all domains,
 * 0 to return no domains.
 *
 * @flags may be used in the future.  Always pass 0 for this parameter.
 *
 * If there is no error then @domains will be updated to point to an
 * array of virDomainPtr.
 *
 * If there is no error and @infos is not NULL, then @infos will be
 * updated to point to an array of virDomainInfo structures, with
 * the same length as the array of domains.
 *
 * Returns the number of domains in the @domains array, or -1 in
 * case of error.
 *
 * If there was no error then the caller must free each domain
 * with virDomainFree, free the array of @domains pointers,
 * and if necessary free the array of @infos structures.
 */
int
virConnectListAllDomains(virConnectPtr conn,
                         virDomainPtr **domains,
                         virDomainInfo **infos,
                         unsigned long stateflags,
                         unsigned long flags);
----------------------------------------------------------------------

-- 
Richard Jones, Emerging Technologies, Red Hat  http://et.redhat.com/~rjones
Read my OCaml programming blog: http://camltastic.blogspot.com/
Fedora now supports 64 OCaml packages (the OPEN alternative to F#)
http://cocan.org/getting_started_with_ocaml_on_red_hat_and_fedora
-------------- next part --------------
Index: include/libvirt/libvirt.h.in
===================================================================
RCS file: /data/cvs/libvirt/include/libvirt/libvirt.h.in,v
retrieving revision 1.53
diff -u -r1.53 libvirt.h.in
--- include/libvirt/libvirt.h.in	27 Aug 2008 20:05:58 -0000	1.53
+++ include/libvirt/libvirt.h.in	3 Sep 2008 15:43:56 -0000
@@ -75,6 +75,11 @@
      VIR_DOMAIN_CRASHED = 6  /* the domain is crashed */
 } virDomainState;
 
+/* For virConnectListAllDomains. */
+#define VIR_DOMAIN_LIST_ACTIVE 1
+#define VIR_DOMAIN_LIST_INACTIVE 2
+#define VIR_DOMAIN_LIST_ALL (VIR_DOMAIN_LIST_ACTIVE | VIR_DOMAIN_LIST_INACTIVE)
+
 /**
  * virDomainInfoPtr:
  *
@@ -417,6 +422,15 @@
 unsigned long long      virNodeGetFreeMemory    (virConnectPtr conn);
 
 /*
+ * New-style list-all-domains call.
+ */
+int                     virConnectListAllDomains(virConnectPtr conn,
+                                                 virDomainPtr **domains,
+                                                 virDomainInfo **infos,
+                                                 unsigned long stateflags,
+                                                 unsigned long flags);
+
+/*
  * Gather list of running domains
  */
 int                     virConnectListDomains   (virConnectPtr conn,
Index: qemud/remote.c
===================================================================
RCS file: /data/cvs/libvirt/qemud/remote.c,v
retrieving revision 1.39
diff -u -r1.39 remote.c
--- qemud/remote.c	27 Aug 2008 20:05:59 -0000	1.39
+++ qemud/remote.c	3 Sep 2008 15:43:59 -0000
@@ -1904,6 +1904,71 @@
 }
 
 static int
+remoteDispatchListAllDomains (struct qemud_server *server ATTRIBUTE_UNUSED,
+                              struct qemud_client *client,
+                              remote_message_header *req,
+                              remote_list_all_domains_args *args,
+                              remote_list_all_domains_ret *ret)
+{
+    virDomainPtr *domains;
+    virDomainInfo *infos = NULL;
+    int i, nr;
+    int retcode = -2;
+
+    CHECK_CONN(client);
+
+    nr = virConnectListAllDomains (client->conn, &domains,
+                                   args->want_infos ? &infos : NULL,
+                                   args->stateflags,
+                                   args->flags);
+    if (nr == -1) return -1;
+
+    if (nr > REMOTE_DOMAIN_LIST_MAX || nr > REMOTE_DOMAIN_INFO_LIST_MAX) {
+        remoteDispatchSendError (client, req, VIR_ERR_RPC,
+                                 _("too many domains to return"));
+        goto done;
+    }
+
+    if (VIR_ALLOC_N (ret->doms.doms_val, nr) == -1) {
+        remoteDispatchSendError(client, req, VIR_ERR_NO_MEMORY, NULL);
+        goto done;
+    }
+    ret->doms.doms_len = nr;
+
+    if (args->want_infos) {
+        if (VIR_ALLOC_N (ret->infos.infos_val, nr) == -1) {
+            remoteDispatchSendError(client, req, VIR_ERR_NO_MEMORY, NULL);
+            VIR_FREE (ret->doms.doms_val);
+            goto done;
+        }
+        ret->infos.infos_len = nr;
+    } else {
+        ret->infos.infos_val = NULL;
+        ret->infos.infos_len = 0;
+    }
+
+    for (i = 0; i < nr; ++i) {
+        make_nonnull_domain (&ret->doms.doms_val[i], domains[i]);
+        if (args->want_infos) {
+            ret->infos.infos_val[i].state = infos[i].state;
+            ret->infos.infos_val[i].max_mem = infos[i].maxMem;
+            ret->infos.infos_val[i].memory = infos[i].memory;
+            ret->infos.infos_val[i].nr_virt_cpu = infos[i].nrVirtCpu;
+            ret->infos.infos_val[i].cpu_time = infos[i].cpuTime;
+        }
+    }
+    retcode = 0;
+
+done:
+    for (i = 0; i < nr; ++i)
+        virDomainFree (domains[i]);
+    free (domains);
+    free (infos);
+
+    return retcode;
+}
+
+static int
 remoteDispatchListDomains (struct qemud_server *server ATTRIBUTE_UNUSED,
                            struct qemud_client *client,
                            remote_message_header *req,
Index: qemud/remote_protocol.x
===================================================================
RCS file: /data/cvs/libvirt/qemud/remote_protocol.x,v
retrieving revision 1.17
diff -u -r1.17 remote_protocol.x
--- qemud/remote_protocol.x	27 Aug 2008 20:05:59 -0000	1.17
+++ qemud/remote_protocol.x	3 Sep 2008 15:43:59 -0000
@@ -64,6 +64,12 @@
 /* Upper limit on lists of domain names. */
 const REMOTE_DOMAIN_NAME_LIST_MAX = 1024;
 
+/* Upper limit on lists of domain structures. */
+const REMOTE_DOMAIN_LIST_MAX = 1024;
+
+/* Upper limit on lists of virDomainInfo structures. */
+const REMOTE_DOMAIN_INFO_LIST_MAX = 1024;
+
 /* Upper limit on cpumap (bytes) passed to virDomainPinVcpu. */
 const REMOTE_CPUMAP_MAX = 256;
 
@@ -205,6 +211,15 @@
     remote_sched_param_value value;
 };
 
+/* virDomainInfo on the wire */
+struct remote_domain_info {
+    unsigned char state;
+    unsigned hyper max_mem;
+    unsigned hyper memory;
+    unsigned short nr_virt_cpu;
+    unsigned hyper cpu_time;
+};
+
 /*----- Calls. -----*/
 
 /* For each call we may have a 'remote_CALL_args' and 'remote_CALL_ret'
@@ -358,6 +373,17 @@
     opaque buffer<REMOTE_DOMAIN_MEMORY_PEEK_BUFFER_MAX>;
 };
 
+struct remote_list_all_domains_args {
+    int want_infos;
+    unsigned hyper stateflags;
+    unsigned hyper flags;
+};
+
+struct remote_list_all_domains_ret {
+    remote_nonnull_domain doms<REMOTE_DOMAIN_LIST_MAX>;
+    remote_domain_info infos<REMOTE_DOMAIN_INFO_LIST_MAX>;
+};
+
 struct remote_list_domains_args {
     int maxids;
 };
@@ -455,6 +481,9 @@
 };
 
 struct remote_domain_get_info_ret {
+    /* remote_domain_info info; - but we have to maintain ABI compatibility
+     * so we cannot use the structure directly.
+     */
     unsigned char state;
     unsigned hyper max_mem;
     unsigned hyper memory;
@@ -1085,7 +1114,9 @@
     REMOTE_PROC_NODE_GET_FREE_MEMORY = 102,
 
     REMOTE_PROC_DOMAIN_BLOCK_PEEK = 103,
-    REMOTE_PROC_DOMAIN_MEMORY_PEEK = 104
+    REMOTE_PROC_DOMAIN_MEMORY_PEEK = 104,
+
+    REMOTE_PROC_LIST_ALL_DOMAINS = 105
 };
 
 /* Custom RPC structure. */
Index: src/driver.h
===================================================================
RCS file: /data/cvs/libvirt/src/driver.h,v
retrieving revision 1.53
diff -u -r1.53 driver.h
--- src/driver.h	27 Aug 2008 20:05:59 -0000	1.53
+++ src/driver.h	3 Sep 2008 15:44:00 -0000
@@ -97,6 +97,12 @@
 typedef char *
         (*virDrvGetCapabilities) (virConnectPtr conn);
 typedef int
+        (*virDrvListAllDomains)		(virConnectPtr conn,
+                                         virDomainPtr **domains,
+                                         virDomainInfo **infos,
+                                         unsigned long stateflags,
+                                         unsigned long flags);
+typedef int
         (*virDrvListDomains)		(virConnectPtr conn,
                                          int *ids,
                                          int maxids);
@@ -307,6 +313,7 @@
     virDrvGetMaxVcpus		getMaxVcpus;
     virDrvNodeGetInfo		nodeGetInfo;
     virDrvGetCapabilities		getCapabilities;
+    virDrvListAllDomains	listAllDomains;
     virDrvListDomains		listDomains;
     virDrvNumOfDomains		numOfDomains;
     virDrvDomainCreateLinux		domainCreateLinux;
Index: src/internal.h
===================================================================
RCS file: /data/cvs/libvirt/src/internal.h,v
retrieving revision 1.78
diff -u -r1.78 internal.h
--- src/internal.h	27 Aug 2008 20:05:59 -0000	1.78
+++ src/internal.h	3 Sep 2008 15:44:00 -0000
@@ -362,6 +362,8 @@
 int __virDomainMigratePerform (virDomainPtr domain, const char *cookie, int cookielen, const char *uri, unsigned long flags, const char *dname, unsigned long bandwidth);
 virDomainPtr __virDomainMigrateFinish (virConnectPtr dconn, const char *dname, const char *cookie, int cookielen, const char *uri, unsigned long flags);
 
+int virEmulateListAllDomains (virConnectPtr conn, virDomainPtr **domains, virDomainInfo **infos, unsigned long stateflags, unsigned long flags);
+
 typedef struct _virStringList virStringList;
 
 struct _virStringList {
Index: src/libvirt.c
===================================================================
RCS file: /data/cvs/libvirt/src/libvirt.c,v
retrieving revision 1.155
diff -u -r1.155 libvirt.c
--- src/libvirt.c	2 Sep 2008 15:00:09 -0000	1.155
+++ src/libvirt.c	3 Sep 2008 15:44:03 -0000
@@ -1145,6 +1145,216 @@
 }
 
 /**
+ * virConnectListAllDomains:
+ * @conn: pointer to the hypervisor connection
+ * @domains: pointer to returned array of domain pointers (must not be NULL)
+ * @infos: pointer to returned array of virDomainInfo structures (may be NULL)
+ * @stateflags: state of domains of interest
+ * @flags: other flags (always 0)
+ *
+ * This call returns the list of all domains, active or inactive,
+ * and their virDomainInfo structures.
+ *
+ * This call is usually more efficient than using the old method
+ * of calling virConnectListDomains and virConnectListDefinedDomains
+ * and then loading each domain and its info.  This call is supported
+ * for all hypervisor types.  (If the backend driver doesn't support it
+ * directly, then the call is emulated for you).
+ *
+ * @stateflags allows only the domains of interest to be
+ * returned.  Callers must pass one of:
+ * VIR_DOMAIN_LIST_ACTIVE to return running domains,
+ * VIR_DOMAIN_LIST_INACTIVE to return defined but not running domains,
+ * VIR_DOMAIN_LIST_ALL to return all domains,
+ * 0 to return no domains.
+ *
+ * @flags may be used in the future.  Always pass 0 for this parameter.
+ *
+ * If there is no error then @domains will be updated to point to an
+ * array of virDomainPtr.
+ *
+ * If there is no error and @infos is not NULL, then @infos will be
+ * updated to point to an array of virDomainInfo structures, with
+ * the same length as the array of domains.
+ *
+ * Returns the number of domains in the @domains array, or -1 in
+ * case of error.
+ *
+ * If there was no error then the caller must free each domain
+ * with virDomainFree, free the array of @domains pointers,
+ * and if necessary free the array of @infos structures.
+ */
+int
+virConnectListAllDomains(virConnectPtr conn,
+                         virDomainPtr **domains,
+                         virDomainInfo **infos,
+                         unsigned long stateflags,
+                         unsigned long flags)
+{
+    DEBUG("conn=%p, domains=%p, infos=%p, stateflags=%lu, flags=%lu",
+          conn, domains, infos, stateflags, flags);
+
+    if (!VIR_IS_CONNECT (conn)) {
+        virLibConnError (NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        return -1;
+    }
+
+    if (flags != 0) {
+        virLibConnError (conn, VIR_ERR_INVALID_ARG,
+                         _("flags must always be 0"));
+        return -1;
+    }
+
+    /* Nothing can match an empty flag set.  Error?  Possibly, but
+     * avoid having to special-case the calling code.
+     */
+    if (stateflags == 0) {
+        *domains = NULL;
+        if (infos)
+            *infos = NULL;
+        return 0;
+    }
+
+    if (domains == NULL) {
+        virLibConnError (conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        return -1;
+    }
+
+    /* Supported by this driver? */
+    if (conn->driver->listAllDomains)
+        return conn->driver->listAllDomains (conn, domains, infos,
+                                             stateflags, flags);
+    else
+        return virEmulateListAllDomains (conn, domains, infos,
+                                         stateflags, flags);
+}
+
+int
+virEmulateListAllDomains (virConnectPtr conn,
+                          virDomainPtr **domains,
+                          virDomainInfo **infos,
+                          unsigned long stateflags,
+                          unsigned long flags ATTRIBUTE_UNUSED)
+{
+    int n_active, n_inactive;
+    int i, j, ret = -1;
+    int *ids = NULL;
+    char **names = NULL;
+    virDomainPtr tdom = NULL;
+    virDomainInfo tinfo;
+
+    n_active =
+        (stateflags & VIR_DOMAIN_LIST_ACTIVE) ?
+        virConnectNumOfDomains (conn) :
+        0;
+    if (n_active == -1) return -1;
+    n_inactive =
+        (stateflags & VIR_DOMAIN_LIST_INACTIVE) ?
+        virConnectNumOfDefinedDomains (conn) :
+        0;
+    if (n_inactive == -1) return -1;
+
+    if (VIR_ALLOC_N (*domains, n_active + n_inactive) == -1) {
+        virLibConnError (conn, VIR_ERR_NO_MEMORY, __FUNCTION__);
+        return -1;
+    }
+    if (infos) {
+        if (VIR_ALLOC_N (*infos, n_active + n_inactive) == -1) {
+            VIR_FREE (*domains);
+            virLibConnError (conn, VIR_ERR_NO_MEMORY, __FUNCTION__);
+            return -1;
+        }
+    }
+
+    /* 'j' is the next free position in the return array. */
+    j = 0;
+
+    if (n_active) {
+        if (VIR_ALLOC_N (ids, n_active) == -1) {
+            virLibConnError (conn, VIR_ERR_NO_MEMORY, __FUNCTION__);
+            goto done;
+        }
+
+        n_active = virConnectListDomains (conn, ids, n_active);
+        if (n_active == -1) goto done;
+
+        for (i = 0; i < n_active; ++i) {
+            /* Note: domains are allowed to disappear unexpectedly. */
+            tdom = virDomainLookupByID (conn, ids[i]);
+            if (!tdom) continue;
+
+            if (infos) {
+                if (virDomainGetInfo (tdom, &tinfo) == -1) {
+                    virDomainFree (tdom);
+                    continue;
+                }
+            }
+
+            (*domains)[j] = tdom;
+            tdom = NULL;
+            if (infos)
+                (*infos)[j] = tinfo;
+            j++;
+        }
+    }
+
+    if (n_inactive) {
+        if (VIR_ALLOC_N (names, n_inactive) == -1) {
+            virLibConnError (conn, VIR_ERR_NO_MEMORY, __FUNCTION__);
+            goto done;
+        }
+
+        n_inactive = virConnectListDefinedDomains (conn, names, n_inactive);
+        if (n_inactive == -1) goto done;
+
+        for (i = 0; i < n_inactive; ++i) {
+            /* Note: domains are allowed to disappear unexpectedly. */
+            tdom = virDomainLookupByName (conn, names[i]);
+            if (!tdom) continue;
+
+            if (infos) {
+                if (virDomainGetInfo (tdom, &tinfo) == -1) {
+                    virDomainFree (tdom);
+                    continue;
+                }
+            }
+
+            (*domains)[j] = tdom;
+            tdom = NULL;
+            if (infos)
+                (*infos)[j] = tinfo;
+            j++;
+        }
+    }
+
+    /* Return the number of domains in the resulting list. */
+    ret = j;
+
+done:
+    VIR_FREE (ids);
+    VIR_FREE (names);
+
+    if (ret == -1) {
+        /* Error path: Free up any domains which we referenced, and
+         * also the domains & infos arrays.
+         */
+        for (i = 0; i < j; ++i)
+            virDomainFree ((*domains)[i]);
+
+        VIR_FREE (*domains);
+
+        if (infos)
+            VIR_FREE (*infos);
+
+        /* Free up the temporary domain. */
+        if (tdom)
+            virDomainFree (tdom);
+    }
+
+    return ret;
+}
+
+/**
  * virConnectListDomains:
  * @conn: pointer to the hypervisor connection
  * @ids: array to collect the list of IDs of active domains
Index: src/libvirt_sym.version
===================================================================
RCS file: /data/cvs/libvirt/src/libvirt_sym.version,v
retrieving revision 1.44
diff -u -r1.44 libvirt_sym.version
--- src/libvirt_sym.version	27 Aug 2008 20:05:59 -0000	1.44
+++ src/libvirt_sym.version	3 Sep 2008 15:44:03 -0000
@@ -12,6 +12,7 @@
 	virConnectGetHostname;
 	virConnectGetURI;
 	virDomainGetConnect;
+	virConnectListAllDomains;
 	virConnectListDomains;
 	virConnectNumOfDomains;
         virDomainCreate;
Index: src/lxc_driver.c
===================================================================
RCS file: /data/cvs/libvirt/src/lxc_driver.c,v
retrieving revision 1.25
diff -u -r1.25 lxc_driver.c
--- src/lxc_driver.c	27 Aug 2008 11:42:52 -0000	1.25
+++ src/lxc_driver.c	3 Sep 2008 15:44:04 -0000
@@ -1127,6 +1127,7 @@
     NULL, /* getMaxVcpus */
     NULL, /* nodeGetInfo */
     NULL, /* getCapabilities */
+    NULL, /* listAllDomains */
     lxcListDomains, /* listDomains */
     lxcNumDomains, /* numOfDomains */
     lxcDomainCreateAndStart, /* domainCreateLinux */
Index: src/openvz_driver.c
===================================================================
RCS file: /data/cvs/libvirt/src/openvz_driver.c,v
retrieving revision 1.44
diff -u -r1.44 openvz_driver.c
--- src/openvz_driver.c	27 Aug 2008 11:19:45 -0000	1.44
+++ src/openvz_driver.c	3 Sep 2008 15:44:04 -0000
@@ -930,6 +930,7 @@
     openvzGetMaxVCPUs, /* getMaxVcpus */
     openvzGetNodeInfo, /* nodeGetInfo */
     NULL, /* getCapabilities */
+    NULL, /* listAllDomains */
     openvzListDomains, /* listDomains */
     openvzNumDomains, /* numOfDomains */
     openvzDomainCreateLinux, /* domainCreateLinux */
Index: src/qemu_driver.c
===================================================================
RCS file: /data/cvs/libvirt/src/qemu_driver.c,v
retrieving revision 1.116
diff -u -r1.116 qemu_driver.c
--- src/qemu_driver.c	3 Sep 2008 15:05:31 -0000	1.116
+++ src/qemu_driver.c	3 Sep 2008 15:44:07 -0000
@@ -3922,6 +3922,7 @@
     qemudGetMaxVCPUs, /* getMaxVcpus */
     qemudGetNodeInfo, /* nodeGetInfo */
     qemudGetCapabilities, /* getCapabilities */
+    NULL, /* listAllDomains */
     qemudListDomains, /* listDomains */
     qemudNumDomains, /* numOfDomains */
     qemudDomainCreate, /* domainCreateLinux */
Index: src/remote_internal.c
===================================================================
RCS file: /data/cvs/libvirt/src/remote_internal.c,v
retrieving revision 1.83
diff -u -r1.83 remote_internal.c
--- src/remote_internal.c	29 Aug 2008 07:11:15 -0000	1.83
+++ src/remote_internal.c	3 Sep 2008 15:44:11 -0000
@@ -1339,6 +1339,83 @@
     return ret.freeMem;
 }
 
+static int
+remoteListAllDomains (virConnectPtr conn,
+                      virDomainPtr **domains,
+                      virDomainInfo **infos,
+                      unsigned long stateflags,
+                      unsigned long flags)
+{
+    int want_infos;
+    int i, nr;
+    remote_list_all_domains_args args;
+    remote_list_all_domains_ret ret;
+    GET_PRIVATE (conn, -1);
+
+    args.want_infos = want_infos = infos != NULL;
+    args.stateflags = stateflags;
+    args.flags = flags;
+
+    memset (&ret, 0, sizeof ret);
+    if (call (conn, priv, 0, REMOTE_PROC_LIST_ALL_DOMAINS,
+              (xdrproc_t) xdr_remote_list_all_domains_args, (char *) &args,
+              (xdrproc_t) xdr_remote_list_all_domains_ret, (char *) &ret) == -1)
+        return -1;
+
+    nr = ret.doms.doms_len;
+    if (want_infos) {
+        if (ret.infos.infos_len != nr) {
+            errorf (conn, VIR_ERR_RPC,
+                    _("length of domains and infos doesn't match: %d != %d"),
+                    ret.infos.infos_len, ret.doms.doms_len);
+            xdr_free ((xdrproc_t) xdr_remote_list_domains_ret, (char *) &ret);
+            return -1;
+        }
+    } else {
+        /* If I didn't ask for the infos, don't give me any! */
+        if (ret.infos.infos_len != 0) {
+            errorf (conn, VIR_ERR_RPC,
+                    _("length of infos should be zero, but is %d"),
+                    ret.infos.infos_len);
+            xdr_free ((xdrproc_t) xdr_remote_list_domains_ret, (char *) &ret);
+            return -1;
+        }
+    }
+    if (nr > REMOTE_DOMAIN_LIST_MAX || nr > REMOTE_DOMAIN_INFO_LIST_MAX) {
+        errorf (conn, VIR_ERR_RPC,
+                _("length of domains list too long: %d > %d or > %d"),
+                nr, REMOTE_DOMAIN_LIST_MAX, REMOTE_DOMAIN_INFO_LIST_MAX);
+        xdr_free ((xdrproc_t) xdr_remote_list_domains_ret, (char *) &ret);
+        return -1;
+    }
+
+    if (VIR_ALLOC_N (*domains, nr) == -1) {
+        errorf (conn, VIR_ERR_NO_MEMORY, _("out of memory"));
+        xdr_free ((xdrproc_t) xdr_remote_list_domains_ret, (char *) &ret);
+        return -1;
+    }
+    if (want_infos && VIR_ALLOC_N (*infos, nr) == -1) {
+        xdr_free ((xdrproc_t) xdr_remote_list_domains_ret, (char *) &ret);
+        VIR_FREE (*domains);
+        errorf (conn, VIR_ERR_NO_MEMORY, _("out of memory"));
+        return -1;
+    }
+
+    for (i = 0; i < nr; ++i) {
+        (*domains)[i] = get_nonnull_domain (conn, ret.doms.doms_val[i]);
+        if (want_infos) {
+            (*infos)[i].state = ret.infos.infos_val[i].state;
+            (*infos)[i].maxMem = ret.infos.infos_val[i].max_mem;
+            (*infos)[i].memory = ret.infos.infos_val[i].memory;
+            (*infos)[i].nrVirtCpu = ret.infos.infos_val[i].nr_virt_cpu;
+            (*infos)[i].cpuTime = ret.infos.infos_val[i].cpu_time;
+        }
+    }
+
+    xdr_free ((xdrproc_t) xdr_remote_list_domains_ret, (char *) &ret);
+
+    return nr;
+}
 
 static int
 remoteListDomains (virConnectPtr conn, int *ids, int maxids)
@@ -4830,6 +4907,7 @@
         .getMaxVcpus = remoteGetMaxVcpus,
         .nodeGetInfo = remoteNodeGetInfo,
     .getCapabilities = remoteGetCapabilities,
+    .listAllDomains = remoteListAllDomains,
     .listDomains = remoteListDomains,
     .numOfDomains = remoteNumOfDomains,
     .domainCreateLinux = remoteDomainCreateLinux,
Index: src/test.c
===================================================================
RCS file: /data/cvs/libvirt/src/test.c,v
retrieving revision 1.84
diff -u -r1.84 test.c
--- src/test.c	20 Aug 2008 20:48:36 -0000	1.84
+++ src/test.c	3 Sep 2008 15:44:12 -0000
@@ -1550,6 +1550,7 @@
     testGetMaxVCPUs, /* getMaxVcpus */
     testNodeGetInfo, /* nodeGetInfo */
     testGetCapabilities, /* getCapabilities */
+    NULL, /* listAllDomains */
     testListDomains, /* listDomains */
     testNumOfDomains, /* numOfDomains */
     testDomainCreateLinux, /* domainCreateLinux */
Index: src/virsh.c
===================================================================
RCS file: /data/cvs/libvirt/src/virsh.c,v
retrieving revision 1.165
diff -u -r1.165 virsh.c
--- src/virsh.c	3 Sep 2008 12:38:28 -0000	1.165
+++ src/virsh.c	3 Sep 2008 15:44:16 -0000
@@ -308,17 +308,6 @@
 static char *_vshStrdup(vshControl *ctl, const char *s, const char *filename, int line);
 #define vshStrdup(_ctl, _s)    _vshStrdup(_ctl, _s, __FILE__, __LINE__)
 
-
-static int idsorter(const void *a, const void *b) {
-  const int *ia = (const int *)a;
-  const int *ib = (const int *)b;
-
-  if (*ia > *ib)
-    return 1;
-  else if (*ia < *ib)
-    return -1;
-  return 0;
-}
 static int namesorter(const void *a, const void *b) {
   const char **sa = (const char**)a;
   const char **sb = (const char**)b;
@@ -326,7 +315,6 @@
   return strcasecmp(*sa, *sb);
 }
 
-
 /* ---------------
  * Commands
  * ---------------
@@ -559,104 +547,91 @@
 };
 
 
+struct listedDom {
+    int id;                     /* INT_MAX if inactive. */
+    const char *name;
+    const char *state_str;
+};
+
+static int
+sortListedDoms (const void *a, const void *b)
+{
+    struct listedDom *sa = (struct listedDom *) a;
+    struct listedDom *sb = (struct listedDom *) b;
+
+    if (sa->id == sb->id) {
+        return strcmp (sa->name, sb->name);
+    } else {
+        return sa->id - sb->id;
+    }
+}
+
 static int
 cmdList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
 {
     int inactive = vshCommandOptBool(cmd, "inactive");
     int all = vshCommandOptBool(cmd, "all");
-    int active = !inactive || all ? 1 : 0;
-    int *ids = NULL, maxid = 0, i;
-    char **names = NULL;
-    int maxname = 0;
-    inactive |= all;
+    virDomainPtr *domains;
+    virDomainInfo *infos;
+    int stateflags, i, nr, id;
+    struct listedDom *doms;
+
+    if (all)
+        stateflags = VIR_DOMAIN_LIST_ALL;
+    else if (inactive)
+        stateflags = VIR_DOMAIN_LIST_INACTIVE;
+    else
+        stateflags = VIR_DOMAIN_LIST_ACTIVE;
 
     if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
         return FALSE;
 
-    if (active) {
-        maxid = virConnectNumOfDomains(ctl->conn);
-        if (maxid < 0) {
-            vshError(ctl, FALSE, "%s", _("Failed to list active domains"));
-            return FALSE;
-        }
-        if (maxid) {
-            ids = vshMalloc(ctl, sizeof(int) * maxid);
+    nr = virConnectListAllDomains (ctl->conn, &domains, &infos, stateflags, 0);
+    if (nr == -1) {
+        vshError(ctl, FALSE, "%s", _("Failed to list domains"));
+        return FALSE;
+    }
 
-            if ((maxid = virConnectListDomains(ctl->conn, &ids[0], maxid)) < 0) {
-                vshError(ctl, FALSE, "%s", _("Failed to list active domains"));
-                free(ids);
-                return FALSE;
-            }
+    /* Not quite so simple: The previous version showed domains
+     * sorted by ID, followed by inactive domains sorted by name.
+     * We must emulate this by pulling out the fields we need from
+     * the domains and infos structures and then sorting it.
+     */
+    doms = vshMalloc (ctl, sizeof (struct listedDom) * nr);
+    for (i = 0; i < nr; ++i) {
+        id = virDomainGetID (domains[i]);
+        if (id == -1) id = INT_MAX;
 
-            qsort(&ids[0], maxid, sizeof(int), idsorter);
-        }
+        doms[i].id = id;
+        doms[i].name = virDomainGetName (domains[i]);
+        doms[i].state_str = N_(vshDomainStateToString (infos[i].state));
     }
-    if (inactive) {
-        maxname = virConnectNumOfDefinedDomains(ctl->conn);
-        if (maxname < 0) {
-            vshError(ctl, FALSE, "%s", _("Failed to list inactive domains"));
-            free(ids);
-            return FALSE;
-        }
-        if (maxname) {
-            names = vshMalloc(ctl, sizeof(char *) * maxname);
 
-            if ((maxname = virConnectListDefinedDomains(ctl->conn, names, maxname)) < 0) {
-                vshError(ctl, FALSE, "%s", _("Failed to list inactive domains"));
-                free(ids);
-                free(names);
-                return FALSE;
-            }
+    qsort (doms, nr, sizeof (struct listedDom), sortListedDoms);
 
-            qsort(&names[0], maxname, sizeof(char*), namesorter);
-        }
-    }
     vshPrintExtra(ctl, "%3s %-20s %s\n", _("Id"), _("Name"), _("State"));
     vshPrintExtra(ctl, "----------------------------------\n");
 
-    for (i = 0; i < maxid; i++) {
-        virDomainInfo info;
-        virDomainPtr dom = virDomainLookupByID(ctl->conn, ids[i]);
-        const char *state;
-
-        /* this kind of work with domains is not atomic operation */
-        if (!dom)
-            continue;
-
-        if (virDomainGetInfo(dom, &info) < 0)
-            state = _("no state");
+    for (i = 0; i < nr; ++i) {
+        if (doms[i].id != INT_MAX)
+            vshPrint(ctl, "%3d %-20s %s\n",
+                     doms[i].id,
+                     doms[i].name,
+                     doms[i].state_str);
         else
-            state = N_(vshDomainStateToString(info.state));
-
-        vshPrint(ctl, "%3d %-20s %s\n",
-                 virDomainGetID(dom),
-                 virDomainGetName(dom),
-                 state);
-        virDomainFree(dom);
+            vshPrint(ctl, "%3s %-20s %s\n",
+                     "-",
+                     doms[i].name,
+                     doms[i].state_str);
     }
-    for (i = 0; i < maxname; i++) {
-        virDomainInfo info;
-        virDomainPtr dom = virDomainLookupByName(ctl->conn, names[i]);
-        const char *state;
-
-        /* this kind of work with domains is not atomic operation */
-        if (!dom) {
-            free(names[i]);
-            continue;
-        }
 
-        if (virDomainGetInfo(dom, &info) < 0)
-            state = _("no state");
-        else
-            state = N_(vshDomainStateToString(info.state));
+    for (i = 0; i < nr; ++i)
+        virDomainFree (domains[i]);
+    free (domains);
+    free (infos);
 
-        vshPrint(ctl, "%3s %-20s %s\n", "-", names[i], state);
+    free (doms);
 
-        virDomainFree(dom);
-        free(names[i]);
-    }
-    free(ids);
-    free(names);
     return TRUE;
 }
 
Index: src/xen_unified.c
===================================================================
RCS file: /data/cvs/libvirt/src/xen_unified.c,v
retrieving revision 1.53
diff -u -r1.53 xen_unified.c
--- src/xen_unified.c	20 Aug 2008 20:48:36 -0000	1.53
+++ src/xen_unified.c	3 Sep 2008 15:44:17 -0000
@@ -481,6 +481,31 @@
     return NULL;
 }
 
+#if 0
+static int
+xenUnifiedListAllDomains (virConnectPtr conn,
+                          virDomainPtr **domains,
+                          virDomainInfo **infos,
+                          unsigned long stateflags,
+                          unsigned long flags)
+{
+    GET_PRIVATE(conn);
+    int ret;
+
+    if (priv->opened[XEN_UNIFIED_XEND_OFFSET]) {
+        ret = xenDaemonListAllDomains (conn, domains, infos, stateflags, flags);
+        return ret;
+    }
+
+    /* Kind of hackish that we call back out to libvirt.c.  However
+     * this doesn't cause any infinite loops because emulation uses
+     * the old-style calls.
+     */
+    ret = virEmulateListAllDomains (conn, domains, infos, stateflags, flags);
+    return ret;
+}
+#endif
+
 static int
 xenUnifiedListDomains (virConnectPtr conn, int *ids, int maxids)
 {
@@ -1318,6 +1343,9 @@
     .getMaxVcpus 			= xenUnifiedGetMaxVcpus,
     .nodeGetInfo 			= xenUnifiedNodeGetInfo,
     .getCapabilities 		= xenUnifiedGetCapabilities,
+#if 0
+    .listAllDomains 			= xenUnifiedListAllDomains,
+#endif
     .listDomains 			= xenUnifiedListDomains,
     .numOfDomains 		= xenUnifiedNumOfDomains,
     .domainCreateLinux 		= xenUnifiedDomainCreateLinux,
Index: src/xend_internal.c
===================================================================
RCS file: /data/cvs/libvirt/src/xend_internal.c,v
retrieving revision 1.211
diff -u -r1.211 xend_internal.c
--- src/xend_internal.c	28 Aug 2008 11:59:07 -0000	1.211
+++ src/xend_internal.c	3 Sep 2008 15:44:21 -0000
@@ -3434,6 +3434,33 @@
 }
 
 #ifndef PROXY
+#if 0
+/**
+ * xenDaemonListAllDomains:
+ * @conn: pointer to the hypervisor connection
+ * @domains: array of domains returned (may not be NULL)
+ * @infos: array of virDomainInfo structures returned (may be NULL)
+ * @stateflags: which domains we are interested in
+ *
+ * Collect the list of all (active/inactive) domains, and store their
+ * domain objects and optional virDomainInfo structures in @domains
+ * and @infos.
+ *
+ * Returns the number of domains found or -1 in case of error
+ */
+int
+xenDaemonListAllDomains (virConnectPtr conn,
+                         virDomainPtr **domains,
+                         virDomainInfo **infos,
+                         unsigned long stateflags,
+                         unsigned long flags ATTRIBUTE_UNUSED)
+{
+    
+
+
+}
+#endif
+
 /**
  * xenDaemonListDomains:
  * @conn: pointer to the hypervisor connection
Index: src/xend_internal.h
===================================================================
RCS file: /data/cvs/libvirt/src/xend_internal.h,v
retrieving revision 1.50
diff -u -r1.50 xend_internal.h
--- src/xend_internal.h	20 Aug 2008 20:48:36 -0000	1.50
+++ src/xend_internal.h	3 Sep 2008 15:44:21 -0000
@@ -179,4 +179,8 @@
 
 int xenDaemonDomainBlockPeek (virDomainPtr domain, const char *path, unsigned long long offset, size_t size, void *buffer);
 
+#if 0
+int xenDaemonListAllDomains (virConnectPtr conn, virDomainPtr **domains, virDomainInfo **infos, unsigned long stateflags, unsigned long flags);
+#endif
+
 #endif /* __XEND_INTERNAL_H_ */


More information about the libvir-list mailing list