[libvirt] [patch 2/4] checkpoint functionality

Matt McCowan matt.mccowan at metoceanengineers.com
Mon Mar 9 14:30:36 UTC 2009


Patches for the drivers and header
Here's hoping jolly Evolution doesn't play silly buggers with wrapping.
If so I'll be resending with claws :(

> Matt McCowan
> 
> --
> Libvir-list mailing list
> Libvir-list at redhat.com
> https://www.redhat.com/mailman/listinfo/libvir-list

--- libvirt.orig/src/driver.h	2009-03-03 18:14:28.000000000 +0900
+++ libvirt-0.6.1.1/src/driver.h	2009-03-09 17:28:54.000000000 +0900
@@ -141,6 +141,12 @@
 typedef int
         (*virDrvDomainSave)		(virDomainPtr domain,
                                          const char *to);
+
+typedef int
+        (*virDrvDomainCheckpoint)       (virDomainPtr domain,
+                                         const char *to,
+                                         const char *script);
+
 typedef int
         (*virDrvDomainRestore)		(virConnectPtr conn,
                                          const char *from);
@@ -372,6 +378,7 @@
     virDrvDomainSetMemory		domainSetMemory;
     virDrvDomainGetInfo		domainGetInfo;
     virDrvDomainSave		domainSave;
+     virDrvDomainCheckpoint	domainCheckpoint;
     virDrvDomainRestore		domainRestore;
     virDrvDomainCoreDump		domainCoreDump;
     virDrvDomainSetVcpus		domainSetVcpus;
diff -ur libvirt.orig/src/lxc_driver.c libvirt-0.6.1.1/src/lxc_driver.c
--- libvirt.orig/src/lxc_driver.c	2009-03-09 12:42:43.000000000 +0900
+++ libvirt-0.6.1.1/src/lxc_driver.c	2009-03-05 11:44:42.000000000 +0900
@@ -1435,6 +1423,7 @@
     NULL, /* domainSetMemory */
     lxcDomainGetInfo, /* domainGetInfo */
     NULL, /* domainSave */
+    NULL, /* domainCheckpoint */
     NULL, /* domainRestore */
     NULL, /* domainCoreDump */
     NULL, /* domainSetVcpus */
diff -ur libvirt.orig/src/openvz_driver.c
libvirt-0.6.1.1/src/openvz_driver.c
--- libvirt.orig/src/openvz_driver.c	2009-03-03 18:14:28.000000000 +0900
+++ libvirt-0.6.1.1/src/openvz_driver.c	2009-03-05 11:44:42.000000000
+0900
@@ -1293,6 +1293,7 @@
     NULL, /* domainSetMemory */
     openvzDomainGetInfo, /* domainGetInfo */
     NULL, /* domainSave */
+    NULL, /* domainCheckpoint */
     NULL, /* domainRestore */
     NULL, /* domainCoreDump */
     openvzDomainSetVcpus, /* domainSetVcpus */
diff -ur libvirt.orig/src/proxy_internal.c
libvirt-0.6.1.1/src/proxy_internal.c
--- libvirt.orig/src/proxy_internal.c	2009-01-29 21:10:32.000000000
+0900
+++ libvirt-0.6.1.1/src/proxy_internal.c	2009-03-05 14:39:58.000000000
+0900
@@ -67,6 +67,7 @@
     NULL, /* domainSetMemory */
     xenProxyDomainGetInfo, /* domainGetInfo */
     NULL, /* domainSave */
+    NULL, /* domainCheckpoint */
     NULL, /* domainRestore */
     NULL, /* domainCoreDump */
     NULL, /* domainSetVcpus */
diff -ur libvirt.orig/src/test.c libvirt-0.6.1.1/src/test.c
--- libvirt.orig/src/test.c	2009-03-03 18:14:28.000000000 +0900
+++ libvirt-0.6.1.1/src/test.c	2009-03-05 11:44:42.000000000 +0900
@@ -3495,6 +3495,7 @@
     testSetMemory, /* domainSetMemory */
     testGetDomainInfo, /* domainGetInfo */
     testDomainSave, /* domainSave */
+    NULL, /* domainCheckpoint */
     testDomainRestore, /* domainRestore */
     testDomainCoreDump, /* domainCoreDump */
     testSetVcpus, /* domainSetVcpus */
diff -ur libvirt.orig/src/uml_driver.c libvirt-0.6.1.1/src/uml_driver.c
--- libvirt.orig/src/uml_driver.c	2009-03-03 18:14:28.000000000 +0900
+++ libvirt-0.6.1.1/src/uml_driver.c	2009-03-05 11:44:42.000000000 +0900
@@ -1848,6 +1848,7 @@
     umlDomainSetMemory, /* domainSetMemory */
     umlDomainGetInfo, /* domainGetInfo */
     NULL, /* domainSave */
+    NULL, /* domainCheckpoint */
     NULL, /* domainRestore */
     NULL, /* domainCoreDump */
     NULL, /* domainSetVcpus */
diff -ur libvirt.orig/src/qemu_driver.c
libvirt-0.6.1.1/src/qemu_driver.c
--- libvirt.orig/src/qemu_driver.c	2009-03-04 10:24:50.000000000 +0900
+++ libvirt-0.6.1.1/src/qemu_driver.c	2009-03-06 16:30:39.000000000
+0900
@@ -2718,6 +2718,156 @@
     return ret;
 }
 
+static int qemudDomainCheckpoint(virDomainPtr dom,
+                                 const char *path,
+                                 const char *script) {
+    struct qemud_driver *driver = dom->conn->privateData;
+    virDomainObjPtr vm;
+    char *command = NULL;
+    char *info = NULL;
+    int fd = -1;
+    char *safe_path = NULL;
+    char *xml = NULL;
+    struct qemud_save_header header;
+    int ret = -1;
+    virDomainEventPtr event = NULL;
+    const char *argv[3];
+
+    memset(&header, 0, sizeof(header));
+    memcpy(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic));
+    header.version = QEMUD_SAVE_VERSION;
+
+    qemuDriverLock(driver);
+    vm = virDomainFindByID(&driver->domains, dom->id);
+
+    if (!vm) {
+        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
+                         _("no domain with matching id %d"), dom->id);
+        goto cleanup;
+    }
+
+    if (!virDomainIsActive(vm)) {
+        qemudReportError(dom->conn, dom, NULL,
VIR_ERR_OPERATION_FAILED,
+                         "%s", _("domain is not running"));
+        goto cleanup;
+    }
+
+    /* Pause */
+    if (vm->state == VIR_DOMAIN_RUNNING) {
+        header.was_running = 1;
+        if (qemudMonitorCommand(vm, "stop", &info) < 0) {
+            qemudReportError(dom->conn, dom, NULL,
VIR_ERR_OPERATION_FAILED,
+                             "%s", _("suspend operation failed"));
+            goto cleanup;
+        }
+        vm->state = VIR_DOMAIN_PAUSED;
+        qemudDebug("Reply %s", info);
+        VIR_FREE(info);
+    }
+
+    /* Get XML for the domain */
+    xml = virDomainDefFormat(dom->conn, vm->def,
VIR_DOMAIN_XML_SECURE);
+    if (!xml) {
+        qemudReportError(dom->conn, dom, NULL,
VIR_ERR_OPERATION_FAILED,
+                         "%s", _("failed to get domain xml"));
+        goto cleanup;
+    }
+    header.xml_len = strlen(xml) + 1;
+
+    /* Write header to file, followed by XML */
+    if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR)) <
0) {
+        qemudReportError(dom->conn, dom, NULL,
VIR_ERR_OPERATION_FAILED,
+                         _("failed to create '%s'"), path);
+        goto cleanup;
+    }
+
+    if (safewrite(fd, &header, sizeof(header)) != sizeof(header)) {
+        qemudReportError(dom->conn, dom, NULL,
VIR_ERR_OPERATION_FAILED,
+                         "%s", _("failed to write save header"));
+        goto cleanup;
+    }
+
+    if (safewrite(fd, xml, header.xml_len) != header.xml_len) {
+        qemudReportError(dom->conn, dom, NULL,
VIR_ERR_OPERATION_FAILED,
+                         "%s", _("failed to write xml"));
+        goto cleanup;
+    }
+
+    if (close(fd) < 0) {
+        virReportSystemError(dom->conn, errno,
+                             _("unable to save file %s"),
+                             path);
+        goto cleanup;
+    }
+    fd = -1;
+
+    /* Migrate to file */
+    safe_path = qemudEscapeShellArg(path);
+    if (!safe_path) {
+        virReportOOMError(dom->conn);
+        goto cleanup;
+    }
+    if (virAsprintf(&command, "migrate \"exec:"
+                  "dd of='%s' oflag=append conv=notrunc 2>/dev/null"
+                  "\"", safe_path) == -1) {
+        virReportOOMError(dom->conn);
+        command = NULL;
+        goto cleanup;
+    }
+
+    if (qemudMonitorCommand(vm, command, &info) < 0) {
+        qemudReportError(dom->conn, dom, NULL,
VIR_ERR_OPERATION_FAILED,
+                         "%s", _("migrate operation failed"));
+        goto cleanup;
+    }
+
+    DEBUG ("migrate reply: %s", info);
+
+    /* If the command isn't supported then qemu prints:
+     * unknown command: migrate" */
+    if (strstr(info, "unknown command:")) {
+        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
+                          "%s",
+                          _("'migrate' not supported by this qemu"));
+        goto cleanup;
+    }
+
+    /* Call optional script */
+    if (script != NULL ) {
+        argv[0] = qemudEscapeShellArg(script);
+        argv[1] = virDomainGetName(dom);
+        argv[2] = NULL;
+        if (virRun(dom->conn, argv, NULL) < 0)
+            qemudReportError(dom->conn, dom, NULL,
VIR_ERR_OPERATION_FAILED,
+                             _("Failed to run '%s'"), script);
+    }
+
+    if (qemudMonitorCommand(vm, "cont", &info) < 0) {
+        qemudReportError(dom->conn, dom, NULL,
VIR_ERR_OPERATION_FAILED,
+                         "%s", _("resume operation failed"));
+        goto cleanup;
+    }
+    vm->state = VIR_DOMAIN_RUNNING;
+    DEBUG ("cont reply: %s", info);
+
+    ret = 0;
+
+cleanup:
+    if (fd != -1)
+        close(fd);
+    VIR_FREE(xml);
+    VIR_FREE(safe_path);
+    VIR_FREE(command);
+    VIR_FREE(info);
+    if (ret != 0)
+        unlink(path);
+    if (vm)
+        virDomainObjUnlock(vm);
+    if (event)
+        qemuDomainEventQueue(driver, event);
+    qemuDriverUnlock(driver);
+    return ret;
+}
 
 static int qemudDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus) {
     struct qemud_driver *driver = dom->conn->privateData;
@@ -4931,6 +5081,7 @@
     qemudDomainSetMemory, /* domainSetMemory */
     qemudDomainGetInfo, /* domainGetInfo */
     qemudDomainSave, /* domainSave */
+    qemudDomainCheckpoint, /* domainCheckpoint */
     qemudDomainRestore, /* domainRestore */
     NULL, /* domainCoreDump */
     qemudDomainSetVcpus, /* domainSetVcpus */





More information about the libvir-list mailing list