commit 4357b2699104b3058c08af6e94b113e69701d3c2
Author: Adam Litke <agl(a)us.ibm.com>
Date: Wed Nov 3 13:40:53 2010 -0500
stream-qemu-support
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index dbde9e7..f712917 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -13143,6 +13143,79 @@ cleanup:
return ret;
}
+static unsigned long long
+qemudDomainStreamDisk (virDomainPtr dom, const char *path,
+ unsigned long long offset, unsigned int flags)
+{
+ struct qemud_driver *driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ unsigned long long ret = -1;
+
+ qemuDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ qemuDriverUnlock(driver);
+
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(dom->uuid, uuidstr);
+ qemuReportError(VIR_ERR_NO_DOMAIN,
+ _("no domain with matching uuid '%s'"),
uuidstr);
+ goto cleanup;
+ }
+
+ if (virDomainObjIsActive(vm)) {
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ qemuDomainObjEnterMonitor(vm);
+ ret = qemuMonitorStreamDisk(priv->mon, path, offset, flags);
+ qemuDomainObjExitMonitor(vm);
+ } else {
+ qemuReportError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("domain is not running"));
+ }
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return ret;
+}
+
+static int
+qemudDomainStreamDiskInfo (virDomainPtr dom, virStreamDiskStatePtr infos,
+ unsigned int nr_infos,
+ unsigned int flags ATTRIBUTE_UNUSED)
+{
+ struct qemud_driver *driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ unsigned int ret = -1;
+
+ qemuDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ qemuDriverUnlock(driver);
+
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(dom->uuid, uuidstr);
+ qemuReportError(VIR_ERR_NO_DOMAIN,
+ _("no domain with matching uuid '%s'"),
uuidstr);
+ goto cleanup;
+ }
+
+ if (virDomainObjIsActive(vm)) {
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ qemuDomainObjEnterMonitor(vm);
+ ret = qemuMonitorStreamDiskInfo(priv->mon, infos, nr_infos);
+ qemuDomainObjExitMonitor(vm);
+ } else {
+ qemuReportError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("domain is not running"));
+ }
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return ret;
+}
+
static int qemuDomainMonitorCommand(virDomainPtr domain, const char *cmd,
char **result, unsigned int flags)
{
@@ -13298,8 +13371,8 @@ static virDriver qemuDriver = {
qemuDomainMonitorCommand, /* qemuDomainMonitorCommand */
qemuDomainSetMemoryParameters, /* domainSetMemoryParameters */
qemuDomainGetMemoryParameters, /* domainGetMemoryParameters */
- NULL, /* domainStreamDisk */
- NULL, /* domainStreamDiskInfo */
+ qemudDomainStreamDisk, /* domainStreamDisk */
+ qemudDomainStreamDiskInfo, /* domainStreamDiskInfo */
};
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 2366fdb..5535703 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -1917,6 +1917,49 @@ int qemuMonitorDeleteSnapshot(qemuMonitorPtr mon, const char
*name)
return ret;
}
+unsigned long long
+qemuMonitorStreamDisk(qemuMonitorPtr mon, const char *path,
+ unsigned long long offset, unsigned int flags)
+{
+ unsigned long long ret;
+
+ DEBUG("mon=%p, path=%p, offset=%llu, flags=%u", mon, path, offset, flags);
+
+ if (!mon) {
+ qemuReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("monitor must not be NULL"));
+ return -1;
+ }
+
+ if (mon->json)
+ //ret = qemuMonitorJSONStreamDisk(mon, path, offset, flags);
+ ret = -1;
+ else
+ ret = qemuMonitorTextStreamDisk(mon, path, offset, flags);
+ return ret;
+}
+
+int qemuMonitorStreamDiskInfo(qemuMonitorPtr mon, virStreamDiskStatePtr infos,
+ unsigned int nr_infos)
+{
+ int ret;
+
+ DEBUG("mon=%p, infos=%p, nr_infos=%u", mon, infos, nr_infos);
+
+ if (!mon) {
+ qemuReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("monitor must not be NULL"));
+ return -1;
+ }
+
+ if (mon->json)
+ //ret = qemuMonitorJSONStreamDiskInfo(mon, infos, nr_infos);
+ ret = -1;
+ else
+ ret = qemuMonitorTextStreamDiskInfo(mon, infos, nr_infos);
+ return ret;
+}
+
int qemuMonitorArbitraryCommand(qemuMonitorPtr mon, const char *cmd, char **reply)
{
int ret;
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 7d09145..344fe06 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -389,6 +389,12 @@ int qemuMonitorCreateSnapshot(qemuMonitorPtr mon, const char *name);
int qemuMonitorLoadSnapshot(qemuMonitorPtr mon, const char *name);
int qemuMonitorDeleteSnapshot(qemuMonitorPtr mon, const char *name);
+unsigned long long
+qemuMonitorStreamDisk(qemuMonitorPtr mon, const char *path,
+ unsigned long long offset, unsigned int flags);
+int qemuMonitorStreamDiskInfo(qemuMonitorPtr mon, virStreamDiskStatePtr infos,
+ unsigned int nr_infos);
+
int qemuMonitorArbitraryCommand(qemuMonitorPtr mon, const char *cmd, char **reply);
/**
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
index d7e128c..8f6ec2f 100644
--- a/src/qemu/qemu_monitor_text.c
+++ b/src/qemu/qemu_monitor_text.c
@@ -2569,6 +2569,159 @@ cleanup:
return ret;
}
+static int qemuMonitorParseStreamInfo(char *text,
+ virStreamDiskStatePtr info)
+{
+ char *p;
+ unsigned long long data;
+ unsigned int device_len;
+
+ memset(info->path, 0, VIR_STREAM_PATH_BUFLEN);
+ info->offset = 0;
+ info->size = 0;
+
+ if (strstr(text, "Device '") && strstr(text, "' not
found")) {
+ qemuReportError(VIR_ERR_OPERATION_INVALID, "%s", _("Device not
found"));
+ return -1;
+ }
+
+ if (strstr(text, "expects a sector size less than device length")) {
+ qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("Offset parameter is greater than the device
size"));
+ return -1;
+ }
+
+ if (strstr(text, "Device '") && strstr(text, "' is in
use")) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
+ _("Another streaming operation is in progress"));
+ return -1;
+ }
+
+ if (strstr(text, "No active stream") || STREQ(text, ""))
+ return 0;
+
+ if ((text = STRSKIP(text, "Streaming device ")) == NULL)
+ return -1;
+
+ /* Parse the device path */
+ p = strstr(text, ": Completed ");
+ if (!p)
+ return -1;
+
+ device_len = (unsigned int)(p - text);
+ if (device_len >= VIR_STREAM_PATH_BUFLEN) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
+ "Device name is too long");
+ return -1;
+ }
+
+ if (sprintf((char *)&info->path, "%.*s", device_len, text) < 0)
{
+ qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
+ "Unable to store device name");
+ return -1;
+ }
+ text = p + 12; /* Skip over ": Completed " */
+
+ /* Parse the current sector offset */
+ if (virStrToLong_ull (text, &p, 10, &data))
+ return -1;
+ info->offset = (size_t) data;
+ text = p;
+
+ /* Parse the total number of sectors */
+ if (!STRPREFIX(text, " of "))
+ return -1;
+ text += 4;
+ if (virStrToLong_ull (text, &p, 10, &data))
+ return -1;
+ info->size = (size_t) data;
+ text = p;
+
+ /* Verify the ending */
+ if (!STRPREFIX(text, " sectors"))
+ return -1;
+
+ return 1;
+}
+
+unsigned long long
+qemuMonitorTextStreamDisk(qemuMonitorPtr mon, const char *path,
+ unsigned long long offset, unsigned int flags)
+{
+ char *cmd;
+ char *reply = NULL;
+ int rc;
+ unsigned long long ret = -1;
+ virStreamDiskState info;
+
+ if (flags == VIR_STREAM_DISK_FULL)
+ rc = virAsprintf(&cmd, "stream_all %s", path);
+ else if (flags == VIR_STREAM_DISK_ONE)
+ rc = virAsprintf(&cmd, "stream %s %llu", path, offset);
+ else {
+ qemuReportError(VIR_ERR_OPERATION_INVALID, "%s%u",
+ _("invalid value for flags: "), flags);
+ return -1;
+ }
+
+ if (rc < 0) {
+ virReportOOMError();
+ return -1;
+ }
+
+ if (qemuMonitorCommand(mon, cmd, &reply)) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED,
+ _("failed to perform stream command '%s'"),
+ cmd);
+ goto cleanup;
+ }
+
+ rc = qemuMonitorParseStreamInfo(reply, &info);
+ if (rc == 0 && flags == VIR_STREAM_DISK_FULL)
+ ret = 0; /* No output means the stream started successfully */
+ if (rc == 1 && flags == VIR_STREAM_DISK_ONE)
+ ret = info.offset;
+
+cleanup:
+ VIR_FREE(cmd);
+ VIR_FREE(reply);
+ return ret;
+}
+
+int qemuMonitorTextStreamDiskInfo(qemuMonitorPtr mon,
+ virStreamDiskStatePtr infos,
+ unsigned int nr_infos)
+{
+ char *cmd;
+ char *reply = NULL;
+ int ret = -1;
+
+ /* Qemu only supports one stream at a time */
+ nr_infos = 1;
+
+ if (virAsprintf(&cmd, "info stream") < 0) {
+ virReportOOMError();
+ return -1;
+ }
+
+ if (qemuMonitorCommand(mon, cmd, &reply)) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED,
+ _("failed to perform stream command '%s'"),
+ cmd);
+ goto cleanup;
+ }
+
+ ret = qemuMonitorParseStreamInfo(reply, infos);
+ if (ret == -1)
+ qemuReportError(VIR_ERR_OPERATION_FAILED,
+ _("Failed to parse monitor output: '%s'"),
reply);
+
+cleanup:
+ VIR_FREE(cmd);
+ VIR_FREE(reply);
+ return ret;
+}
+
int qemuMonitorTextArbitraryCommand(qemuMonitorPtr mon, const char *cmd,
char **reply)
{
diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h
index c017509..80923f3 100644
--- a/src/qemu/qemu_monitor_text.h
+++ b/src/qemu/qemu_monitor_text.h
@@ -194,6 +194,14 @@ int qemuMonitorTextCreateSnapshot(qemuMonitorPtr mon, const char
*name);
int qemuMonitorTextLoadSnapshot(qemuMonitorPtr mon, const char *name);
int qemuMonitorTextDeleteSnapshot(qemuMonitorPtr mon, const char *name);
+unsigned long long
+qemuMonitorTextStreamDisk(qemuMonitorPtr mon, const char *path,
+ unsigned long long offset, unsigned int flags);
+int qemuMonitorTextStreamDiskInfo(qemuMonitorPtr mon,
+ virStreamDiskStatePtr infos,
+ unsigned int nr_infos);
+
+
int qemuMonitorTextArbitraryCommand(qemuMonitorPtr mon, const char *cmd,
char **reply);
--
Thanks,
Adam