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

[libvirt] [Patch] enable --checkpoint option in 'virsh save'



Folks.
I'm working on a scenario where I would like to provide my backup subsystems with a clean disk and ram state of any given VM, without necessitating shutting down the a VM.
Xen's 'xm save' function with the '-c' (checkpoint) argument made sense in that I could checkpoint save the VM, take a snapshot of the LV containing the domain and its 'save' dump then resume the domain. Unfortunately out-of-the-box the Xen implementation did not pause the domain after the checkpoint, but resumed it automatically. Fastforward to using kvm ...
Qemu/kvm with it's 'migrate' command by default left the domain paused after creating a state dump - just what I was looking for. A look at the libvirt code revealed that 'virsh save' carried out a migrate, then shut the domain down. So I have tried implementing a --checkpoint option into the save function using the --live option to the 'virsh migrate' function as a bit of a template.
I'm a sysadmin, not a coder, so please forgive any oversights and all the other coding rules that may be broken. As mentioned before I did try to simply copy how the migrate --live option is used throughout.

Patch (against 0.6.0) attached. I have also filed a feature request under bugzilla. If the additional feature is seen as warranted, please let me know what I can do to help implement it if the patch is not the way to go about it.

Thankyou very much for Libvirt

Regards
Matt McCowan
--- ./include/libvirt/libvirt.h.in	2009-01-20 22:48:27.000000000 +0900
+++ ../libvirt-0.6.0.1/./include/libvirt/libvirt.h.in	2009-02-11 14:34:38.000000000 +0900
@@ -464,8 +464,14 @@
 int                     virDomainResume         (virDomainPtr domain);
 
+/* Domain save flags. */
+typedef enum {
+  VIR_SAVE_CHECKPOINT                  = 1, /* checkpoint save */
+} virDomainSaveFlags;
+
 /*
  * Domain save/restore
  */
 int                     virDomainSave           (virDomainPtr domain,
+                                                 unsigned long flags,
                                                  const char *to);
 int                     virDomainRestore        (virConnectPtr conn,
--- ./src/qemu_driver.c	2009-01-31 18:04:18.000000000 +0900
+++ ../libvirt-0.6.0.1/./src/qemu_driver.c	2009-02-11 13:39:30.000000000 +0900
@@ -2357,4 +2357,5 @@
 
 static int qemudDomainSave(virDomainPtr dom,
+                           unsigned long flags ATTRIBUTE_UNUSED,
                            const char *path) {
     struct qemud_driver *driver = dom->conn->privateData;
@@ -2470,13 +2471,15 @@
     }
 
-    /* Shut it down */
-    qemudShutdownVMDaemon(dom->conn, driver, vm);
-    event = virDomainEventNewFromObj(vm,
+    if (!(flags & VIR_SAVE_CHECKPOINT)) {
+        /* Shut it down */
+        qemudShutdownVMDaemon(dom->conn, driver, vm);
+        event = virDomainEventNewFromObj(vm,
                                      VIR_DOMAIN_EVENT_STOPPED,
                                      VIR_DOMAIN_EVENT_STOPPED_SAVED);
-    if (!vm->persistent) {
-        virDomainRemoveInactive(&driver->domains,
+        if (!vm->persistent) {
+            virDomainRemoveInactive(&driver->domains,
                                 vm);
-        vm = NULL;
+            vm = NULL;
+        }
     }
     ret = 0;
--- ./src/remote_internal.c	2009-01-31 18:04:18.000000000 +0900
+++ ../libvirt-0.6.0.1/./src/remote_internal.c	2009-02-11 14:08:23.000000000 +0900
@@ -2070,5 +2070,5 @@
 
 static int
-remoteDomainSave (virDomainPtr domain, const char *to)
+remoteDomainSave (virDomainPtr domain, unsigned long flags, const char *to)
 {
     int rv = -1;
@@ -2080,4 +2080,5 @@
     make_nonnull_domain (&args.dom, domain);
     args.to = (char *) to;
+    args.flags = flags;
 
     if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_SAVE,
--- ./src/xend_internal.h	2008-12-19 21:51:12.000000000 +0900
+++ ../libvirt-0.6.0.1/./src/xend_internal.h	2009-02-12 12:35:55.000000000 +0900
@@ -141,5 +141,6 @@
 int xenDaemonDomainReboot(virDomainPtr domain, unsigned int flags);
 int xenDaemonDomainDestroy(virDomainPtr domain);
-int xenDaemonDomainSave(virDomainPtr domain, const char *filename);
+int xenDaemonDomainSave(virDomainPtr domain, unsigned long flags,
+                        const char *filename);
 int xenDaemonDomainRestore(virConnectPtr conn, const char *filename);
 int xenDaemonDomainSetMemory(virDomainPtr domain, unsigned long memory);
--- ./src/libvirt.c	2009-01-31 18:04:17.000000000 +0900
+++ ../libvirt-0.6.0.1/./src/libvirt.c	2009-02-12 12:37:20.000000000 +0900
@@ -1931,4 +1931,5 @@
  * virDomainSave:
  * @domain: a domain object
+ * @flags: flags
  * @to: path for the output file
  *
@@ -1937,13 +1938,16 @@
  * listed as running anymore (this may be a problem).
  * Use virDomainRestore() to restore a domain after saving.
+ * Flags may be one of more of the following:
+ *   VIR_SAVE_CHECKPOINT  Don't exit after save
  *
  * Returns 0 in case of success and -1 in case of failure.
  */
 int
-virDomainSave(virDomainPtr domain, const char *to)
+virDomainSave(virDomainPtr domain, unsigned long flags,
+              const char *to)
 {
     char filepath[4096];
     virConnectPtr conn;
-    DEBUG("domain=%p, to=%s", domain, to);
+    DEBUG("domain=%p, flags=%lu, to=%s", domain, flags, to);
 
     virResetLastError();
@@ -1985,5 +1989,5 @@
     if (conn->driver->domainSave) {
         int ret;
-        ret = conn->driver->domainSave (domain, to);
+        ret = conn->driver->domainSave (domain, flags, to);
         if (ret < 0)
             goto error;
--- ./src/test.c	2009-01-21 05:39:28.000000000 +0900
+++ ../libvirt-0.6.0.1/./src/test.c	2009-02-12 12:37:40.000000000 +0900
@@ -1180,5 +1180,5 @@
 #define TEST_SAVE_MAGIC "TestGuestMagic"
 
-static int testDomainSave(virDomainPtr domain,
+static int testDomainSave(virDomainPtr domain, unsigned long flags,
                           const char *path)
 {
@@ -1210,6 +1210,6 @@
     if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR)) < 0) {
         virReportSystemError(domain->conn, errno,
-                             _("saving domain '%s' to '%s': open failed"),
-                             domain->name, path);
+                             _("saving domain '%s' with '%lu' to '%s': open failed"),
+                             domain->name, flags, path);
         goto cleanup;
     }
@@ -1217,18 +1217,18 @@
     if (safewrite(fd, TEST_SAVE_MAGIC, sizeof(TEST_SAVE_MAGIC)) < 0) {
         virReportSystemError(domain->conn, errno,
-                             _("saving domain '%s' to '%s': write failed"),
-                             domain->name, path);
+                             _("saving domain '%s' with '%lu' to '%s': write failed"),
+                             domain->name, flags, path);
         goto cleanup;
     }
     if (safewrite(fd, (char*)&len, sizeof(len)) < 0) {
         virReportSystemError(domain->conn, errno,
-                             _("saving domain '%s' to '%s': write failed"),
-                             domain->name, path);
+                             _("saving domain '%s' with '%lu' to '%s': write failed"),
+                             domain->name, flags, path);
         goto cleanup;
     }
     if (safewrite(fd, xml, len) < 0) {
         virReportSystemError(domain->conn, errno,
-                             _("saving domain '%s' to '%s': write failed"),
-                             domain->name, path);
+                             _("saving domain '%s' with '%lu' to '%s': write failed"),
+                             domain->name, flags, path);
         goto cleanup;
     }
@@ -1236,6 +1236,6 @@
     if (close(fd) < 0) {
         virReportSystemError(domain->conn, errno,
-                             _("saving domain '%s' to '%s': write failed"),
-                             domain->name, path);
+                             _("saving domain '%s' with '%lu' to '%s': write failed"),
+                             domain->name, flags, path);
         goto cleanup;
     }
--- ./src/xen_unified.c	2009-01-31 18:04:18.000000000 +0900
+++ ../libvirt-0.6.0.1/./src/xen_unified.c	2009-02-11 13:41:07.000000000 +0900
@@ -901,5 +901,5 @@
 
 static int
-xenUnifiedDomainSave (virDomainPtr dom, const char *to)
+xenUnifiedDomainSave (virDomainPtr dom, unsigned long flags, const char *to)
 {
     GET_PRIVATE(dom->conn);
--- ./src/driver.h	2008-12-19 21:51:11.000000000 +0900
+++ ../libvirt-0.6.0.1/./src/driver.h	2009-02-11 13:02:16.000000000 +0900
@@ -141,4 +141,5 @@
 typedef int
         (*virDrvDomainSave)		(virDomainPtr domain,
+	                                 unsigned long flags,
                                          const char *to);
 typedef int
--- ./src/virsh.c	2009-01-31 18:04:18.000000000 +0900
+++ ../libvirt-0.6.0.1/./src/virsh.c	2009-02-12 12:19:53.000000000 +0900
@@ -1044,9 +1044,10 @@
 static const vshCmdInfo info_save[] = {
     {"help", gettext_noop("save a domain state to a file")},
-    {"desc", gettext_noop("Save a running domain.")},
+    {"desc", gettext_noop("Save a running domain. Add --checkpoint to not quit")},
     {NULL, NULL}
 };
 
 static const vshCmdOptDef opts_save[] = {
+    {"checkpoint", VSH_OT_BOOL, 0, gettext_noop("checkpoint save")},
     {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("domain name, id or uuid")},
     {"file", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("where to save the data")},
@@ -1060,4 +1061,5 @@
     char *name;
     char *to;
+    int flags = 0;
     int ret = TRUE;
 
@@ -1070,9 +1072,12 @@
     if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
         return FALSE;
+	
+    if (vshCommandOptBool (cmd, "checkpoint"))
+        flags |= VIR_SAVE_CHECKPOINT;
 
-    if (virDomainSave(dom, to) == 0) {
+    if (virDomainSave(dom, flags, to) == 0) {
         vshPrint(ctl, _("Domain %s saved to %s\n"), name, to);
     } else {
-        vshError(ctl, FALSE, _("Failed to save domain %s to %s"), name, to);
+        vshError(ctl, FALSE, _("Failed to save domain %s with %lu to %s"), name, flags, to);
         ret = FALSE;
     }
--- ./src/xend_internal.c	2009-01-31 18:04:18.000000000 +0900
+++ ../libvirt-0.6.0.1/./src/xend_internal.c	2009-02-12 12:41:54.000000000 +0900
@@ -2974,4 +2974,5 @@
  * xenDaemonDomainSave:
  * @domain: pointer to the Domain block
+ * @flags: flags
  * @filename: path for the output file
  *
@@ -2985,5 +2986,7 @@
  */
 int
-xenDaemonDomainSave(virDomainPtr domain, const char *filename)
+xenDaemonDomainSave(virDomainPtr domain,
+                    unsigned long flags ATTRIBUTE_UNUSED,
+                    const char *filename)
 {
     if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL) ||
--- ./qemud/remote_protocol.x	2008-12-19 21:51:11.000000000 +0900
+++ ../libvirt-0.6.0.1/./qemud/remote_protocol.x	2009-02-11 14:07:10.000000000 +0900
@@ -481,4 +481,5 @@
 struct remote_domain_save_args {
     remote_nonnull_domain dom;
+    unsigned hyper flags;
     remote_nonnull_string to;
 };
--- ./qemud/remote_protocol.h	2009-01-31 18:04:17.000000000 +0900
+++ ../libvirt-0.6.0.1/./qemud/remote_protocol.h	2009-02-11 14:05:38.000000000 +0900
@@ -447,4 +447,5 @@
 struct remote_domain_save_args {
         remote_nonnull_domain dom;
+        uint64_t flags;
         remote_nonnull_string to;
 };
--- ./qemud/remote_protocol.c	2009-01-31 18:04:17.000000000 +0900
+++ ../libvirt-0.6.0.1/./qemud/remote_protocol.c	2009-02-11 14:06:32.000000000 +0900
@@ -856,4 +856,6 @@
          if (!xdr_remote_nonnull_domain (xdrs, &objp->dom))
                  return FALSE;
+         if (!xdr_uint64_t (xdrs, &objp->flags))
+                 return FALSE;
          if (!xdr_remote_nonnull_string (xdrs, &objp->to))
                  return FALSE;
--- ./qemud/remote.c	2009-01-31 18:04:17.000000000 +0900
+++ ../libvirt-0.6.0.1/./qemud/remote.c	2009-02-11 12:18:54.000000000 +0900
@@ -1857,5 +1857,5 @@
     }
 
-    if (virDomainSave (dom, args->to) == -1) {
+    if (virDomainSave (dom, args->flags, args->to) == -1) {
         virDomainFree(dom);
         remoteDispatchConnError(rerr, conn);
--- ./docs/libvirt-refs.xml	2009-01-31 18:20:13.000000000 +0900
+++ ../libvirt-0.6.0.1/./docs/libvirt-refs.xml	2009-02-11 10:25:58.000000000 +0900
@@ -2876,4 +2876,7 @@
           <ref name='virConnectListStoragePools'/>
         </word>
+        <word name='checkpoint'>
+          <ref name='virDomainSave'/>
+        </word>
         <word name='choose'>
           <ref name='virDomainMigrate'/>
--- ./docs/libvirt-api.xml	2009-01-31 18:20:13.000000000 +0900
+++ ../libvirt-0.6.0.1/./docs/libvirt-api.xml	2009-02-11 15:12:40.000000000 +0900
@@ -41,4 +41,5 @@
      <exports symbol='VIR_DOMAIN_EVENT_UNDEFINED' type='enum'/>
      <exports symbol='VIR_MIGRATE_LIVE' type='enum'/>
+     <exports symbol='VIR_SAVE_CHECKPOINT' type='enum'/>
      <exports symbol='VIR_DOMAIN_EVENT_STOPPED_DESTROYED' type='enum'/>
      <exports symbol='VIR_DOMAIN_EVENT_DEFINED_ADDED' type='enum'/>
@@ -594,4 +595,5 @@
     <enum name='VIR_MEMORY_VIRTUAL' file='libvirt' value='1' type='virDomainMemoryFlags' info=' addresses are virtual addresses'/>
     <enum name='VIR_MIGRATE_LIVE' file='libvirt' value='1' type='virDomainMigrateFlags' info=' live migration'/>
+    <enum name='VIR_SAVE_CHECKPOINT' file='libvirt' value='1' type='virDomainSaveFlags' info=' checkpoint save'/>
     <enum name='VIR_STORAGE_POOL_BUILDING' file='libvirt' value='1' type='virStoragePoolState' info='Initializing pool, not available'/>
     <enum name='VIR_STORAGE_POOL_BUILD_NEW' file='libvirt' value='0' type='virStoragePoolBuildFlags' info='Regular build from scratch'/>
@@ -1208,7 +1210,8 @@
     </function>
     <function name='virDomainSave' file='libvirt' module='libvirt'>
-      <info>This method will suspend a domain and save its memory contents to a file on disk. After the call, if successful, the domain is not listed as running anymore (this may be a problem). Use virDomainRestore() to restore a domain after saving.</info>
+      <info>This method will suspend a domain and save its memory contents to a file on disk. Flags may be one of more of the following: VIR_SAVE_CHECKPOINT. After the call, if successful, the domain is not listed as running anymore (this may be a problem). Use virDomainRestore() to restore a domain after saving.</info>
       <return type='int' info='0 in case of success and -1 in case of failure.'/>
       <arg name='domain' type='virDomainPtr' info='a domain object'/>
+      <arg name='flags' type='unsigned long' info='save flags'/>
       <arg name='to' type='const char *' info='path for the output file'/>
     </function>

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