Patch adds backup of active domains to files and block devices. Option to specify backup file format is available. --- Using blockjob flag is not complete consistent - on libvirt crash/restart the flag will be lost. However this is not the problem of this particular patch or place. src/conf/backup_conf.c | 35 +++++++++++++ src/conf/backup_conf.h | 4 ++ src/libvirt_private.syms | 2 + src/qemu/qemu_domain.c | 14 +++++ src/qemu/qemu_domain.h | 2 + src/qemu/qemu_driver.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 186 insertions(+) diff --git a/src/conf/backup_conf.c b/src/conf/backup_conf.c index f8111e9..b1203b5 100644 --- a/src/conf/backup_conf.c +++ b/src/conf/backup_conf.c @@ -257,3 +257,38 @@ virDomainBackupDefFree(virDomainBackupDefPtr def) VIR_FREE(def); } + +int +virDomainBackupDefCheckDisks(virDomainBackupDefPtr def, + virDomainDefPtr vmdef) +{ + int ret = -1; + virBitmapPtr map = NULL; + size_t i; + + if (!(map = virBitmapNew(vmdef->ndisks))) + return -1; + + for (i = 0; i < def->ndisks; i++) { + virDomainBackupDiskDefPtr disk = &def->disks[i]; + int idx = virDomainDiskIndexByName(vmdef, disk->name, false); + + if (idx < 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("no disk named '%s'"), disk->name); + goto cleanup; + } + + if (virBitmapIsBitSet(map, idx)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("disk '%s' specified twice"), disk->name); + goto cleanup; + } + ignore_value(virBitmapSetBit(map, idx)); + } + ret = 0; + + cleanup: + virBitmapFree(map); + return ret; +} diff --git a/src/conf/backup_conf.h b/src/conf/backup_conf.h index 223fc19..d99926b 100644 --- a/src/conf/backup_conf.h +++ b/src/conf/backup_conf.h @@ -62,4 +62,8 @@ virDomainBackupDefParseNode(xmlDocPtr xml, void virDomainBackupDefFree(virDomainBackupDefPtr def); +int +virDomainBackupDefCheckDisks(virDomainBackupDefPtr def, + virDomainDefPtr vmdef); + #endif /* __BACKUP_CONF_H */ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index beeee9b..046941f 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -43,6 +43,7 @@ virAccessPermStorageVolTypeToString; # conf/backup_conf.h +virDomainBackupDefCheckDisks; virDomainBackupDefFree; virDomainBackupDefParseNode; virDomainBackupDefParseString; @@ -1015,6 +1016,7 @@ virDomainClass; virDomainSnapshotClass; virGetConnect; virGetDomain; +virGetDomainBackup; virGetDomainSnapshot; virGetInterface; virGetNetwork; diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 8cba755..55dba34 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -6428,6 +6428,20 @@ qemuDomainDiskByName(virDomainDefPtr def, } +virDomainDiskDefPtr +qemuDomainDiskByNameChecked(virDomainDefPtr def, + const char *name) +{ + int idx = virDomainDiskIndexByName(def, name, false); + if (idx < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, _("no disk named '%s'"), name); + return NULL; + } + + return def->disks[idx]; +} + + /** * qemuDomainDefValidateDiskLunSource: * @src: disk source struct diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 2ee1829..1b5a21b 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -700,6 +700,8 @@ int qemuDomainSetPrivatePaths(virQEMUDriverPtr driver, void qemuDomainClearPrivatePaths(virDomainObjPtr vm); virDomainDiskDefPtr qemuDomainDiskByName(virDomainDefPtr def, const char *name); +virDomainDiskDefPtr qemuDomainDiskByNameChecked(virDomainDefPtr def, + const char *name); char *qemuDomainGetMasterKeyFilePath(const char *libDir); diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 38c8414..35f5b65 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -20261,6 +20261,134 @@ qemuDomainSetGuestVcpus(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 (virDomainBackupDefCheckDisks(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; + const char *format_str = NULL; + + if (!(disk = qemuDomainDiskByNameChecked(vm->def, def->disks[i].name))) + goto cleanup; + + 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; + } else if (target->type == VIR_STORAGE_TYPE_BLOCK) { + int format = target->format ? target->format : disk->src->format; + + /* qemu itself does not make this check */ + if (format != VIR_STORAGE_FILE_RAW) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("disk '%s' backup to block device is only" + " possible in raw format"), + def->disks[i].name); + 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++) { + virDomainDiskDefPtr disk; + /* NULL is internal error, that is a bug, at least we get it in log */ + if (!(disk = qemuDomainDiskByNameChecked(vm->def, def->disks[i].name))) + continue; + + QEMU_DOMAIN_DISK_PRIVATE(disk)->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 */ @@ -20474,6 +20602,7 @@ static virHypervisorDriver qemuHypervisorDriver = { .domainMigrateStartPostCopy = qemuDomainMigrateStartPostCopy, /* 1.3.3 */ .domainGetGuestVcpus = qemuDomainGetGuestVcpus, /* 2.0.0 */ .domainSetGuestVcpus = qemuDomainSetGuestVcpus, /* 2.0.0 */ + .domainBackupCreateXML = qemuDomainBackupCreateXML, /* 2.5.0 */ }; -- 1.8.3.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list