Supported options - backup to file or block device - specify format of backup --- src/conf/backup_conf.c | 32 ++++++++++++++ src/conf/backup_conf.h | 5 +++ src/libvirt_private.syms | 1 + src/qemu/qemu_driver.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 149 insertions(+), 1 deletion(-) diff --git a/src/conf/backup_conf.c b/src/conf/backup_conf.c index a5bd995..49f1370 100644 --- a/src/conf/backup_conf.c +++ b/src/conf/backup_conf.c @@ -265,3 +265,35 @@ virDomainBackupDefFree(virDomainBackupDefPtr def) VIR_FREE(def); } + + +int +virDomainBackupDefResolveDisks(virDomainBackupDefPtr def, + virDomainDefPtr vmdef) +{ + int ret = -1; + size_t i, j; + + for (i = 0; i < def->ndisks; i++) { + virDomainBackupDiskDefPtr disk = &def->disks[i]; + + for (j = 0; j < i; j++) { + if (STREQ(def->disks[j].name, disk->name)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("disk '%s' specified twice"), disk->name); + goto cleanup; + } + } + + if (!(disk->vmdisk = virDomainDiskByName(vmdef, disk->name, false))) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("no disk named '%s'"), disk->name); + goto cleanup; + } + } + + ret = 0; + + cleanup: + return ret; +} diff --git a/src/conf/backup_conf.h b/src/conf/backup_conf.h index 6f689e3..ae7411e 100644 --- a/src/conf/backup_conf.h +++ b/src/conf/backup_conf.h @@ -33,6 +33,7 @@ typedef virDomainBackupDiskDef *virDomainBackupDiskDefPtr; struct _virDomainBackupDiskDef { char *name; /* name matching the <target dev='...' of the domain */ virStorageSourcePtr target; + virDomainDiskDefPtr vmdisk; }; /* Stores the complete backup metadata */ @@ -62,4 +63,8 @@ virDomainBackupDefParseNode(xmlDocPtr xml, void virDomainBackupDefFree(virDomainBackupDefPtr def); +int +virDomainBackupDefResolveDisks(virDomainBackupDefPtr def, + virDomainDefPtr vmdef); + #endif /* __BACKUP_CONF_H */ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index e2ffc91..e788b3c 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -46,6 +46,7 @@ virAccessPermStorageVolTypeToString; virDomainBackupDefFree; virDomainBackupDefParseNode; virDomainBackupDefParseString; +virDomainBackupDefResolveDisks; # conf/capabilities.h diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index a5c664e..91bad28 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -20449,6 +20449,115 @@ qemuDomainSetBlockThreshold(virDomainPtr dom, } +static virDomainBackupPtr +qemuDomainBackupCreateXML(virDomainPtr domain, + const char *xmlDesc, + unsigned int flags) +{ + virQEMUDriverPtr driver = domain->conn->privateData; + qemuDomainObjPrivatePtr priv; + virDomainBackupDefPtr def = NULL; + virDomainBackupPtr backup = NULL; + virDomainBackupPtr ret = NULL; + virJSONValuePtr actions = NULL; + virDomainObjPtr vm = NULL; + char *path = NULL, *device = NULL; + bool job = false; + int rc; + size_t i; + + virCheckFlags(0, NULL); + + if (!(vm = qemuDomObjFromDomain(domain))) + goto cleanup; + + if (virDomainBackupCreateXMLEnsureACL(domain->conn, vm->def) < 0) + goto cleanup; + + if (!(def = virDomainBackupDefParseString(xmlDesc, NULL, NULL, 0))) + goto cleanup; + + if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0) + goto cleanup; + job = true; + + if (!virDomainObjIsActive(vm)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + "%s", _("backing up inactive domains is not supported")); + goto cleanup; + } + + if (virDomainBackupDefResolveDisks(def, vm->def) < 0) + goto cleanup; + + if (!(actions = virJSONValueNewArray())) + goto cleanup; + + for (i = 0; i < def->ndisks; i++) { + virStorageSourcePtr target = def->disks[i].target; + virDomainDiskDefPtr disk = def->disks[i].vmdisk; + const char *format_str = NULL; + + if (target->type != VIR_STORAGE_TYPE_FILE && + target->type != VIR_STORAGE_TYPE_BLOCK) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("disk '%s' backup type '%s' is not supported"), + def->disks[i].name, + virStorageTypeToString(target->type)); + goto cleanup; + } + + if (qemuDomainDiskBlockJobIsActive(disk)) + goto cleanup; + + if (qemuGetDriveSourceString(target, NULL, &path) < 0) + goto cleanup; + + if (!(device = qemuAliasFromDisk(disk))) + goto cleanup; + + if (target->format) + format_str = virStorageFileFormatTypeToString(target->format); + + if (qemuMonitorDriveBackup(actions, device, path, NULL, format_str, 0, + false) < 0) + goto cleanup; + + VIR_FREE(path); + VIR_FREE(device); + } + + priv = vm->privateData; + if (!(backup = virGetDomainBackup(domain, def->name))) + goto cleanup; + + qemuDomainObjEnterMonitor(driver, vm); + rc = qemuMonitorTransaction(priv->mon, actions); + if (qemuDomainObjExitMonitor(driver, vm) < 0 || rc < 0) + goto cleanup; + + ret = backup; + backup = NULL; + + for (i = 0; i < def->ndisks; i++) + QEMU_DOMAIN_DISK_PRIVATE(def->disks->vmdisk)->blockjob = true; + + cleanup: + if (job) + qemuDomainObjEndJob(driver, vm); + + VIR_FREE(path); + VIR_FREE(device); + + virDomainBackupDefFree(def); + virJSONValueFree(actions); + virDomainObjEndAPI(&vm); + virObjectUnref(backup); + + return ret; +} + + static virHypervisorDriver qemuHypervisorDriver = { .name = QEMU_DRIVER_NAME, .connectOpen = qemuConnectOpen, /* 0.2.0 */ @@ -20663,7 +20772,8 @@ static virHypervisorDriver qemuHypervisorDriver = { .domainGetGuestVcpus = qemuDomainGetGuestVcpus, /* 2.0.0 */ .domainSetGuestVcpus = qemuDomainSetGuestVcpus, /* 2.0.0 */ .domainSetVcpu = qemuDomainSetVcpu, /* 3.1.0 */ - .domainSetBlockThreshold = qemuDomainSetBlockThreshold /* 3.2.0 */ + .domainSetBlockThreshold = qemuDomainSetBlockThreshold, /* 3.2.0 */ + .domainBackupCreateXML = qemuDomainBackupCreateXML, /* 3.4.0 */ }; -- 1.8.3.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list