From cadbf40d05b9df2b0fe6d2e9409e1f1a105b830e Mon Sep 17 00:00:00 2001 From: Pavel Hrdina Date: Thu, 1 Dec 2022 15:38:59 +0100 Subject: [PATCH] qemu_process: abort snapshot delete when daemon starts If the daemon crashes or is restarted while the snapshot delete is in progress we have to handle it gracefully to not leave any block jobs active. For now we will simply abort the snapshot delete operation so user can start it again. We need to refuse deleting external snapshots if there is already another active job as we would have to figure out which jobs we can abort. Signed-off-by: Pavel Hrdina Reviewed-by: Peter Krempa --- src/qemu/qemu_process.c | 37 +++++++++++++++++++++++++++++++++++++ src/qemu/qemu_snapshot.c | 15 +++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 49ae7b688b..cc65e6befa 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -3692,6 +3692,42 @@ qemuProcessRecoverMigration(virQEMUDriver *driver, } +static void +qemuProcessAbortSnapshotDelete(virDomainObj *vm, + virDomainJobObj *job) +{ + size_t i; + qemuDomainObjPrivate *priv = vm->privateData; + qemuDomainJobPrivate *jobPriv = job->privateData; + + if (!jobPriv->snapshotDelete) + return; + + for (i = 0; i < vm->def->ndisks; i++) { + virDomainDiskDef *disk = vm->def->disks[i]; + g_autoptr(qemuBlockJobData) diskJob = qemuBlockJobDiskGetJob(disk); + + if (!diskJob) + continue; + + if (diskJob->type != QEMU_BLOCKJOB_TYPE_COMMIT && + diskJob->type != QEMU_BLOCKJOB_TYPE_ACTIVE_COMMIT) { + continue; + } + + qemuBlockJobSyncBegin(diskJob); + + qemuDomainObjEnterMonitor(vm); + ignore_value(qemuMonitorBlockJobCancel(priv->mon, diskJob->name, false)); + qemuDomainObjExitMonitor(vm); + + diskJob->state = QEMU_BLOCKJOB_STATE_ABORTING; + + qemuBlockJobSyncEnd(vm, diskJob, VIR_ASYNC_JOB_NONE); + } +} + + static int qemuProcessRecoverJob(virQEMUDriver *driver, virDomainObj *vm, @@ -3741,6 +3777,7 @@ qemuProcessRecoverJob(virQEMUDriver *driver, vm->def->name); } } + qemuProcessAbortSnapshotDelete(vm, job); break; case VIR_ASYNC_JOB_START: diff --git a/src/qemu/qemu_snapshot.c b/src/qemu/qemu_snapshot.c index 189fe98299..348d3260c8 100644 --- a/src/qemu/qemu_snapshot.c +++ b/src/qemu/qemu_snapshot.c @@ -3095,6 +3095,13 @@ qemuSnapshotDeleteValidate(virDomainObj *vm, } } + if (virDomainSnapshotIsExternal(snap) && + qemuDomainHasBlockjob(vm, false)) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("cannot delete external snapshots when there is another active block job")); + return -1; + } + if (virDomainSnapshotIsExternal(snap) && !(flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", @@ -3158,6 +3165,14 @@ qemuSnapshotDelete(virDomainObj *vm, * running to get everything we need. */ delData = g_steal_pointer(&externalData); externalData = qemuSnapshotDeleteExternalPrepare(vm, snap); + } else { + qemuDomainJobPrivate *jobPriv = vm->job->privateData; + + /* If the VM is running we need to indicate that the async snapshot + * job is snapshot delete job. */ + jobPriv->snapshotDelete = true; + + qemuDomainSaveStatus(vm); } if (!externalData)