From 27c85260532f879be5674a4eed0811c21fd34f94 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Sat, 27 Aug 2011 17:07:18 -0600 Subject: [PATCH] start: allow discarding managed save There have been several instances of people having problems with a broken managed save file, and not aware that they could use 'virsh managedsave-remove dom' to fix things. Making it possible to do this as part of starting a domain makes the same functionality easier to find, and one less API call. * include/libvirt/libvirt.h.in (VIR_DOMAIN_START_FORCE_BOOT): New flag. * src/libvirt.c (virDomainCreateWithFlags): Document it. * src/qemu/qemu_driver.c (qemuDomainObjStart): Alter signature. (qemuAutostartDomain, qemuDomainStartWithFlags): Update callers. * tools/virsh.c (cmdStart): Expose it in virsh. * tools/virsh.pod (start): Document it. --- include/libvirt/libvirt.h.in | 1 + src/libvirt.c | 3 +++ src/qemu/qemu_driver.c | 50 +++++++++++++++++++++--------------- tools/virsh.c | 7 ++++- tools/virsh.pod | 5 ++-- 5 files changed, 43 insertions(+), 23 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 53a2f7d6f2..c51a5b9ddd 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -236,6 +236,7 @@ typedef enum { VIR_DOMAIN_START_PAUSED = 1 << 0, /* Launch guest in paused state */ VIR_DOMAIN_START_AUTODESTROY = 1 << 1, /* Automatically kill guest when virConnectPtr is closed */ VIR_DOMAIN_START_BYPASS_CACHE = 1 << 2, /* Avoid file system cache pollution */ + VIR_DOMAIN_START_FORCE_BOOT = 1 << 3, /* Boot, discarding any managed save */ } virDomainCreateFlags; diff --git a/src/libvirt.c b/src/libvirt.c index 65a099b36c..80c8b7cd01 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -7081,6 +7081,9 @@ error: * the file, or fail if it cannot do so for the given system; this can allow * less pressure on file system cache, but also risks slowing loads from NFS. * + * If the VIR_DOMAIN_START_FORCE_BOOT flag is set, then any managed save + * file for this domain is discarded, and the domain boots from scratch. + * * Returns 0 in case of success, -1 in case of error */ int diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index f21122d930..5033998703 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -120,9 +120,7 @@ static int qemudShutdown(void); static int qemuDomainObjStart(virConnectPtr conn, struct qemud_driver *driver, virDomainObjPtr vm, - bool start_paused, - bool autodestroy, - bool bypass_cache); + unsigned int flags); static int qemudDomainGetMaxVcpus(virDomainPtr dom); @@ -135,11 +133,16 @@ struct qemuAutostartData { }; static void -qemuAutostartDomain(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque) +qemuAutostartDomain(void *payload, const void *name ATTRIBUTE_UNUSED, + void *opaque) { virDomainObjPtr vm = payload; struct qemuAutostartData *data = opaque; virErrorPtr err; + int flags = 0; + + if (data->driver->autoStartBypassCache) + flags |= VIR_DOMAIN_START_BYPASS_CACHE; virDomainObjLock(vm); virResetLastError(); @@ -152,9 +155,7 @@ qemuAutostartDomain(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaq } else { if (vm->autostart && !virDomainObjIsActive(vm) && - qemuDomainObjStart(data->conn, data->driver, vm, - false, false, - data->driver->autoStartBypassCache) < 0) { + qemuDomainObjStart(data->conn, data->driver, vm, flags) < 0) { err = virGetLastError(); VIR_ERROR(_("Failed to autostart VM '%s': %s"), vm->def->name, @@ -4441,12 +4442,14 @@ static int qemuDomainObjStart(virConnectPtr conn, struct qemud_driver *driver, virDomainObjPtr vm, - bool start_paused, - bool autodestroy, - bool bypass_cache) + unsigned int flags) { int ret = -1; char *managed_save; + bool start_paused = (flags & VIR_DOMAIN_START_PAUSED) != 0; + bool autodestroy = (flags & VIR_DOMAIN_START_AUTODESTROY) != 0; + bool bypass_cache = (flags & VIR_DOMAIN_START_BYPASS_CACHE) != 0; + bool force_boot = (flags & VIR_DOMAIN_START_FORCE_BOOT) != 0; /* * If there is a managed saved state restore it instead of starting @@ -4458,13 +4461,22 @@ qemuDomainObjStart(virConnectPtr conn, goto cleanup; if (virFileExists(managed_save)) { - ret = qemuDomainObjRestore(conn, driver, vm, managed_save, - bypass_cache); + if (force_boot) { + if (unlink(managed_save) < 0) { + virReportSystemError(errno, + _("cannot remove managed save file %s"), + managed_save); + goto cleanup; + } + } else { + ret = qemuDomainObjRestore(conn, driver, vm, managed_save, + bypass_cache); - if ((ret == 0) && (unlink(managed_save) < 0)) - VIR_WARN("Failed to remove the managed state %s", managed_save); + if ((ret == 0) && (unlink(managed_save) < 0)) + VIR_WARN("Failed to remove the managed state %s", managed_save); - goto cleanup; + goto cleanup; + } } ret = qemuProcessStart(conn, driver, vm, NULL, start_paused, @@ -4493,7 +4505,8 @@ qemuDomainStartWithFlags(virDomainPtr dom, unsigned int flags) virCheckFlags(VIR_DOMAIN_START_PAUSED | VIR_DOMAIN_START_AUTODESTROY | - VIR_DOMAIN_START_BYPASS_CACHE, -1); + VIR_DOMAIN_START_BYPASS_CACHE | + VIR_DOMAIN_START_FORCE_BOOT, -1); qemuDriverLock(driver); vm = virDomainFindByUUID(&driver->domains, dom->uuid); @@ -4515,10 +4528,7 @@ qemuDomainStartWithFlags(virDomainPtr dom, unsigned int flags) goto endjob; } - if (qemuDomainObjStart(dom->conn, driver, vm, - (flags & VIR_DOMAIN_START_PAUSED) != 0, - (flags & VIR_DOMAIN_START_AUTODESTROY) != 0, - (flags & VIR_DOMAIN_START_BYPASS_CACHE) != 0) < 0) + if (qemuDomainObjStart(dom->conn, driver, vm, flags) < 0) goto endjob; ret = 0; diff --git a/tools/virsh.c b/tools/virsh.c index 15b9bdd4f0..49034aec26 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -1537,9 +1537,12 @@ static const vshCmdOptDef opts_start[] = { {"console", VSH_OT_BOOL, 0, N_("attach to console after creation")}, #endif {"paused", VSH_OT_BOOL, 0, N_("leave the guest paused after creation")}, - {"autodestroy", VSH_OT_BOOL, 0, N_("automatically destroy the guest when virsh disconnects")}, + {"autodestroy", VSH_OT_BOOL, 0, + N_("automatically destroy the guest when virsh disconnects")}, {"bypass-cache", VSH_OT_BOOL, 0, N_("avoid file system cache when loading")}, + {"force-boot", VSH_OT_BOOL, 0, + N_("force fresh boot by discarding any managed save")}, {NULL, 0, 0, NULL} }; @@ -1572,6 +1575,8 @@ cmdStart(vshControl *ctl, const vshCmd *cmd) flags |= VIR_DOMAIN_START_AUTODESTROY; if (vshCommandOptBool(cmd, "bypass-cache")) flags |= VIR_DOMAIN_START_BYPASS_CACHE; + if (vshCommandOptBool(cmd, "force-boot")) + flags |= VIR_DOMAIN_START_FORCE_BOOT; /* Prefer older API unless we have to pass a flag. */ if ((flags ? virDomainCreateWithFlags(dom, flags) diff --git a/tools/virsh.pod b/tools/virsh.pod index 81d7a1e35f..2cd0f738c3 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -890,7 +890,7 @@ The exact behavior of a domain when it shuts down is set by the I parameter in the domain's XML definition. =item B I [I<--console>] [I<--paused>] [I<--autodestroy>] -[I<--bypass-cache>] +[I<--bypass-cache>] [I<--force-boot>] Start a (previously defined) inactive domain, either from the last B state, or via a fresh boot if no managedsave state is @@ -901,7 +901,8 @@ If I<--autodestroy> is requested, then the guest will be automatically destroyed when virsh closes its connection to libvirt, or otherwise exits. If I<--bypass-cache> is specified, and managedsave state exists, the restore will avoid the file system cache, although this may slow -down the operation. +down the operation. If I<--force-boot> is specified, then any +managedsave state is discarded and a fresh boot occurs. =item B I