[libvirt PATCH 02/30] qemu_block: extract block commit code to separate function

Pavel Hrdina phrdina at redhat.com
Thu Dec 8 13:30:38 UTC 2022


Signed-off-by: Pavel Hrdina <phrdina at redhat.com>
---
 src/qemu/qemu_block.c  | 179 +++++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_block.h  |   9 +++
 src/qemu/qemu_driver.c | 162 +------------------------------------
 3 files changed, 189 insertions(+), 161 deletions(-)

diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c
index 8a6f601b29..4cca7555f3 100644
--- a/src/qemu/qemu_block.c
+++ b/src/qemu/qemu_block.c
@@ -3196,3 +3196,182 @@ qemuBlockExportAddNBD(virDomainObj *vm,
 
     return qemuMonitorBlockExportAdd(priv->mon, &nbdprops);
 }
+
+
+int
+qemuBlockCommit(virDomainObj *vm,
+                virDomainDiskDef *disk,
+                virStorageSource *baseSource,
+                virStorageSource *topSource,
+                virStorageSource *top_parent,
+                unsigned long bandwidth,
+                unsigned int flags)
+{
+    qemuDomainObjPrivate *priv = vm->privateData;
+    virQEMUDriver *driver = priv->driver;
+    int rc = -1;
+    bool clean_access = false;
+    g_autofree char *backingPath = NULL;
+    qemuBlockJobData *job = NULL;
+    g_autoptr(virStorageSource) mirror = NULL;
+
+    if (virDomainObjCheckActive(vm) < 0)
+        return -1;
+
+    /* Convert bandwidth MiB to bytes, if necessary */
+    if (!(flags & VIR_DOMAIN_BLOCK_COMMIT_BANDWIDTH_BYTES)) {
+        if (bandwidth > LLONG_MAX >> 20) {
+            virReportError(VIR_ERR_OVERFLOW,
+                           _("bandwidth must be less than %llu"),
+                           LLONG_MAX >> 20);
+            return -1;
+        }
+        bandwidth <<= 20;
+    }
+
+    if (!qemuDomainDiskBlockJobIsSupported(disk))
+        return -1;
+
+    if (virStorageSourceIsEmpty(disk->src)) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("disk %s has no source file to be committed"),
+                       disk->dst);
+        return -1;
+    }
+
+    if (qemuDomainDiskBlockJobIsActive(disk))
+        return -1;
+
+    if (qemuDomainSupportsCheckpointsBlockjobs(vm) < 0)
+        return -1;
+
+    if (topSource == disk->src) {
+        /* XXX Should we auto-pivot when COMMIT_ACTIVE is not specified? */
+        if (!(flags & VIR_DOMAIN_BLOCK_COMMIT_ACTIVE)) {
+            virReportError(VIR_ERR_INVALID_ARG,
+                           _("commit of '%s' active layer requires active flag"),
+                           disk->dst);
+            return -1;
+        }
+    } else if (flags & VIR_DOMAIN_BLOCK_COMMIT_ACTIVE) {
+        virReportError(VIR_ERR_INVALID_ARG,
+                       _("active commit requested but '%s' is not active"),
+                       topSource->path);
+        return -1;
+    }
+
+    if (!virStorageSourceHasBacking(topSource)) {
+        virReportError(VIR_ERR_INVALID_ARG,
+                       _("top '%s' in chain for '%s' has no backing file"),
+                       topSource->path, disk->src->path);
+        return -1;
+    }
+
+    if ((flags & VIR_DOMAIN_BLOCK_COMMIT_SHALLOW) &&
+        baseSource != topSource->backingStore) {
+        virReportError(VIR_ERR_INVALID_ARG,
+                       _("base '%s' is not immediately below '%s' in chain "
+                         "for '%s'"),
+                       baseSource->path, topSource->path, disk->src->path);
+        return -1;
+    }
+
+    /* For an active commit, clone enough of the base to act as the mirror */
+    if (topSource == disk->src) {
+        if (!(mirror = virStorageSourceCopy(baseSource, false)))
+            return -1;
+        if (virStorageSourceInitChainElement(mirror,
+                                             disk->src,
+                                             true) < 0)
+            return -1;
+    }
+
+    if (flags & VIR_DOMAIN_BLOCK_COMMIT_RELATIVE &&
+        topSource != disk->src) {
+        if (top_parent &&
+            qemuBlockUpdateRelativeBacking(vm, top_parent, disk->src) < 0)
+            return -1;
+
+        if (virStorageSourceGetRelativeBackingPath(topSource, baseSource,
+                                                   &backingPath) < 0)
+            return -1;
+
+        if (!backingPath) {
+            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                           _("can't keep relative backing relationship"));
+            return -1;
+        }
+    }
+
+    /* For the commit to succeed, we must allow qemu to open both the
+     * 'base' image and the parent of 'top' as read/write; 'top' might
+     * not have a parent, or might already be read-write.  XXX It
+     * would also be nice to revert 'base' to read-only, as well as
+     * revoke access to files removed from the chain, when the commit
+     * operation succeeds, but doing that requires tracking the
+     * operation in XML across libvirtd restarts.  */
+    clean_access = true;
+    if (qemuDomainStorageSourceAccessAllow(driver, vm, baseSource,
+                                           false, false, false) < 0)
+        goto error;
+
+    if (top_parent && top_parent != disk->src) {
+        /* While top_parent is topmost image, we don't need to remember its
+         * owner as it will be overwritten upon finishing the commit. Hence,
+         * pass chainTop = false. */
+        if (qemuDomainStorageSourceAccessAllow(driver, vm, top_parent,
+                                               false, false, false) < 0)
+            goto error;
+    }
+
+    if (!(job = qemuBlockJobDiskNewCommit(vm, disk, top_parent, topSource,
+                                          baseSource,
+                                          flags & VIR_DOMAIN_BLOCK_COMMIT_DELETE,
+                                          flags)))
+        goto error;
+
+    disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_NONE;
+
+    if (!backingPath && top_parent &&
+        !(backingPath = qemuBlockGetBackingStoreString(baseSource, false)))
+        goto error;
+
+    qemuDomainObjEnterMonitor(vm);
+
+    rc = qemuMonitorBlockCommit(priv->mon,
+                                qemuDomainDiskGetTopNodename(disk),
+                                job->name,
+                                topSource->nodeformat,
+                                baseSource->nodeformat,
+                                backingPath, bandwidth);
+
+    qemuDomainObjExitMonitor(vm);
+
+    if (rc < 0)
+        goto error;
+
+    if (mirror) {
+        disk->mirror = g_steal_pointer(&mirror);
+        disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_ACTIVE_COMMIT;
+    }
+    qemuBlockJobStarted(job, vm);
+
+    return 0;
+
+ error:
+    if (clean_access) {
+        virErrorPtr orig_err;
+        virErrorPreserveLast(&orig_err);
+        /* Revert access to read-only, if possible.  */
+        qemuDomainStorageSourceAccessAllow(driver, vm, baseSource,
+                                           true, false, false);
+        if (top_parent && top_parent != disk->src)
+            qemuDomainStorageSourceAccessAllow(driver, vm, top_parent,
+                                               true, false, false);
+
+        virErrorRestore(&orig_err);
+    }
+    qemuBlockJobStartupFinalize(vm, job);
+
+    return -1;
+}
diff --git a/src/qemu/qemu_block.h b/src/qemu/qemu_block.h
index 8a3a10344e..85b4805d89 100644
--- a/src/qemu/qemu_block.h
+++ b/src/qemu/qemu_block.h
@@ -276,3 +276,12 @@ qemuBlockExportAddNBD(virDomainObj *vm,
                       const char *exportname,
                       bool writable,
                       const char *bitmap);
+
+int
+qemuBlockCommit(virDomainObj *vm,
+                virDomainDiskDef *disk,
+                virStorageSource *baseSource,
+                virStorageSource *topSource,
+                virStorageSource *top_parent,
+                unsigned long bandwidth,
+                unsigned int flags);
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index d509582719..2f05da3d8c 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -15114,19 +15114,12 @@ qemuDomainBlockCommit(virDomainPtr dom,
                       unsigned long bandwidth,
                       unsigned int flags)
 {
-    virQEMUDriver *driver = dom->conn->privateData;
-    qemuDomainObjPrivate *priv;
     virDomainObj *vm = NULL;
     int ret = -1;
     virDomainDiskDef *disk = NULL;
     virStorageSource *topSource;
     virStorageSource *baseSource = NULL;
     virStorageSource *top_parent = NULL;
-    bool clean_access = false;
-    g_autofree char *backingPath = NULL;
-    unsigned long long speed = bandwidth;
-    qemuBlockJobData *job = NULL;
-    g_autoptr(virStorageSource) mirror = NULL;
 
     virCheckFlags(VIR_DOMAIN_BLOCK_COMMIT_SHALLOW |
                   VIR_DOMAIN_BLOCK_COMMIT_ACTIVE |
@@ -15136,7 +15129,6 @@ qemuDomainBlockCommit(virDomainPtr dom,
 
     if (!(vm = qemuDomainObjFromDomain(dom)))
         goto cleanup;
-    priv = vm->privateData;
 
     if (virDomainBlockCommitEnsureACL(dom->conn, vm->def) < 0)
         goto cleanup;
@@ -15144,176 +15136,24 @@ qemuDomainBlockCommit(virDomainPtr dom,
     if (virDomainObjBeginJob(vm, VIR_JOB_MODIFY) < 0)
         goto cleanup;
 
-    if (virDomainObjCheckActive(vm) < 0)
-        goto endjob;
-
-    /* Convert bandwidth MiB to bytes, if necessary */
-    if (!(flags & VIR_DOMAIN_BLOCK_COMMIT_BANDWIDTH_BYTES)) {
-        if (speed > LLONG_MAX >> 20) {
-            virReportError(VIR_ERR_OVERFLOW,
-                           _("bandwidth must be less than %llu"),
-                           LLONG_MAX >> 20);
-            goto endjob;
-        }
-        speed <<= 20;
-    }
-
     if (!(disk = qemuDomainDiskByName(vm->def, path)))
         goto endjob;
 
-    if (!qemuDomainDiskBlockJobIsSupported(disk))
-        goto endjob;
-
-    if (virStorageSourceIsEmpty(disk->src)) {
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                       _("disk %s has no source file to be committed"),
-                       disk->dst);
-        goto endjob;
-    }
-
-    if (qemuDomainDiskBlockJobIsActive(disk))
-        goto endjob;
-
-    if (qemuDomainSupportsCheckpointsBlockjobs(vm) < 0)
-        goto endjob;
-
     if (!top || STREQ(top, disk->dst))
         topSource = disk->src;
     else if (!(topSource = virStorageSourceChainLookup(disk->src, NULL, top,
                                                        disk->dst, &top_parent)))
         goto endjob;
 
-    if (topSource == disk->src) {
-        /* XXX Should we auto-pivot when COMMIT_ACTIVE is not specified? */
-        if (!(flags & VIR_DOMAIN_BLOCK_COMMIT_ACTIVE)) {
-            virReportError(VIR_ERR_INVALID_ARG,
-                           _("commit of '%s' active layer requires active flag"),
-                           disk->dst);
-            goto endjob;
-        }
-    } else if (flags & VIR_DOMAIN_BLOCK_COMMIT_ACTIVE) {
-        virReportError(VIR_ERR_INVALID_ARG,
-                       _("active commit requested but '%s' is not active"),
-                       topSource->path);
-        goto endjob;
-    }
-
-    if (!virStorageSourceHasBacking(topSource)) {
-        virReportError(VIR_ERR_INVALID_ARG,
-                       _("top '%s' in chain for '%s' has no backing file"),
-                       topSource->path, path);
-        goto endjob;
-    }
-
     if (!base && (flags & VIR_DOMAIN_BLOCK_COMMIT_SHALLOW))
         baseSource = topSource->backingStore;
     else if (!(baseSource = virStorageSourceChainLookup(disk->src, topSource,
                                                         base, disk->dst, NULL)))
         goto endjob;
 
-    if ((flags & VIR_DOMAIN_BLOCK_COMMIT_SHALLOW) &&
-        baseSource != topSource->backingStore) {
-        virReportError(VIR_ERR_INVALID_ARG,
-                       _("base '%s' is not immediately below '%s' in chain "
-                         "for '%s'"),
-                       base, topSource->path, path);
-        goto endjob;
-    }
-
-    /* For an active commit, clone enough of the base to act as the mirror */
-    if (topSource == disk->src) {
-        if (!(mirror = virStorageSourceCopy(baseSource, false)))
-            goto endjob;
-        if (virStorageSourceInitChainElement(mirror,
-                                             disk->src,
-                                             true) < 0)
-            goto endjob;
-    }
-
-    if (flags & VIR_DOMAIN_BLOCK_COMMIT_RELATIVE &&
-        topSource != disk->src) {
-        if (top_parent &&
-            qemuBlockUpdateRelativeBacking(vm, top_parent, disk->src) < 0)
-            goto endjob;
-
-        if (virStorageSourceGetRelativeBackingPath(topSource, baseSource,
-                                                   &backingPath) < 0)
-            goto endjob;
-
-        if (!backingPath) {
-            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
-                           _("can't keep relative backing relationship"));
-            goto endjob;
-        }
-    }
-
-    /* For the commit to succeed, we must allow qemu to open both the
-     * 'base' image and the parent of 'top' as read/write; 'top' might
-     * not have a parent, or might already be read-write.  XXX It
-     * would also be nice to revert 'base' to read-only, as well as
-     * revoke access to files removed from the chain, when the commit
-     * operation succeeds, but doing that requires tracking the
-     * operation in XML across libvirtd restarts.  */
-    clean_access = true;
-    if (qemuDomainStorageSourceAccessAllow(driver, vm, baseSource,
-                                           false, false, false) < 0)
-        goto endjob;
-
-    if (top_parent && top_parent != disk->src) {
-        /* While top_parent is topmost image, we don't need to remember its
-         * owner as it will be overwritten upon finishing the commit. Hence,
-         * pass chainTop = false. */
-        if (qemuDomainStorageSourceAccessAllow(driver, vm, top_parent,
-                                               false, false, false) < 0)
-            goto endjob;
-    }
-
-    if (!(job = qemuBlockJobDiskNewCommit(vm, disk, top_parent, topSource,
-                                          baseSource,
-                                          flags & VIR_DOMAIN_BLOCK_COMMIT_DELETE,
-                                          flags)))
-        goto endjob;
-
-    disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_NONE;
-
-    if (!backingPath && top_parent &&
-        !(backingPath = qemuBlockGetBackingStoreString(baseSource, false)))
-        goto endjob;
-
-    qemuDomainObjEnterMonitor(vm);
-
-    ret = qemuMonitorBlockCommit(priv->mon,
-                                 qemuDomainDiskGetTopNodename(disk),
-                                 job->name,
-                                 topSource->nodeformat,
-                                 baseSource->nodeformat,
-                                 backingPath, speed);
-
-    qemuDomainObjExitMonitor(vm);
-
-    if (ret < 0)
-        goto endjob;
-
-    if (mirror) {
-        disk->mirror = g_steal_pointer(&mirror);
-        disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_ACTIVE_COMMIT;
-    }
-    qemuBlockJobStarted(job, vm);
+    ret = qemuBlockCommit(vm, disk, baseSource, topSource, top_parent, bandwidth, flags);
 
  endjob:
-    if (ret < 0 && clean_access) {
-        virErrorPtr orig_err;
-        virErrorPreserveLast(&orig_err);
-        /* Revert access to read-only, if possible.  */
-        qemuDomainStorageSourceAccessAllow(driver, vm, baseSource,
-                                           true, false, false);
-        if (top_parent && top_parent != disk->src)
-            qemuDomainStorageSourceAccessAllow(driver, vm, top_parent,
-                                               true, false, false);
-
-        virErrorRestore(&orig_err);
-    }
-    qemuBlockJobStartupFinalize(vm, job);
     virDomainObjEndJob(vm);
 
  cleanup:
-- 
2.38.1



More information about the libvir-list mailing list