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

Along the lines of Xen's 'xm save' function with the '-c' checkpoint flag, following up is a patch to basically make-it-so, plus enable it for qemu. Patch merges with CVS, and passes tests as described in the HACKING file. The code implementing the '--live' option for 'virsh migrate' was copied/pasted/mod'ed to create the --checkpoint option for 'virsh save' Regards Matt McCowan

diff -ur libvirt.orig/docs/libvirt-api.xml libvirt/docs/libvirt-api.xml --- libvirt.orig/docs/libvirt-api.xml 2009-01-31 20:46:29.000000000 +0900 +++ libvirt/docs/libvirt-api.xml 2009-02-24 18:12:34.000000000 +0900 @@ -40,6 +40,7 @@ <exports symbol='VIR_CRED_NOECHOPROMPT' type='enum'/> <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'/> <exports symbol='VIR_DOMAIN_EVENT_STARTED_MIGRATED' type='enum'/> @@ -593,6 +594,7 @@ <enum name='VIR_FROM_XML' file='virterror' value='5' type='virErrorDomain' info='Error in the XML code'/> <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'/> <enum name='VIR_STORAGE_POOL_BUILD_REPAIR' file='libvirt' value='1' type='virStoragePoolBuildFlags' info='Repair / reinitialize'/> @@ -1207,9 +1209,10 @@ <arg name='domain' type='virDomainPtr' info='a domain object'/> </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 may be suspended (CHECKPOINT) or 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> <function name='virDomainSetAutostart' file='libvirt' module='libvirt'> diff -ur libvirt.orig/docs/libvirt-refs.xml libvirt/docs/libvirt-refs.xml --- libvirt.orig/docs/libvirt-refs.xml 2009-01-31 20:46:29.000000000 +0900 +++ libvirt/docs/libvirt-refs.xml 2009-02-24 13:09:07.000000000 +0900 @@ -2875,6 +2875,9 @@ <ref name='virConnectListDefinedStoragePools'/> <ref name='virConnectListStoragePools'/> </word> + <word name='checkpoint'> + <ref name='virDomainSave'/> + </word> <word name='choose'> <ref name='virDomainMigrate'/> </word> diff -ur libvirt.orig/include/libvirt/libvirt.h.in libvirt/include/libvirt/libvirt.h.in --- libvirt.orig/include/libvirt/libvirt.h.in 2009-01-20 21:14:03.000000000 +0900 +++ libvirt/include/libvirt/libvirt.h.in 2009-02-24 13:09:07.000000000 +0900 @@ -463,10 +463,16 @@ int virDomainSuspend (virDomainPtr domain); 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, const char *from); diff -ur libvirt.orig/qemud/remote.c libvirt/qemud/remote.c --- libvirt.orig/qemud/remote.c 2009-02-06 01:28:30.000000000 +0900 +++ libvirt/qemud/remote.c 2009-02-24 13:09:07.000000000 +0900 @@ -1861,7 +1861,7 @@ return -1; } - if (virDomainSave (dom, args->to) == -1) { + if (virDomainSave (dom, args->flags, args->to) == -1) { virDomainFree(dom); remoteDispatchConnError(rerr, conn); return -1; diff -ur libvirt.orig/qemud/remote_protocol.c libvirt/qemud/remote_protocol.c --- libvirt.orig/qemud/remote_protocol.c 2009-01-29 06:33:56.000000000 +0900 +++ libvirt/qemud/remote_protocol.c 2009-02-24 13:09:07.000000000 +0900 @@ -855,6 +855,8 @@ 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; return TRUE; diff -ur libvirt.orig/qemud/remote_protocol.h libvirt/qemud/remote_protocol.h --- libvirt.orig/qemud/remote_protocol.h 2009-01-29 06:33:56.000000000 +0900 +++ libvirt/qemud/remote_protocol.h 2009-02-24 13:09:07.000000000 +0900 @@ -446,6 +446,7 @@ struct remote_domain_save_args { remote_nonnull_domain dom; + uint64_t flags; remote_nonnull_string to; }; typedef struct remote_domain_save_args remote_domain_save_args; diff -ur libvirt.orig/qemud/remote_protocol.x libvirt/qemud/remote_protocol.x --- libvirt.orig/qemud/remote_protocol.x 2008-12-18 02:23:21.000000000 +0900 +++ libvirt/qemud/remote_protocol.x 2009-02-24 13:09:07.000000000 +0900 @@ -480,6 +480,7 @@ struct remote_domain_save_args { remote_nonnull_domain dom; + unsigned hyper flags; remote_nonnull_string to; }; diff -ur libvirt.orig/src/driver.h libvirt/src/driver.h --- libvirt.orig/src/driver.h 2008-12-18 06:48:20.000000000 +0900 +++ libvirt/src/driver.h 2009-02-24 13:09:07.000000000 +0900 @@ -140,6 +140,7 @@ virDomainInfoPtr info); typedef int (*virDrvDomainSave) (virDomainPtr domain, + unsigned long flags, const char *to); typedef int (*virDrvDomainRestore) (virConnectPtr conn, diff -ur libvirt.orig/src/libvirt.c libvirt/src/libvirt.c --- libvirt.orig/src/libvirt.c 2009-02-17 19:33:41.000000000 +0900 +++ libvirt/src/libvirt.c 2009-02-24 13:09:07.000000000 +0900 @@ -1937,21 +1937,25 @@ /** * virDomainSave: * @domain: a domain object + * @flags: flags * @to: path for the output file * * 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. + * 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(); @@ -1991,7 +1995,7 @@ if (conn->driver->domainSave) { int ret; - ret = conn->driver->domainSave (domain, to); + ret = conn->driver->domainSave (domain, flags, to); if (ret < 0) goto error; return ret; diff -ur libvirt.orig/src/qemu_driver.c libvirt/src/qemu_driver.c --- libvirt.orig/src/qemu_driver.c 2009-02-19 17:18:31.000000000 +0900 +++ libvirt/src/qemu_driver.c 2009-02-24 13:09:07.000000000 +0900 @@ -2393,6 +2393,7 @@ }; static int qemudDomainSave(virDomainPtr dom, + unsigned long flags ATTRIBUTE_UNUSED, const char *path) { struct qemud_driver *driver = dom->conn->privateData; virDomainObjPtr vm; @@ -2504,15 +2505,17 @@ goto cleanup; } - /* 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; diff -ur libvirt.orig/src/remote_internal.c libvirt/src/remote_internal.c --- libvirt.orig/src/remote_internal.c 2009-02-17 18:44:18.000000000 +0900 +++ libvirt/src/remote_internal.c 2009-02-24 13:09:07.000000000 +0900 @@ -2065,7 +2065,7 @@ } static int -remoteDomainSave (virDomainPtr domain, const char *to) +remoteDomainSave (virDomainPtr domain, unsigned long flags, const char *to) { int rv = -1; remote_domain_save_args args; @@ -2075,6 +2075,7 @@ make_nonnull_domain (&args.dom, domain); args.to = (char *) to; + args.flags = flags; if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_SAVE, (xdrproc_t) xdr_remote_domain_save_args, (char *) &args, diff -ur libvirt.orig/src/test.c libvirt/src/test.c --- libvirt.orig/src/test.c 2009-02-14 03:11:03.000000000 +0900 +++ libvirt/src/test.c 2009-02-24 13:09:07.000000000 +0900 @@ -1176,7 +1176,7 @@ #define TEST_SAVE_MAGIC "TestGuestMagic" -static int testDomainSave(virDomainPtr domain, +static int testDomainSave(virDomainPtr domain, unsigned long flags, const char *path) { testConnPtr privconn = domain->conn->privateData; @@ -1206,34 +1206,34 @@ 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; } len = strlen(xml); 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; } 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; } fd = -1; diff -ur libvirt.orig/src/virsh.c libvirt/src/virsh.c --- libvirt.orig/src/virsh.c 2009-02-17 07:51:31.000000000 +0900 +++ libvirt/src/virsh.c 2009-02-24 18:09:30.000000000 +0900 @@ -1067,11 +1067,12 @@ */ 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")}, {NULL, 0, 0, NULL} @@ -1083,6 +1084,7 @@ virDomainPtr dom; char *name; char *to; + long unsigned int flags = 0; int ret = TRUE; if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) @@ -1094,10 +1096,14 @@ if (!(dom = vshCommandOptDomain(ctl, cmd, &name))) return FALSE; - if (virDomainSave(dom, to) == 0) { + if (vshCommandOptBool (cmd, "checkpoint")) + flags |= VIR_SAVE_CHECKPOINT; + + 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; } diff -ur libvirt.orig/src/xen_unified.c libvirt/src/xen_unified.c --- libvirt.orig/src/xen_unified.c 2009-02-06 01:03:11.000000000 +0900 +++ libvirt/src/xen_unified.c 2009-02-24 13:09:07.000000000 +0900 @@ -899,7 +899,7 @@ } static int -xenUnifiedDomainSave (virDomainPtr dom, const char *to) +xenUnifiedDomainSave (virDomainPtr dom, unsigned long flags, const char *to) { GET_PRIVATE(dom->conn); int i; diff -ur libvirt.orig/src/xend_internal.c libvirt/src/xend_internal.c --- libvirt.orig/src/xend_internal.c 2009-02-14 03:23:23.000000000 +0900 +++ libvirt/src/xend_internal.c 2009-02-24 13:09:07.000000000 +0900 @@ -2999,6 +2999,7 @@ /** * xenDaemonDomainSave: * @domain: pointer to the Domain block + * @flags: flags * @filename: path for the output file * * This method will suspend a domain and save its memory contents to @@ -3010,7 +3011,9 @@ * Returns 0 in case of success, -1 (with errno) in case of error. */ 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) || (filename == NULL)) { diff -ur libvirt.orig/src/xend_internal.h libvirt/src/xend_internal.h --- libvirt.orig/src/xend_internal.h 2008-12-18 06:26:16.000000000 +0900 +++ libvirt/src/xend_internal.h 2009-02-24 13:09:07.000000000 +0900 @@ -140,7 +140,8 @@ int xenDaemonDomainShutdown(virDomainPtr domain); 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); int xenDaemonDomainSetMaxMemory(virDomainPtr domain, unsigned long memory);

Matt McCowan wrote:
diff -ur libvirt.orig/include/libvirt/libvirt.h.in libvirt/include/libvirt/libvirt.h.in --- libvirt.orig/include/libvirt/libvirt.h.in 2009-01-20 21:14:03.000000000 +0900 +++ libvirt/include/libvirt/libvirt.h.in 2009-02-24 13:09:07.000000000 +0900 @@ -463,10 +463,16 @@ int virDomainSuspend (virDomainPtr domain); 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);
Unfortunately, you cannot do this. virDomainSave() is part of the public API in libvirt, and that is guaranteed to never change. So we can't add more fields to it. Your best bet at this point might be to add another call, "virDomainCheckpoint", with the arguments you need. Then factor out the internal implementations of virDomainSave so that both virDomainSave and virDomainCheckpoint share most of the same code, with just the slight differences for checkpointing. -- Chris Lalancette
participants (2)
-
Chris Lalancette
-
Matt McCowan