[libvirt] [RFC PATCH 07/10] qemu: add qemuDomainBackupCreateXML implementation

Nikolay Shirokovskiy nshirokovskiy at virtuozzo.com
Mon Nov 14 07:14:59 UTC 2016


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




More information about the libvir-list mailing list