[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH v1 09/10] libxl: introduce libxl_retrieve_domain_configuration



Introduce a new public API to return domain configuration. This returned
configuration can be used to rebuild a domain.

Note that this configuration doesn't equal to the current state of the
domain. What it does is to use JSON version configuration as template
and pull in relevant information from xenstore.

With this approach we can preserve what user has provided in the
original configuration as well as valuable information from xenstore.

Signed-off-by: Wei Liu <wei.liu2@xxxxxxxxxx>
---
 tools/libxl/libxl.c |  200 +++++++++++++++++++++++++++++++++++++++++++++++++++
 tools/libxl/libxl.h |   16 +++++
 2 files changed, 216 insertions(+)

diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 49d7ef6..cd5914c 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -6034,6 +6034,206 @@ void libxl_mac_copy(libxl_ctx *ctx, libxl_mac *dst, 
libxl_mac *src)
     for (i = 0; i < 6; i++)
         (*dst)[i] = (*src)[i];
 }
+
+int libxl_retrieve_domain_configuration(libxl_ctx *ctx, uint32_t domid,
+                                        libxl_domain_config *d_config)
+{
+    GC_INIT(ctx);
+    int rc;
+    int fd_lock = -1;
+
+    if (!libxl_domid_valid_guest(domid)) {
+        rc = ERROR_INVAL;
+        goto out;
+    }
+
+    rc = libxl__lock_domain_configuration(gc, domid, &fd_lock);
+    if (rc) {
+        LOGE(ERROR, "fail to lock domain configuration for domain %d", domid);
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    rc = libxl__get_domain_configuration(gc, domid, d_config);
+    if (rc) {
+        LOGE(ERROR, "fail to get domain configuration for domain %d", domid);
+        rc = ERROR_FAIL;
+        goto out_unlock;
+    }
+
+    /* Domain name */
+    {
+        char *domname;
+        domname = libxl_domid_to_name(ctx, domid);
+        if (!domname) {
+            LOGE(ERROR, "fail to get domain name for domain %d", domid);
+            goto out_unlock;
+        }
+        free(d_config->c_info.name);
+        d_config->c_info.name = domname; /* steals allocation */
+    }
+
+    /* Domain UUID */
+    {
+        libxl_dominfo info;
+        rc = libxl_domain_info(ctx, &info, domid);
+        if (rc) {
+            LOGE(ERROR, "fail to get domain info for domain %d", domid);
+            goto out_unlock;
+        }
+        libxl_uuid_copy(ctx, &d_config->c_info.uuid, &info.uuid);
+    }
+
+    /* Memory limits:
+     *
+     * Currently there're three memory limits:
+     *  1. "target" in xenstore (originally memory= in config file)
+     *  2. "static-max" in xenstore (originally maxmem= in config file)
+     *  3. "max_memkb" in hypervisor
+     *
+     * The third one is not visible and currently managed by
+     * toolstack. In order to rebuild a domain we only need to have
+     * "target" and "static-max".
+     */
+    {
+        uint32_t memory;
+
+        /* "target" */
+        rc = libxl_get_memory_target(ctx, domid, &memory);
+        if (rc) {
+            LOGE(ERROR, "fail to get memory target for domain %d", domid);
+            goto out_unlock;
+        }
+        /* If the domain is HVM domain, target memory in xenstore is
+         * smaller than what user has asked for. The difference is
+         * video_memkb, so add it back. Otherwise domain rebuild will
+         * fail.
+         */
+        if (d_config->b_info.type == LIBXL_DOMAIN_TYPE_HVM)
+            d_config->b_info.target_memkb =
+                memory + d_config->b_info.video_memkb;
+
+        /* "static-max" */
+        rc = libxl_get_memory_static_max(ctx, domid, &memory);
+        if (rc) {
+            LOGE(ERROR, "fail to get memory static-max for domain %d", domid);
+            goto out_unlock;
+        }
+        d_config->b_info.max_memkb = memory;
+    }
+
+    /* Devices: disk, nic, vtpm, pcidev */
+
+    /* The MERGE macro implements following logic:
+     * 0. retrieve JSON
+     * 1. retrieve list of device from xenstore
+     * 2. use xenstore entries as primary reference and compare JSON
+     *    entries with them.
+     *    a. if a device is present in xenstore and in JSON, merge the
+     *       two views.
+     *    b. if a device is not present in xenstore but in JSON, delete
+     *       it from the result.
+     *    c. it's impossible to have an entry present in xenstore but
+     *       not in JSON, because we maintain an invariant that every
+     *       entry in xenstore must have a corresponding entry in JSON.
+     * 3. "merge" operates on "src" and "dst". "src" points to the
+     *    entry retrieved from xenstore while "dst" points to the entry
+     *    retrieve from JSON.
+     */
+#define MERGE(type, ptr, cnt, compare, merge)                           \
+    do {                                                                \
+        libxl_device_##type *p = NULL;                                  \
+        int i, j, num;                                                  \
+                                                                        \
+        p = libxl_device_##type##_list(CTX, domid, &num);               \
+        if (p == NULL) {                                                \
+            LOGE(DEBUG,                                                 \
+                 "no %s from xenstore for domain %d",                   \
+                 #type, domid);                                         \
+        }                                                               \
+                                                                        \
+        for (i = 0; i < d_config->cnt; i++) {                           \
+            libxl_device_##type *q = &d_config->ptr[i];                 \
+            for (j = 0; j < num; j++) {                                 \
+                if (compare(&p[j], q))                                  \
+                    break;                                              \
+            }                                                           \
+                                                                        \
+            if (j < num) {         /* found in xenstore */              \
+                libxl_device_##type *dst, *src;                         \
+                dst = q;                                                \
+                src = &p[j];                                            \
+                merge;                                                  \
+            } else {                /* not found in xenstore */         \
+                LOGE(WARN, "Device present in JSON but not in xenstore, 
ignored"); \
+                                                                        \
+                libxl_device_##type##_dispose(q);                       \
+                                                                        \
+                for (j = i; j < d_config->cnt - 1; j++)                 \
+                    memcpy(&d_config->ptr[j], &d_config->ptr[j+1],      \
+                           sizeof(libxl_device_##type));                \
+                                                                        \
+                d_config->ptr =                                         \
+                    libxl__realloc(NOGC, d_config->ptr,                 \
+                                   sizeof(libxl_device_##type) *        \
+                                   (d_config->cnt - 1));                \
+                                                                        \
+                /* rewind counters */                                   \
+                d_config->cnt--;                                        \
+                i--;                                                    \
+            }                                                           \
+        }                                                               \
+                                                                        \
+        for (i = 0; i < num; i++)                                       \
+            libxl_device_##type##_dispose(&p[i]);                       \
+        free(p);                                                        \
+    } while (0);
+
+    MERGE(nic, nics, num_nics, COMPARE_DEVID, {
+            libxl__update_config_nic(gc, dst, src);
+        });
+
+    MERGE(vtpm, vtpms, num_vtpms, COMPARE_DEVID, {
+            libxl__update_config_vtpm(gc, dst, src);
+        });
+
+    MERGE(pci, pcidevs, num_pcidevs, COMPARE_PCI, {});
+
+    /* Take care of removable device. We maintain invariant in the
+     * insert / remove operation so that:
+     * 1. if xenstore is "empty" while JSON is not, the result
+     *    is "empty"
+     * 2. if xenstore has a different media than JSON, use the
+     *    one in JSON
+     * 3. if xenstore and JSON have the same media, well, you
+     *    know the answer :-)
+     *
+     * Currently there is only one removable device -- CDROM.
+     * Look for libxl_cdrom_insert for reference.
+     */
+    MERGE(disk, disks, num_disks, COMPARE_DISK, {
+            if (src->removable) {
+                if (!src->pdev_path || *src->pdev_path == '\0') {
+                    /* 1, use "empty" */
+                    free(dst->pdev_path);
+                    dst->pdev_path = libxl__strdup(NOGC, "");
+                    dst->format = LIBXL_DISK_FORMAT_EMPTY;
+                } else {
+                    /* 2 and 3, use JSON, no need to touch anything */
+                    ;
+                }
+            }
+        });
+
+#undef MERGE
+
+out_unlock:
+    libxl__unlock_domain_configuration(gc, domid, &fd_lock);
+out:
+    GC_FREE;
+    return rc;
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index f9eb0f1..982f339 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -358,6 +358,14 @@ typedef struct libxl__ctx libxl_ctx;
 #endif
 #endif
 
+/* LIBXL_HAVE_RETRIEVE_DOMAIN_CONFIGURATION
+ *
+ * If this is defined we have libxl_retrieve_domain_configuration which
+ * returns the current configuration of a domain, which can be used to
+ * rebuild a domain.
+ */
+#define LIBXL_HAVE_RETRIEVE_DOMAIN_CONFIGURATION 1
+
 /* LIBXL_HAVE_GET_MEMORY_STATIC_MAX
  *
  * If this is defined we have an API called libxl_get_memory_static_max
@@ -834,6 +842,14 @@ int static inline libxl_domain_create_restore_0x040200(
 void libxl_domain_config_init(libxl_domain_config *d_config);
 void libxl_domain_config_dispose(libxl_domain_config *d_config);
 
+/*
+ * Retrieve domain configuration and filled it in d_config. The
+ * returned configuration can be used to rebuild a domain. It only
+ * works with DomU.
+ */
+int libxl_retrieve_domain_configuration(libxl_ctx *ctx, uint32_t domid,
+                                        libxl_domain_config *d_config);
+
 int libxl_domain_suspend(libxl_ctx *ctx, uint32_t domid, int fd,
                          int flags, /* LIBXL_SUSPEND_* */
                          const libxl_asyncop_how *ao_how)
-- 
1.7.10.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.