]> xenbits.xensource.com Git - libvirt.git/commitdiff
qemu_process: abort snapshot delete when daemon starts
authorPavel Hrdina <phrdina@redhat.com>
Thu, 1 Dec 2022 14:38:59 +0000 (15:38 +0100)
committerPavel Hrdina <phrdina@redhat.com>
Mon, 9 Jan 2023 12:33:16 +0000 (13:33 +0100)
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 <phrdina@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
src/qemu/qemu_process.c
src/qemu/qemu_snapshot.c

index 49ae7b688b798fdb7a04ad7213d09ab8784ef02b..cc65e6befa9db76256e1e3673d09884ef14cf4a1 100644 (file)
@@ -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:
index 189fe98299d777da9d08341ff6a5eb1a75c85e7e..348d3260c84173a6b4f72117b6b838ae30f3277c 100644 (file)
@@ -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)