mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-24 14:45:24 +00:00
snapshot: wire up qemu transaction command
The hardest part about adding transactions is not using the new monitor command, but undoing the partial changes we made prior to a failed transaction. * src/qemu/qemu_driver.c (qemuDomainSnapshotCreateDiskActive): Use transaction when available. (qemuDomainSnapshotUndoSingleDiskActive): New function. (qemuDomainSnapshotCreateSingleDiskActive): Pass through actions. (qemuDomainSnapshotCreateXML): Adjust caller.
This commit is contained in:
parent
64d5e815b7
commit
0436d328f5
@ -9823,7 +9823,8 @@ qemuDomainSnapshotCreateSingleDiskActive(struct qemud_driver *driver,
|
|||||||
virDomainObjPtr vm,
|
virDomainObjPtr vm,
|
||||||
virDomainSnapshotDiskDefPtr snap,
|
virDomainSnapshotDiskDefPtr snap,
|
||||||
virDomainDiskDefPtr disk,
|
virDomainDiskDefPtr disk,
|
||||||
virDomainDiskDefPtr persistDisk)
|
virDomainDiskDefPtr persistDisk,
|
||||||
|
virJSONValuePtr actions)
|
||||||
{
|
{
|
||||||
qemuDomainObjPrivatePtr priv = vm->privateData;
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||||
char *device = NULL;
|
char *device = NULL;
|
||||||
@ -9883,7 +9884,7 @@ qemuDomainSnapshotCreateSingleDiskActive(struct qemud_driver *driver,
|
|||||||
origdriver = NULL;
|
origdriver = NULL;
|
||||||
|
|
||||||
/* create the actual snapshot */
|
/* create the actual snapshot */
|
||||||
ret = qemuMonitorDiskSnapshot(priv->mon, NULL, device, source);
|
ret = qemuMonitorDiskSnapshot(priv->mon, actions, device, source);
|
||||||
virDomainAuditDisk(vm, disk->src, source, "snapshot", ret >= 0);
|
virDomainAuditDisk(vm, disk->src, source, "snapshot", ret >= 0);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -9924,6 +9925,69 @@ cleanup:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The domain is expected to hold monitor lock. This is the
|
||||||
|
* counterpart to qemuDomainSnapshotCreateSingleDiskActive, called
|
||||||
|
* only on a failed transaction. */
|
||||||
|
static void
|
||||||
|
qemuDomainSnapshotUndoSingleDiskActive(struct qemud_driver *driver,
|
||||||
|
virDomainObjPtr vm,
|
||||||
|
virDomainDiskDefPtr origdisk,
|
||||||
|
virDomainDiskDefPtr disk,
|
||||||
|
virDomainDiskDefPtr persistDisk,
|
||||||
|
bool need_unlink)
|
||||||
|
{
|
||||||
|
char *source = NULL;
|
||||||
|
char *driverType = NULL;
|
||||||
|
char *persistSource = NULL;
|
||||||
|
char *persistDriverType = NULL;
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
if (!(source = strdup(origdisk->src)) ||
|
||||||
|
(origdisk->driverType &&
|
||||||
|
!(driverType = strdup(origdisk->driverType))) ||
|
||||||
|
(persistDisk &&
|
||||||
|
(!(persistSource = strdup(source)) ||
|
||||||
|
(driverType && !(persistDriverType = strdup(driverType)))))) {
|
||||||
|
virReportOOMError();
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virSecurityManagerRestoreImageLabel(driver->securityManager,
|
||||||
|
vm->def, disk) < 0)
|
||||||
|
VIR_WARN("Unable to restore security label on %s", disk->src);
|
||||||
|
if (virDomainLockDiskDetach(driver->lockManager, vm, disk) < 0)
|
||||||
|
VIR_WARN("Unable to release lock on %s", disk->src);
|
||||||
|
if (need_unlink && stat(disk->src, &st) == 0 &&
|
||||||
|
st.st_size == 0 && S_ISREG(st.st_mode) && unlink(disk->src) < 0)
|
||||||
|
VIR_WARN("Unable to remove just-created %s", disk->src);
|
||||||
|
|
||||||
|
/* Update vm in place to match changes. */
|
||||||
|
VIR_FREE(disk->src);
|
||||||
|
disk->src = source;
|
||||||
|
source = NULL;
|
||||||
|
VIR_FREE(disk->driverType);
|
||||||
|
if (driverType) {
|
||||||
|
disk->driverType = driverType;
|
||||||
|
driverType = NULL;
|
||||||
|
}
|
||||||
|
if (persistDisk) {
|
||||||
|
VIR_FREE(persistDisk->src);
|
||||||
|
persistDisk->src = persistSource;
|
||||||
|
persistSource = NULL;
|
||||||
|
VIR_FREE(persistDisk->driverType);
|
||||||
|
if (persistDriverType) {
|
||||||
|
persistDisk->driverType = persistDriverType;
|
||||||
|
persistDriverType = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
VIR_FREE(source);
|
||||||
|
VIR_FREE(driverType);
|
||||||
|
VIR_FREE(persistSource);
|
||||||
|
VIR_FREE(persistDriverType);
|
||||||
|
}
|
||||||
|
|
||||||
/* The domain is expected to be locked and active. */
|
/* The domain is expected to be locked and active. */
|
||||||
static int
|
static int
|
||||||
qemuDomainSnapshotCreateDiskActive(virConnectPtr conn,
|
qemuDomainSnapshotCreateDiskActive(virConnectPtr conn,
|
||||||
@ -9933,6 +9997,8 @@ qemuDomainSnapshotCreateDiskActive(virConnectPtr conn,
|
|||||||
unsigned int flags)
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
virDomainObjPtr vm = *vmptr;
|
virDomainObjPtr vm = *vmptr;
|
||||||
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||||
|
virJSONValuePtr actions = NULL;
|
||||||
bool resume = false;
|
bool resume = false;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
int i;
|
int i;
|
||||||
@ -9982,9 +10048,17 @@ qemuDomainSnapshotCreateDiskActive(virConnectPtr conn,
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_TRANSACTION)) {
|
||||||
|
actions = virJSONValueNewArray();
|
||||||
|
if (!actions) {
|
||||||
|
virReportOOMError();
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* No way to roll back if first disk succeeds but later disks
|
/* No way to roll back if first disk succeeds but later disks
|
||||||
* fail. Based on earlier qemuDomainSnapshotDiskPrepare, all
|
* fail, unless we have transaction support.
|
||||||
|
* Based on earlier qemuDomainSnapshotDiskPrepare, all
|
||||||
* disks in this list are now either SNAPSHOT_NO, or
|
* disks in this list are now either SNAPSHOT_NO, or
|
||||||
* SNAPSHOT_EXTERNAL with a valid file name and qcow2 format. */
|
* SNAPSHOT_EXTERNAL with a valid file name and qcow2 format. */
|
||||||
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
||||||
@ -10006,10 +10080,37 @@ qemuDomainSnapshotCreateDiskActive(virConnectPtr conn,
|
|||||||
ret = qemuDomainSnapshotCreateSingleDiskActive(driver, vm,
|
ret = qemuDomainSnapshotCreateSingleDiskActive(driver, vm,
|
||||||
&snap->def->disks[i],
|
&snap->def->disks[i],
|
||||||
vm->def->disks[i],
|
vm->def->disks[i],
|
||||||
persistDisk);
|
persistDisk, actions);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (actions) {
|
||||||
|
if (ret == 0)
|
||||||
|
ret = qemuMonitorTransaction(priv->mon, actions);
|
||||||
|
if (ret < 0) {
|
||||||
|
/* Transaction failed; undo the changes to vm. */
|
||||||
|
bool need_unlink = !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT);
|
||||||
|
while (--i >= 0) {
|
||||||
|
virDomainDiskDefPtr persistDisk = NULL;
|
||||||
|
|
||||||
|
if (snap->def->disks[i].snapshot == VIR_DOMAIN_DISK_SNAPSHOT_NO)
|
||||||
|
continue;
|
||||||
|
if (vm->newDef) {
|
||||||
|
int indx = virDomainDiskIndexByName(vm->newDef,
|
||||||
|
vm->def->disks[i]->dst,
|
||||||
|
false);
|
||||||
|
if (indx >= 0)
|
||||||
|
persistDisk = vm->newDef->disks[indx];
|
||||||
|
}
|
||||||
|
|
||||||
|
qemuDomainSnapshotUndoSingleDiskActive(driver, vm,
|
||||||
|
snap->def->dom->disks[i],
|
||||||
|
vm->def->disks[i],
|
||||||
|
persistDisk,
|
||||||
|
need_unlink);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -10043,7 +10144,8 @@ cleanup:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vm) {
|
if (vm && (ret == 0 ||
|
||||||
|
!qemuCapsGet(priv->qemuCaps, QEMU_CAPS_TRANSACTION))) {
|
||||||
if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0 ||
|
if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0 ||
|
||||||
(persist &&
|
(persist &&
|
||||||
virDomainSaveConfig(driver->configDir, vm->newDef) < 0))
|
virDomainSaveConfig(driver->configDir, vm->newDef) < 0))
|
||||||
|
Loading…
Reference in New Issue
Block a user