[libvirt] [PATCH] virConnectListAllDomains

Richard W.M. Jones rjones at redhat.com
Fri Aug 29 12:38:57 UTC 2008


As observed in this thread:

  https://www.redhat.com/archives/libvir-list/2008-July/msg00215.html

several tools need to grab the complete list of domains frequently
(eg. virt-manager and virt-top) and the way they do it currently is
very inefficient, both in terms of the number of round-trips in the
remote case (4 + 2*N calls), and the fact that we could implement
drivers better if we could get all domains in a single operation.

Therefore this patch adds the virConnectListAllDomains call:

  int virConnectListAllDomains (virConnectPtr conn,
                                virDomainPtr **domains,
                                virDomainInfo **infos,
                                int stateflags);

This call gets domains and virDomainInfo structures.  The reasons for
getting the info structures as well are that we get them anyway as a
side-effect of filtering on state, and virsh, virt-top and
virt-manager all get the info structures at the same time as getting
the domains.

As in Dan's proposal above, you can filter on state, with three
special values (VIR_DOMAIN_LIST_ACTIVE, VIR_DOMAIN_LIST_INACTIVE and
VIR_DOMAIN_LIST_ALL) which do what you think.

virConnectListAllDomains is always available.  If the driver doesn't
implement it directly, then we emulate it in src/libvirt.c.  This
ensures that virt-manager etc can start to use this call straightaway.

There is no direct implementation for Xen or QEMU yet.  (If the
general patch is accepted, then I'll implement at least for QEMU).
However there is already a benefit to applying this patch because it
optimizes the remote case from 4 + 2*N calls down to 1.

There is no Python binding yet.

Rich.

-- 
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	29 Aug 2008 12:29:24 -0000
@@ -75,6 +75,24 @@
      VIR_DOMAIN_CRASHED = 6  /* the domain is crashed */
 } virDomainState;
 
+/* For virConnectListAllDomains. */
+#define VIR_DOMAIN_LIST_NOSTATE (1 << VIR_DOMAIN_NOSTATE)
+#define VIR_DOMAIN_LIST_RUNNING (1 << VIR_DOMAIN_RUNNING)
+#define VIR_DOMAIN_LIST_BLOCKED (1 << VIR_DOMAIN_BLOCKED)
+#define VIR_DOMAIN_LIST_PAUSED (1 << VIR_DOMAIN_PAUSED)
+#define VIR_DOMAIN_LIST_SHUTDOWN (1 << VIR_DOMAIN_SHUTDOWN)
+#define VIR_DOMAIN_LIST_SHUTOFF (1 << VIR_DOMAIN_SHUTOFF)
+#define VIR_DOMAIN_LIST_CRASHED (1 << VIR_DOMAIN_CRASHED)
+
+#define VIR_DOMAIN_LIST_ACTIVE (VIR_DOMAIN_LIST_NOSTATE |       \
+                                VIR_DOMAIN_LIST_RUNNING |       \
+                                VIR_DOMAIN_LIST_BLOCKED |       \
+                                VIR_DOMAIN_LIST_PAUSED |        \
+                                VIR_DOMAIN_LIST_SHUTDOWN |      \
+                                VIR_DOMAIN_LIST_CRASHED)
+#define VIR_DOMAIN_LIST_INACTIVE VIR_DOMAIN_LIST_SHUTOFF
+#define VIR_DOMAIN_LIST_ALL (VIR_DOMAIN_LIST_ACTIVE | VIR_DOMAIN_LIST_INACTIVE)
+
 /**
  * virDomainInfoPtr:
  *
@@ -417,6 +435,14 @@
 unsigned long long      virNodeGetFreeMemory    (virConnectPtr conn);
 
 /*
+ * New-style list-all-domains call.
+ */
+int                     virConnectListAllDomains(virConnectPtr conn,
+                                                 virDomainPtr **domains,
+                                                 virDomainInfo **infos,
+                                                 int stateflags);
+
+/*
  * 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	29 Aug 2008 12:29:27 -0000
@@ -1904,6 +1904,62 @@
 }
 
 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;
+    int i, nr;
+    int retcode = -2;
+
+    CHECK_CONN(client);
+
+    nr = virConnectListAllDomains (client->conn, &domains, &infos,
+                                   args->stateflags);
+    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;
+    }
+    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->doms.doms_len = nr;
+    ret->infos.infos_len = nr;
+
+    for (i = 0; i < nr; ++i) {
+        make_nonnull_domain (&ret->doms.doms_val[i], domains[i]);
+        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.c
===================================================================
RCS file: /data/cvs/libvirt/qemud/remote_protocol.c,v
retrieving revision 1.17
diff -u -r1.17 remote_protocol.c
--- qemud/remote_protocol.c	27 Aug 2008 20:05:59 -0000	1.17
+++ qemud/remote_protocol.c	29 Aug 2008 12:29:28 -0000
@@ -219,6 +219,23 @@
 }
 
 bool_t
+xdr_remote_domain_info (XDR *xdrs, remote_domain_info *objp)
+{
+
+         if (!xdr_u_char (xdrs, &objp->state))
+                 return FALSE;
+         if (!xdr_u_quad_t (xdrs, &objp->max_mem))
+                 return FALSE;
+         if (!xdr_u_quad_t (xdrs, &objp->memory))
+                 return FALSE;
+         if (!xdr_u_short (xdrs, &objp->nr_virt_cpu))
+                 return FALSE;
+         if (!xdr_u_quad_t (xdrs, &objp->cpu_time))
+                 return FALSE;
+        return TRUE;
+}
+
+bool_t
 xdr_remote_open_args (XDR *xdrs, remote_open_args *objp)
 {
 
@@ -588,6 +605,30 @@
 }
 
 bool_t
+xdr_remote_list_all_domains_args (XDR *xdrs, remote_list_all_domains_args *objp)
+{
+
+         if (!xdr_int (xdrs, &objp->stateflags))
+                 return FALSE;
+        return TRUE;
+}
+
+bool_t
+xdr_remote_list_all_domains_ret (XDR *xdrs, remote_list_all_domains_ret *objp)
+{
+        char **objp_cpp0 = (char **) (void *) &objp->doms.doms_val;
+        char **objp_cpp1 = (char **) (void *) &objp->infos.infos_val;
+
+         if (!xdr_array (xdrs, objp_cpp0, (u_int *) &objp->doms.doms_len, REMOTE_DOMAIN_LIST_MAX,
+                sizeof (remote_nonnull_domain), (xdrproc_t) xdr_remote_nonnull_domain))
+                 return FALSE;
+         if (!xdr_array (xdrs, objp_cpp1, (u_int *) &objp->infos.infos_len, REMOTE_DOMAIN_INFO_LIST_MAX,
+                sizeof (remote_domain_info), (xdrproc_t) xdr_remote_domain_info))
+                 return FALSE;
+        return TRUE;
+}
+
+bool_t
 xdr_remote_list_domains_args (XDR *xdrs, remote_list_domains_args *objp)
 {
 
Index: qemud/remote_protocol.h
===================================================================
RCS file: /data/cvs/libvirt/qemud/remote_protocol.h,v
retrieving revision 1.17
diff -u -r1.17 remote_protocol.h
--- qemud/remote_protocol.h	27 Aug 2008 20:05:59 -0000	1.17
+++ qemud/remote_protocol.h	29 Aug 2008 12:29:29 -0000
@@ -23,6 +23,8 @@
 typedef remote_nonnull_string *remote_string;
 #define REMOTE_DOMAIN_ID_LIST_MAX 16384
 #define REMOTE_DOMAIN_NAME_LIST_MAX 1024
+#define REMOTE_DOMAIN_LIST_MAX 1024
+#define REMOTE_DOMAIN_INFO_LIST_MAX 1024
 #define REMOTE_CPUMAP_MAX 256
 #define REMOTE_VCPUINFO_MAX 2048
 #define REMOTE_CPUMAPS_MAX 16384
@@ -122,6 +124,15 @@
 };
 typedef struct remote_sched_param remote_sched_param;
 
+struct remote_domain_info {
+        u_char state;
+        u_quad_t max_mem;
+        u_quad_t memory;
+        u_short nr_virt_cpu;
+        u_quad_t cpu_time;
+};
+typedef struct remote_domain_info remote_domain_info;
+
 struct remote_open_args {
         remote_string name;
         int flags;
@@ -299,6 +310,23 @@
 };
 typedef struct remote_domain_memory_peek_ret remote_domain_memory_peek_ret;
 
+struct remote_list_all_domains_args {
+        int stateflags;
+};
+typedef struct remote_list_all_domains_args remote_list_all_domains_args;
+
+struct remote_list_all_domains_ret {
+        struct {
+                u_int doms_len;
+                remote_nonnull_domain *doms_val;
+        } doms;
+        struct {
+                u_int infos_len;
+                remote_domain_info *infos_val;
+        } infos;
+};
+typedef struct remote_list_all_domains_ret remote_list_all_domains_ret;
+
 struct remote_list_domains_args {
         int maxids;
 };
@@ -1188,6 +1216,7 @@
         REMOTE_PROC_NODE_GET_FREE_MEMORY = 102,
         REMOTE_PROC_DOMAIN_BLOCK_PEEK = 103,
         REMOTE_PROC_DOMAIN_MEMORY_PEEK = 104,
+        REMOTE_PROC_LIST_ALL_DOMAINS = 105,
 };
 typedef enum remote_procedure remote_procedure;
 
@@ -1234,6 +1263,7 @@
 extern  bool_t xdr_remote_vcpu_info (XDR *, remote_vcpu_info*);
 extern  bool_t xdr_remote_sched_param_value (XDR *, remote_sched_param_value*);
 extern  bool_t xdr_remote_sched_param (XDR *, remote_sched_param*);
+extern  bool_t xdr_remote_domain_info (XDR *, remote_domain_info*);
 extern  bool_t xdr_remote_open_args (XDR *, remote_open_args*);
 extern  bool_t xdr_remote_supports_feature_args (XDR *, remote_supports_feature_args*);
 extern  bool_t xdr_remote_supports_feature_ret (XDR *, remote_supports_feature_ret*);
@@ -1260,6 +1290,8 @@
 extern  bool_t xdr_remote_domain_block_peek_ret (XDR *, remote_domain_block_peek_ret*);
 extern  bool_t xdr_remote_domain_memory_peek_args (XDR *, remote_domain_memory_peek_args*);
 extern  bool_t xdr_remote_domain_memory_peek_ret (XDR *, remote_domain_memory_peek_ret*);
+extern  bool_t xdr_remote_list_all_domains_args (XDR *, remote_list_all_domains_args*);
+extern  bool_t xdr_remote_list_all_domains_ret (XDR *, remote_list_all_domains_ret*);
 extern  bool_t xdr_remote_list_domains_args (XDR *, remote_list_domains_args*);
 extern  bool_t xdr_remote_list_domains_ret (XDR *, remote_list_domains_ret*);
 extern  bool_t xdr_remote_num_of_domains_ret (XDR *, remote_num_of_domains_ret*);
@@ -1415,6 +1447,7 @@
 extern bool_t xdr_remote_vcpu_info ();
 extern bool_t xdr_remote_sched_param_value ();
 extern bool_t xdr_remote_sched_param ();
+extern bool_t xdr_remote_domain_info ();
 extern bool_t xdr_remote_open_args ();
 extern bool_t xdr_remote_supports_feature_args ();
 extern bool_t xdr_remote_supports_feature_ret ();
@@ -1441,6 +1474,8 @@
 extern bool_t xdr_remote_domain_block_peek_ret ();
 extern bool_t xdr_remote_domain_memory_peek_args ();
 extern bool_t xdr_remote_domain_memory_peek_ret ();
+extern bool_t xdr_remote_list_all_domains_args ();
+extern bool_t xdr_remote_list_all_domains_ret ();
 extern bool_t xdr_remote_list_domains_args ();
 extern bool_t xdr_remote_list_domains_ret ();
 extern bool_t xdr_remote_num_of_domains_ret ();
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	29 Aug 2008 12:29:30 -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,15 @@
     opaque buffer<REMOTE_DOMAIN_MEMORY_PEEK_BUFFER_MAX>;
 };
 
+struct remote_list_all_domains_args {
+    int stateflags;
+};
+
+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 +479,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 +1112,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	29 Aug 2008 12:29:30 -0000
@@ -97,6 +97,11 @@
 typedef char *
         (*virDrvGetCapabilities) (virConnectPtr conn);
 typedef int
+        (*virDrvListAllDomains)		(virConnectPtr conn,
+                                         virDomainPtr **domains,
+                                         virDomainInfo **infos,
+                                         int stateflags);
+typedef int
         (*virDrvListDomains)		(virConnectPtr conn,
                                          int *ids,
                                          int maxids);
@@ -307,6 +312,7 @@
     virDrvGetMaxVcpus		getMaxVcpus;
     virDrvNodeGetInfo		nodeGetInfo;
     virDrvGetCapabilities		getCapabilities;
+    virDrvListAllDomains	listAllDomains;
     virDrvListDomains		listDomains;
     virDrvNumOfDomains		numOfDomains;
     virDrvDomainCreateLinux		domainCreateLinux;
Index: src/libvirt.c
===================================================================
RCS file: /data/cvs/libvirt/src/libvirt.c,v
retrieving revision 1.154
diff -u -r1.154 libvirt.c
--- src/libvirt.c	27 Aug 2008 20:05:59 -0000	1.154
+++ src/libvirt.c	29 Aug 2008 12:29:34 -0000
@@ -1145,6 +1145,180 @@
 }
 
 /**
+ * virConnectListAllDomains:
+ * @conn: pointer to the hypervisor connection
+ * @domains: pointer to returned array of domain pointers
+ * @infos: pointer to returned array of virDomainInfo structures
+ * @stateflags: state of domains of interest
+ *
+ * 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.  Common values are:
+ * 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.
+ * And VIR_DOMAIN_LIST_NOSTATE (etc) to return domains in particular
+ * states.  You may logically 'or' together several flags.
+ *
+ * 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 free the array of @infos structures.
+ */
+int
+virConnectListAllDomains(virConnectPtr conn,
+                         virDomainPtr **domains,
+                         virDomainInfo **infos,
+                         int stateflags)
+{
+    DEBUG("conn=%p, domains=%p, stateflags=%d", conn, domains, stateflags); 
+
+    if (!VIR_IS_CONNECT (conn)) {
+        virLibConnError (NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        return -1;
+    }
+
+    /* Nothing can match an empty flag set.  Error?  Possibly. */
+    if (stateflags == 0) {
+        *domains = NULL;
+        *infos = NULL;
+        return 0;
+    }
+
+    if (domains == NULL || infos == 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);
+    else {
+        /* Not supported, so emulate it. */
+        int n_active, n_inactive;
+        int i, j, ret = -1;
+        int *ids = NULL;
+        char **names = NULL;
+        virDomainPtr tdom = NULL;
+
+        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;
+
+        /* This over-allocates the return arrays, but that doesn't
+         * matter.
+         */
+        if (VIR_ALLOC_N (*domains, n_active + n_inactive) == -1) {
+            virLibConnError (conn, VIR_ERR_NO_MEMORY, __FUNCTION__);
+            return -1;
+        }
+        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 (virDomainGetInfo (tdom, &((*infos)[j])) == -1) {
+                    virDomainFree (tdom);
+                    continue;
+                }
+
+                if ((*infos)[j].state & stateflags) {
+                    (*domains)[j++] = tdom;
+                    tdom = NULL;
+                } else
+                    virDomainFree (tdom);
+            }
+        }
+
+        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 (virDomainGetInfo (tdom, &((*infos)[j])) == -1) {
+                    virDomainFree (tdom);
+                    continue;
+                }
+
+                /* By the logic above, if we are here at all then the
+                 * caller must have requested inactive domains, so
+                 * unconditionally add it to the list.  Don't need to
+                 * check the state flag.
+                 */
+                (*domains)[j++] = tdom;
+                tdom = NULL;
+            }
+        }
+
+        /* 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);
+            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	29 Aug 2008 12:29:34 -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	29 Aug 2008 12:29:35 -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	29 Aug 2008 12:29:35 -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.113
diff -u -r1.113 qemu_driver.c
--- src/qemu_driver.c	29 Aug 2008 07:11:15 -0000	1.113
+++ src/qemu_driver.c	29 Aug 2008 12:29:38 -0000
@@ -3872,6 +3872,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	29 Aug 2008 12:29:41 -0000
@@ -1339,6 +1339,66 @@
     return ret.freeMem;
 }
 
+static int
+remoteListAllDomains (virConnectPtr conn,
+                      virDomainPtr **domains,
+                      virDomainInfo **infos,
+                      int stateflags)
+{
+    int i, nr;
+    remote_list_all_domains_args args;
+    remote_list_all_domains_ret ret;
+    GET_PRIVATE (conn, -1);
+
+    args.stateflags = stateflags;
+
+    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 (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;
+    }
+    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 (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]);
+        (*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 +4890,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	29 Aug 2008 12:29:42 -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.163
diff -u -r1.163 virsh.c
--- src/virsh.c	27 Aug 2008 20:05:59 -0000	1.163
+++ src/virsh.c	29 Aug 2008 12:29:47 -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,93 @@
 };
 
 
+struct listedDom {
+    int id;                     /* INT_MAX if inactive. */
+    char *name;                 /* strdup'd domain 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 sb->id - sa->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);
+    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 = vshStrdup (ctl, virDomainGetName (domains[i]));
+        doms[i].state_str = N_(vshDomainStateToString (infos[i].state));
+
+        virDomainFree (domains[i]);
     }
-    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;
-            }
+    free (domains);
+    free (infos);
+
+    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, "%3s %-20s %s\n",
+                     "-",
+                     doms[i].name,
+                     doms[i].state_str);
 
-        vshPrint(ctl, "%3d %-20s %s\n",
-                 virDomainGetID(dom),
-                 virDomainGetName(dom),
-                 state);
-        virDomainFree(dom);
+        free (doms[i].name);
     }
-    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));
 
-        vshPrint(ctl, "%3s %-20s %s\n", "-", names[i], state);
+    free (doms);
 
-        virDomainFree(dom);
-        free(names[i]);
-    }
-    free(ids);
-    free(names);
     return TRUE;
 }
 


More information about the libvir-list mailing list