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

[Xen-devel] [RFC PATCH 4/7] libxl: add snapshot APIs



Add snapshot related APIs for xl, including:
create disk snapshots, revert disk snapshots.

Together with existing memory save/restore APIs, xl can create domain
snapshot and revert from a domain snapshot.

Limitations:

About disk snapshot create, there are many cases:
- qdisk, internal, should calls qmp command to do the work.
- qdisk, external, should calls qmp command to do the work, qemu
  will replace disk backend file after creating external snapshot.
- nonqdisk, internal, should call 'qemu-img snapshot' to do the work.
- nonqdisk, external, should call 'qemu-img create' to create a new file
  with the original disk file as backing file. And libxl should replace
  domain disk from original disk to the new file.

Problem is: to the last case, during domain snapshot, between domain suspend
and resume, how to replace the disk backend file from libxl? Especially if
disk file format is changed (original disk backend file is 'raw', new file
is 'qcow2') ?

Considering this, currently the API only support qdisk, non-qdisk cases
are not included.

About disk snapshot revert:

Reverting from external disk snapshot is actually starting domain from a
specified backing file, since backing file should be kept read-only, that
will involve block copy operation. Currently this case is not supported.

Only support reverting from internal disk snapshot.

Signed-off-by: Chunyan Liu <cyliu@xxxxxxxx>
---
 tools/libxl/Makefile         |   1 +
 tools/libxl/libxl.h          |   6 ++
 tools/libxl/libxl_internal.h |   6 ++
 tools/libxl/libxl_snapshot.c | 219 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 232 insertions(+)
 create mode 100644 tools/libxl/libxl_snapshot.c

diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
index 9036076..0917326 100644
--- a/tools/libxl/Makefile
+++ b/tools/libxl/Makefile
@@ -105,6 +105,7 @@ LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o 
libxl_pci.o \
                        libxl_qmp.o libxl_event.o libxl_fork.o \
                        libxl_dom_suspend.o $(LIBXL_OBJS-y)
 LIBXL_OBJS += libxl_genid.o
+LIBXL_OBJS += libxl_snapshot.o
 LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o
 
 LIBXL_TESTS += timedereg
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index 5f9047c..d60f139 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -1729,6 +1729,12 @@ int libxl_psr_cat_get_l3_info(libxl_ctx *ctx, 
libxl_psr_cat_info **info,
 void libxl_psr_cat_info_list_free(libxl_psr_cat_info *list, int nr);
 #endif
 
+/* Domain snapshot related APIs */
+int libxl_disk_snapshot_create(libxl_ctx *ctx, uint32_t domid,
+                               libxl_disk_snapshot *snapshot, int nb);
+int libxl_disk_snapshot_revert(libxl_ctx *ctx, uint32_t domid,
+                               libxl_disk_snapshot *snapshot, int nb);
+
 /* misc */
 
 /* Each of these sets or clears the flag according to whether the
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index c3dec85..f24e0af 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -1749,6 +1749,12 @@ _hidden void libxl__qmp_cleanup(libxl__gc *gc, uint32_t 
domid);
 _hidden int libxl__qmp_initializations(libxl__gc *gc, uint32_t domid,
                                        const libxl_domain_config 
*guest_config);
 
+typedef struct libxl__ao_snapshot libxl__ao_snapshot;
+struct libxl__ao_snapshot {
+    libxl__ao *ao;
+    libxl__ev_child child;
+};
+
 /* on failure, logs */
 int libxl__sendmsg_fds(libxl__gc *gc, int carrier,
                        const void *data, size_t datalen,
diff --git a/tools/libxl/libxl_snapshot.c b/tools/libxl/libxl_snapshot.c
new file mode 100644
index 0000000..34d36ef
--- /dev/null
+++ b/tools/libxl/libxl_snapshot.c
@@ -0,0 +1,219 @@
+/*
+ * libxl_snapshot.c: code domain snapshot related APIs
+ *
+ * Copyright (C) 2015 SUSE LINUX Products GmbH, Nuernberg, Germany.
+ * Author Chunyan Liu <cyliu@xxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+
+#include "libxl_osdeps.h" /* must come before any other headers */
+
+#include "libxl_internal.h"
+
+/* Replace domain disk to external path after taking external disk
+ * snapshot, since original disk becomes backing file. It will need
+ * to update xenstore information as well as domain config.
+ */
+static int libxl__update_disk_configuration(libxl__gc *gc, uint32_t domid,
+                                            libxl_disk_snapshot snapshot)
+{
+    char *backend_path, *path, *value;
+    const char *format;
+    int i, rc;
+    libxl__device device;
+    libxl_domain_config d_config;
+    libxl__domain_userdata_lock *lock = NULL;
+
+    /* update domain config */
+    libxl_domain_config_init(&d_config);
+    lock = libxl__lock_domain_userdata(gc, domid);
+    if (!lock) {
+        rc = ERROR_LOCK_FAIL;
+        goto out;
+    }
+
+    rc = libxl__get_domain_configuration(gc, domid, &d_config);
+    if (rc) goto out;
+
+    for (i = 0; i < d_config.num_disks; i++) {
+        if (!strcmp(d_config.disks[i].vdev, snapshot.disk.vdev)) {
+            free(d_config.disks[i].pdev_path);
+            d_config.disks[i].pdev_path =
+                strdup(snapshot.u.external.external_path);
+            d_config.disks[i].format =
+                snapshot.u.external.external_format;
+        }
+    }
+
+    rc = libxl__set_domain_configuration(gc, domid, &d_config);
+    if (rc) goto out;
+
+    /* update xenstore */
+    rc = libxl__device_from_disk(gc, domid, &snapshot.disk, &device);
+    if (rc) {
+        LOG(ERROR, "Update xenstore disk information failed");
+        goto out;
+    }
+    backend_path = libxl__device_backend_path(gc, &device);
+
+    path = GCSPRINTF("%s/params", backend_path);
+    format =
+        libxl_disk_format_to_string(snapshot.u.external.external_format);
+    value = GCSPRINTF("%s:%s", format,
+                      snapshot.u.external.external_path);
+
+    rc = libxl__xs_write_checked(gc, XBT_NULL, path, value);
+    if (rc) {
+        LOG(ERROR, "Update xenstore disk information failed");
+        goto out;
+    }
+
+    path = GCSPRINTF("%s/format", backend_path);
+    rc = libxl__xs_write_checked(gc, XBT_NULL, path, format);
+    if (rc) {
+        LOG(ERROR, "Update xenstore disk information failed");
+        goto out;
+    }
+
+    rc = 0;
+
+out:
+    if (lock) libxl__unlock_domain_userdata(lock);
+    libxl_domain_config_dispose(&d_config);
+    return rc;
+}
+
+int libxl_disk_snapshot_create(libxl_ctx *ctx, uint32_t domid,
+                               libxl_disk_snapshot *snapshot, int nb)
+{
+    int i;
+    GC_INIT(ctx);
+    int rc;
+
+    rc = libxl__qmp_disk_snapshot_transaction(gc, domid, snapshot, nb);
+    if (rc) {
+        LOG(ERROR, "domain disk snapshot create fail\n");
+        goto out;
+    }
+
+    for (i = 0; i < nb; i++) {
+        if (snapshot[i].type == LIBXL_DISK_SNAPSHOT_TYPE_EXTERNAL) {
+            /* Domain disk points to the new disk, original disk becomes
+            * backing file. Now, we need to update xenstore information
+            * and domain config.
+            */
+            rc = libxl__update_disk_configuration(gc, domid, snapshot[i]);
+            if (rc) goto out;
+        }
+    }
+
+out:
+    GC_FREE;
+    return rc;
+}
+
+static void snapshot_finished(libxl__egc *egc, libxl__ev_child *child,
+                              pid_t pid, int status)
+{
+    libxl__ao_snapshot *ao_snapshot = CONTAINER_OF(child, libxl__ao_snapshot, 
child);
+    STATE_AO_GC(ao_snapshot->ao);
+    int rc = 0;
+
+    if (status) {
+        LOG(ERROR, "cmd failed");
+        libxl_report_child_exitstatus(CTX, XTL_ERROR, "cmd",
+                                      pid, status);
+        rc = ERROR_FAIL;
+        goto out;
+    } else {
+        LOG(DEBUG, "cmd completed");
+    }
+
+out:
+    libxl__ao_complete(egc, ao, rc);
+    return;
+}
+
+static int internal_disk_snapshot_helper(libxl_ctx *ctx, uint32_t domid,
+                                         libxl_disk_snapshot *snapshot,
+                                         libxl__disk_snapshot_op op)
+{
+    AO_CREATE(ctx, domid, NULL);
+    libxl__ao_snapshot *ao_snapshot;
+    const char **args;
+    int i, rc;
+
+    GCNEW(ao_snapshot);
+    ao_snapshot->ao = ao;
+
+    switch (snapshot->disk.format) {
+    case LIBXL_DISK_FORMAT_QCOW2:
+        i = 0;
+        args = libxl__zalloc(gc, 6 * sizeof(*args));
+        args[i++] = LIBEXEC_BIN "/" "qemu-img";
+        args[i++] = "snapshot";
+        switch (op) {
+        case LIBXL__DISK_SNAPSHOT_OP_REVERT:
+            args[i++] = "-a";
+            break;
+        case LIBXL__DISK_SNAPSHOT_OP_CREATE:
+            args[i++] = "-c";
+            break;
+        case LIBXL__DISK_SNAPSHOT_OP_DELETE:
+            args[i++] = "-d";
+            break;
+        default:
+            LOG(ERROR, "disk snapshot helper: unsupported operation");
+            rc = -1;
+            goto out;
+        }
+        args[i++] = GCSPRINTF("%s", snapshot->name);
+        args[i++] = GCSPRINTF("%s", snapshot->disk.pdev_path);
+        break;
+    default:
+        LOG(ERROR, "disk snapshot helper: unsupported disk format");
+        rc = -1;
+        goto out;
+    }
+
+    pid_t pid = libxl__ev_child_fork(gc, &ao_snapshot->child, 
snapshot_finished);
+    if (pid == -1) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    if (!pid) {
+        /* child */
+        libxl__exec(gc, -1, -1, -1, args[0], (char **)args, NULL);
+        exit(-1);
+    }
+
+    /* parent */
+    return AO_INPROGRESS;
+
+out:
+    return rc;
+}
+
+int libxl_disk_snapshot_revert(libxl_ctx *ctx, uint32_t domid,
+                               libxl_disk_snapshot *snapshot, int nb)
+{
+    int i;
+    int rc = 0;
+
+    for ( i = 0; i < nb; i++ ) {
+        assert(snapshot[i].type == LIBXL_DISK_SNAPSHOT_TYPE_INTERNAL);
+        rc = internal_disk_snapshot_helper(ctx, domid, &snapshot[i],
+                                           LIBXL__DISK_SNAPSHOT_OP_REVERT);
+    }
+    return rc;
+}
-- 
2.1.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®.