On Fri, Apr 10, 2015 at 14:59:03 +0200, Ján Tomko wrote:
The blockdev-snapshot-sync command only takes a format
but does not allow specifying the compat level or other features
that should be used.
Pre-create the qcow2 file ourselves and tell qemu to reuse it.
Note: the default compat level for qemu (and thus external snapshot
creation) is now 1.10 but libvirt's storage driver still uses 0.10.
After this patch, 0.10 will be the default for both.
---
src/qemu/qemu_driver.c | 11 ++++++++
src/storage/storage_backend.c | 66 +++++++++++++++++++++++++++++++++++++++++++
src/storage/storage_backend.h | 5 ++++
src/storage/storage_driver.c | 27 ++++++++++++++++++
src/storage/storage_driver.h | 4 +++
5 files changed, 113 insertions(+)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 921417c..4f14546 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -14073,6 +14073,7 @@ qemuDomainSnapshotCreateSingleDiskActive(virQEMUDriverPtr
driver,
char *device = NULL;
char *source = NULL;
const char *formatStr = NULL;
+ const char *qemuImgPath = NULL;
int ret = -1, rc;
bool need_unlink = false;
@@ -14082,6 +14083,9 @@ qemuDomainSnapshotCreateSingleDiskActive(virQEMUDriverPtr
driver,
return -1;
}
+ if (!(qemuImgPath = qemuFindQemuImgBinary(driver)))
+ goto cleanup;
+
if (virAsprintf(&device, "drive-%s", disk->info.alias) < 0)
goto cleanup;
@@ -14114,6 +14118,13 @@ qemuDomainSnapshotCreateSingleDiskActive(virQEMUDriverPtr
driver,
goto cleanup;
}
need_unlink = true;
+ if (newDiskSrc->format == VIR_STORAGE_FILE_QCOW2) {
+ rc = virStorageFileCreateWithFormat(newDiskSrc,
+ source,
+ disk->src,
+ qemuImgPath);
+ reuse = true;
+ }
Since this step is way more prone to fail compared to the existing
pre-creation step (that is used just to allow labeling the file before
passing it to qemu) I'd rather see this happen prior to actually
starting to take the snapshot (at this point, the memory was already
snapshotted and the VM is possibly paused, so if this takes a long time
or fails we would waste the memory snapshot).
}
/* set correct security, cgroup and locking options on the new image */
diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c
index 4ecea88..9ffbc6e 100644
--- a/src/storage/storage_backend.c
+++ b/src/storage/storage_backend.c
@@ -1079,6 +1079,72 @@ virStorageBackendCreateQemuImgCmdFromVol(virConnectPtr conn,
return cmd;
}
+
+/* Create a qemu-img virCommand from the supplied binary path,
+ * StorageSource and path (translated for network drives
+ * supported by qemu-img)
+ */
+static virCommandPtr
+virStorageBackendCreateQemuImgCmdFromSource(virStorageSourcePtr src,
+ const char *path,
+ virStorageSourcePtr backingSrc,
+ const char *create_tool)
+{
+ virCommandPtr cmd = NULL;
+ struct _virStorageBackendQemuImgInfo info = {
+ .format = src->format,
+ .path = path,
+ .encryption = NULL,
+ .preallocate = false,
+ .compat = src->compat,
+ .features = src->features,
+ .nocow = src->nocow,
+ };
+ char *tmpstr = NULL;
+
+ info.backingFormat = backingSrc->format;
+ info.backingPath = backingSrc->path;
This definitely is not enough to pass the backing source path. Once you
have a network path you need a lot of the fields virStorageSource
structure to format the path since it needs to format the
qemu-compatible backing string.
A better way will be to format the string from backingSrc right at this
point to the qemu source string and use that.
Additionally, you'll also need
+
+ if (!(tmpstr = virBitmapFormat(info.features)))
+ return NULL;
+
+ VIR_DEBUG("creating file via qemu_img: format %s path %s compat %s features
%s",
+ virStorageFileFormatTypeToString(info.format),
+ info.path, info.compat, tmpstr);
+ VIR_DEBUG("... backing format %s backing path %s",
+ virStorageFileFormatTypeToString(info.backingFormat),
+ info.backingPath);
+
+ cmd = virStorageBackendCreateQemuImgCmd(create_tool,
+ QEMU_IMG_BACKING_FORMAT_OPTIONS_COMPAT,
+ info);
+ return cmd;
+}
+
+
+int
+virStorageBackendCreateQemuImgFileFromSource(virStorageSourcePtr src,
+ const char *path,
Since you already are passing @src, there should be no need to use
@path.
Additionally since @path contains authentication data for some protocols
we should not pass it to commands that would show in the process list
with the arguments. (We already do that when starting the VM. I have it on
my todo list)
+ virStorageSourcePtr
backingSrc,
+ const char *create_tool)
+{
+ int ret = -1;
+ virCommandPtr cmd = NULL;
+
+ cmd = virStorageBackendCreateQemuImgCmdFromSource(src, path, backingSrc,
+ create_tool);
+ if (!cmd)
+ goto cleanup;
+
+ if (virCommandRun(cmd, NULL) < 0)
+ goto cleanup;
+
+ ret = 0;
+ cleanup:
+ return ret;
+}
+
+
static int
virStorageBackendCreateQemuImg(virConnectPtr conn,
virStoragePoolObjPtr pool,
diff --git a/src/storage/storage_backend.h b/src/storage/storage_backend.h
index bb1e8d8..c591845 100644
--- a/src/storage/storage_backend.h
+++ b/src/storage/storage_backend.h
@@ -249,6 +249,11 @@ virStorageFileBackendPtr virStorageFileBackendForType(int type, int
protocol);
virStorageFileBackendPtr virStorageFileBackendForTypeInternal(int type,
int protocol,
bool report);
+int
+virStorageBackendCreateQemuImgFileFromSource(virStorageSourcePtr src,
+ const char *path,
+ virStorageSourcePtr backingSrc,
+ const char *create_tool);
struct _virStorageFileBackend {
diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c
index 551a0ca..162e065 100644
--- a/src/storage/storage_driver.c
+++ b/src/storage/storage_driver.c
@@ -2725,6 +2725,33 @@ virStorageFileCreate(virStorageSourcePtr src)
return ret;
}
+/**
+ * virStorageFileCreate: Creates a storage file stub with the specified
+ * format
+ *
+ * @src: file structure pointing to the file
+ * @path: path to the file
+ * @backingSrc: file structure pointing to the backing file
+ * @create_tool: path to qemu-img
+ *
+ * Returns 0 on success, -2 if the function isn't supported by the backend,
+ * -1 on other failure. Errno is set in case of failure.
+ */
+int virStorageFileCreateWithFormat(virStorageSourcePtr src,
+ const char *path,
+ virStorageSourcePtr backingSrc,
+ const char *create_tool)
+{
+ if (!virStorageFileIsInitialized(src) ||
+ !src->drv->backend->storageFileCreate) {
+ errno = ENOSYS;
This check doesn't make sense since storageFileCreate is not used. The
function that calls qemu-img should make sure that qemu-img actually is
able to create the file.
+ return -2;
+ }
+
+ return virStorageBackendCreateQemuImgFileFromSource(src, path, backingSrc,
+ create_tool);
+}
+
/**
* virStorageFileUnlink: Unlink storage file via storage driver
Peter