On Wed, Jan 08, 2025 at 19:42:42 +0000, Daniel P. Berrangé wrote: > The auto shutdown code can currently only perform managed save, > which may fail in some cases, for example when PCI devices are > assigned. On failure, shutdown inhibitors remain in place which > may be undesirable. > > This expands the logic to try a sequence of operations > > * Managed save > * Graceful shutdown > * Forced poweroff > > Each of these operations can be enabled or disabled, but they > are always applied in this order. > > With the shutdown option, a configurable time is allowed for > shutdown to complete, defaulting to 30 seconds, before moving > onto the forced poweroff phase. > > Signed-off-by: Daniel P. Berrangé <berrange@xxxxxxxxxx> > --- > src/hypervisor/domain_driver.c | 113 +++++++++++++++++++++++++++------ > src/hypervisor/domain_driver.h | 4 ++ > src/qemu/qemu_driver.c | 3 + > 3 files changed, 100 insertions(+), 20 deletions(-) > > diff --git a/src/hypervisor/domain_driver.c b/src/hypervisor/domain_driver.c > index 949e3d01f1..ea3f1cbfcd 100644 > --- a/src/hypervisor/domain_driver.c > +++ b/src/hypervisor/domain_driver.c Noticed while reviewing last patch: > @@ -726,31 +743,87 @@ virDomainDriverAutoShutdown(virDomainDriverAutoShutdownConfig *cfg) > VIR_CONNECT_LIST_DOMAINS_ACTIVE)) < 0) > goto cleanup; > > - flags = g_new0(unsigned int, numDomains); > + VIR_DEBUG("Auto shutdown with %d running domains", numDomains); > + if (cfg->trySave) { > + g_autofree unsigned int *flags = g_new0(unsigned int, numDomains); > + for (i = 0; i < numDomains; i++) { > + int state; > + /* > + * Pause all VMs to make them stop dirtying pages, > + * so save is quicker. We remember if any VMs were > + * paused so we can restore that on resume. > + */ > + flags[i] = VIR_DOMAIN_SAVE_RUNNING; > + if (virDomainGetState(domains[i], &state, NULL, 0) == 0) { > + if (state == VIR_DOMAIN_PAUSED) > + flags[i] = VIR_DOMAIN_SAVE_PAUSED; > + } > + virDomainSuspend(domains[i]); Any VM where we attempt 'save' is paused ... > + } > + > + for (i = 0; i < numDomains; i++) { > + if (virDomainManagedSave(domains[i], flags[i]) < 0) { > + VIR_WARN("Unable to perform managed save of '%s': %s", > + virDomainGetName(domains[i]), > + virGetLastErrorMessage()); > + continue; ... but not unpaused if saving fails ... > + } > + virObjectUnref(domains[i]); > + domains[i] = NULL; > + } > + } > + > + if (cfg->tryShutdown) { > + GTimer *timer = NULL; > + for (i = 0; i < numDomains; i++) { > + if (domains[i] == NULL) > + continue; > + if (virDomainShutdown(domains[i]) < 0) { ... so if we then request a graceful shutdown the guest OS can't respond to it. > + VIR_WARN("Unable to perform graceful shutdown of '%s': %s", > + virDomainGetName(domains[i]), > + virGetLastErrorMessage()); > + break; > + } > + }