These helpers add infrastructure which simplifies adding and rolling
back virStorageSources to a running qemu instance. Using of the helper
structure and separate functions allows for a much cleaner code in the
section dealing with the monitor.
Signed-off-by: Peter Krempa <pkrempa(a)redhat.com>
---
src/qemu/qemu_block.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_block.h | 34 +++++++++++
2 files changed, 189 insertions(+)
diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c
index a514e8a055..09437cdb40 100644
--- a/src/qemu/qemu_block.c
+++ b/src/qemu/qemu_block.c
@@ -1467,3 +1467,158 @@ qemuBlockStorageSourceGetBlockdevProps(virStorageSourcePtr src)
virJSONValueFree(props);
return ret;
}
+
+
+void
+qemuBlockStorageSourceAttachDataFree(qemuBlockStorageSourceAttachDataPtr data)
+{
+ if (!data)
+ return;
+
+ virJSONValueFree(data->storageProps);
+ virJSONValueFree(data->formatProps);
+ VIR_FREE(data);
+}
+
+
+/**
+ * qemuBlockStorageSourceAttachPrepareBlockdev:
+ * @src: storage source to prepare data from
+ *
+ * Creates a qemuBlockStorageSourceAttachData structure containing data to attach
+ * @src to a VM using the blockdev-add approach. Note that this function only
+ * creates the data for the storage source itself, any other related
+ * authentication/encryption/... objects need to be prepared separately.
+ *
+ * The changes are then applied using qemuBlockStorageSourceAttachApply.
+ *
+ * Returns the filled data structure on success or NULL on error and a libvirt
+ * error is reported
+ */
+qemuBlockStorageSourceAttachDataPtr
+qemuBlockStorageSourceAttachPrepareBlockdev(virStorageSourcePtr src)
+{
+ qemuBlockStorageSourceAttachDataPtr data;
+ qemuBlockStorageSourceAttachDataPtr ret = NULL;
+
+ if (VIR_ALLOC(data) < 0)
+ return NULL;
+
+ if (!(data->formatProps = qemuBlockStorageSourceGetBlockdevProps(src)) ||
+ !(data->storageProps = qemuBlockStorageSourceGetBackendProps(src, false)))
+ goto cleanup;
+
+ data->storageNodeName = src->nodestorage;
+ data->formatNodeName = src->nodeformat;
+
+ VIR_STEAL_PTR(ret, data);
+
+ cleanup:
+ qemuBlockStorageSourceAttachDataFree(data);
+ return ret;
+}
+
+
+/**
+ * qemuBlockStorageSourceAttachApply:
+ * @mon: monitor object
+ * @data: structure holding data of block device to apply
+ *
+ * Attaches a virStorageSource definition converted to
+ * qemuBlockStorageSourceAttachData to a running VM. This function expects being
+ * called after the monitor was entered.
+ *
+ * Returns 0 on success and -1 on error with a libvirt error reported. If an
+ * error occured, changes which were already applied need to be rolled back by
+ * calling qemuBlockStorageSourceAttachRollback.
+ */
+int
+qemuBlockStorageSourceAttachApply(qemuMonitorPtr mon,
+ qemuBlockStorageSourceAttachDataPtr data)
+{
+ int rv;
+
+ if (data->storageProps) {
+ rv = qemuMonitorBlockdevAdd(mon, data->storageProps);
+ data->storageProps = NULL;
+
+ if (rv < 0)
+ return -1;
+
+ data->storageAttached = true;
+ }
+
+ if (data->formatProps) {
+ rv = qemuMonitorBlockdevAdd(mon, data->formatProps);
+ data->formatProps = NULL;
+
+ if (rv < 0)
+ return -1;
+
+ data->formatAttached = true;
+ }
+
+ return 0;
+}
+
+
+/**
+ * qemuBlockStorageSourceAttachRollback:
+ * @mon: monitor object
+ * @data: structure holding data of block device to roll back
+ *
+ * Attempts a best effort rollback of changes which were made to a running VM by
+ * qemuBlockStorageSourceAttachApply. Preserves any existing errors.
+ *
+ * This function expects being called after the monitor was entered.
+ */
+void
+qemuBlockStorageSourceAttachRollback(qemuMonitorPtr mon,
+ qemuBlockStorageSourceAttachDataPtr data)
+{
+ virErrorPtr orig_err;
+
+ virErrorPreserveLast(&orig_err);
+
+ if (data->formatAttached)
+ ignore_value(qemuMonitorBlockdevDel(mon, data->formatNodeName));
+
+ if (data->storageAttached)
+ ignore_value(qemuMonitorBlockdevDel(mon, data->storageNodeName));
+
+ virErrorRestore(&orig_err);
+}
+
+
+/**
+ * qemuBlockStorageSourceDetachOneBlockdev:
+ * @driver: qemu driver object
+ * @vm: domain object
+ * @asyncJob: currently running async job
+ * @src: storage source to detach
+ *
+ * Detaches one virStorageSource using blockdev-del. Note that this does not
+ * detach any authentication/encryption objects. This function enters the
+ * monitor internally.
+ */
+int
+qemuBlockStorageSourceDetachOneBlockdev(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ qemuDomainAsyncJob asyncJob,
+ virStorageSourcePtr src)
+{
+ int ret;
+
+ if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
+ return -1;
+
+ ret = qemuMonitorBlockdevDel(qemuDomainGetMonitor(vm), src->nodeformat);
+
+ if (ret == 0)
+ ret = qemuMonitorBlockdevDel(qemuDomainGetMonitor(vm), src->nodestorage);
+
+ if (qemuDomainObjExitMonitor(driver, vm) < 0)
+ return -1;
+
+ return ret;
+}
diff --git a/src/qemu/qemu_block.h b/src/qemu/qemu_block.h
index f819c6f907..bbaf9ec0f1 100644
--- a/src/qemu/qemu_block.h
+++ b/src/qemu/qemu_block.h
@@ -67,4 +67,38 @@ qemuBlockStorageSourceGetURI(virStorageSourcePtr src);
virJSONValuePtr
qemuBlockStorageSourceGetBlockdevProps(virStorageSourcePtr src);
+
+typedef struct qemuBlockStorageSourceAttachData qemuBlockStorageSourceAttachData;
+typedef qemuBlockStorageSourceAttachData *qemuBlockStorageSourceAttachDataPtr;
+struct qemuBlockStorageSourceAttachData {
+ virJSONValuePtr storageProps;
+ const char *storageNodeName;
+ bool storageAttached;
+
+ virJSONValuePtr formatProps;
+ const char *formatNodeName;
+ bool formatAttached;
+};
+
+
+void
+qemuBlockStorageSourceAttachDataFree(qemuBlockStorageSourceAttachDataPtr data);
+
+qemuBlockStorageSourceAttachDataPtr
+qemuBlockStorageSourceAttachPrepareBlockdev(virStorageSourcePtr src);
+
+int
+qemuBlockStorageSourceAttachApply(qemuMonitorPtr mon,
+ qemuBlockStorageSourceAttachDataPtr data);
+
+void
+qemuBlockStorageSourceAttachRollback(qemuMonitorPtr mon,
+ qemuBlockStorageSourceAttachDataPtr data);
+
+int
+qemuBlockStorageSourceDetachOneBlockdev(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ qemuDomainAsyncJob asyncJob,
+ virStorageSourcePtr src);
+
#endif /* __QEMU_BLOCK_H__ */
--
2.16.2