9119d9
From abecf1fdcf58796b048eeaa6ccecc39f19ffdbcd Mon Sep 17 00:00:00 2001
9119d9
Message-Id: <abecf1fdcf58796b048eeaa6ccecc39f19ffdbcd@dist-git>
9119d9
From: Pavel Hrdina <phrdina@redhat.com>
9119d9
Date: Wed, 14 Jan 2015 13:38:27 +0100
9119d9
Subject: [PATCH] qemu_process: detect updated video ram size values from QEMU
9119d9
9119d9
QEMU internally updates the size of video memory if the domain XML had
9119d9
provided too low memory size or there are some dependencies for a QXL
9119d9
devices 'vgamem' and 'ram' size. We need to know about the changes and
9119d9
store them into the status XML to not break migration or managedsave
9119d9
through different libvirt versions.
9119d9
9119d9
The values would be loaded only if the "vgamem_mb" property exists for
9119d9
the device.  The presence of the "vgamem_mb" also tells that the
9119d9
"ram_size" and "vram_size" exists for QXL devices.
9119d9
9119d9
Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
9119d9
(cherry picked from commit ce745914b33e3f9a136d91655600b931e7a4178f)
9119d9
9119d9
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1180574
9119d9
9119d9
Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
9119d9
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
9119d9
---
9119d9
 src/qemu/qemu_monitor.c      | 34 ++++++++++++++++++
9119d9
 src/qemu/qemu_monitor.h      |  4 +++
9119d9
 src/qemu/qemu_monitor_json.c | 69 ++++++++++++++++++++++++++++++++++++
9119d9
 src/qemu/qemu_monitor_json.h |  3 ++
9119d9
 src/qemu/qemu_process.c      | 83 ++++++++++++++++++++++++++++++++++++++++++++
9119d9
 5 files changed, 193 insertions(+)
9119d9
9119d9
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
9119d9
index df7bb45..0b1b80e 100644
9119d9
--- a/src/qemu/qemu_monitor.c
9119d9
+++ b/src/qemu/qemu_monitor.c
9119d9
@@ -1158,6 +1158,40 @@ qemuMonitorFindBalloonObjectPath(qemuMonitorPtr mon,
9119d9
     return ret;
9119d9
 }
9119d9
 
9119d9
+
9119d9
+/**
9119d9
+ * To update video memory size in status XML we need to load correct values from
9119d9
+ * QEMU.  This is supported only with JSON monitor.
9119d9
+ *
9119d9
+ * Returns 0 on success, -1 on failure and sets proper error message.
9119d9
+ */
9119d9
+int
9119d9
+qemuMonitorUpdateVideoMemorySize(qemuMonitorPtr mon,
9119d9
+                                 virDomainVideoDefPtr video,
9119d9
+                                 const char *videoName)
9119d9
+{
9119d9
+    int ret = -1;
9119d9
+    char *path = NULL;
9119d9
+
9119d9
+    if (mon->json) {
9119d9
+        ret = qemuMonitorFindObjectPath(mon, "/", videoName, &path);
9119d9
+        if (ret < 0) {
9119d9
+            if (ret == -2)
9119d9
+                virReportError(VIR_ERR_INTERNAL_ERROR,
9119d9
+                               _("Failed to find QOM Object path for "
9119d9
+                                 "device '%s'"), videoName);
9119d9
+            return -1;
9119d9
+        }
9119d9
+
9119d9
+        ret = qemuMonitorJSONUpdateVideoMemorySize(mon, video, path);
9119d9
+        VIR_FREE(path);
9119d9
+        return ret;
9119d9
+    }
9119d9
+
9119d9
+    return 0;
9119d9
+}
9119d9
+
9119d9
+
9119d9
 int qemuMonitorHMPCommandWithFd(qemuMonitorPtr mon,
9119d9
                                 const char *cmd,
9119d9
                                 int scm_fd,
9119d9
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
9119d9
index b08d74d..8930744 100644
9119d9
--- a/src/qemu/qemu_monitor.h
9119d9
+++ b/src/qemu/qemu_monitor.h
9119d9
@@ -243,6 +243,10 @@ virJSONValuePtr qemuMonitorGetOptions(qemuMonitorPtr mon)
9119d9
     ATTRIBUTE_NONNULL(1);
9119d9
 void qemuMonitorSetOptions(qemuMonitorPtr mon, virJSONValuePtr options)
9119d9
     ATTRIBUTE_NONNULL(1);
9119d9
+int qemuMonitorUpdateVideoMemorySize(qemuMonitorPtr mon,
9119d9
+                                     virDomainVideoDefPtr video,
9119d9
+                                     const char *videName)
9119d9
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
9119d9
 int qemuMonitorHMPCommandWithFd(qemuMonitorPtr mon,
9119d9
                                 const char *cmd,
9119d9
                                 int scm_fd,
9119d9
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
9119d9
index 97151dc..9b3d17a 100644
9119d9
--- a/src/qemu/qemu_monitor_json.c
9119d9
+++ b/src/qemu/qemu_monitor_json.c
9119d9
@@ -1443,6 +1443,75 @@ int qemuMonitorJSONGetVirtType(qemuMonitorPtr mon,
9119d9
 }
9119d9
 
9119d9
 
9119d9
+/**
9119d9
+ * Loads correct video memory size values from QEMU and update the video
9119d9
+ * definition.
9119d9
+ *
9119d9
+ * Return 0 on success, -1 on failure and set proper error message.
9119d9
+ */
9119d9
+int
9119d9
+qemuMonitorJSONUpdateVideoMemorySize(qemuMonitorPtr mon,
9119d9
+                                     virDomainVideoDefPtr video,
9119d9
+                                     char *path)
9119d9
+{
9119d9
+    qemuMonitorJSONObjectProperty prop = {
9119d9
+        QEMU_MONITOR_OBJECT_PROPERTY_ULONG,
9119d9
+        {0}
9119d9
+    };
9119d9
+
9119d9
+    switch (video->type) {
9119d9
+    case VIR_DOMAIN_VIDEO_TYPE_VGA:
9119d9
+        if (qemuMonitorJSONGetObjectProperty(mon, path, "vgamem_mb", &prop) < 0) {
9119d9
+            virReportError(VIR_ERR_INTERNAL_ERROR,
9119d9
+                           _("QOM Objext '%s' has no property 'vgamem_mb'"),
9119d9
+                           path);
9119d9
+            return -1;
9119d9
+        }
9119d9
+        video->vram = prop.val.ul * 1024;
9119d9
+        break;
9119d9
+    case VIR_DOMAIN_VIDEO_TYPE_QXL:
9119d9
+        if (qemuMonitorJSONGetObjectProperty(mon, path, "vram_size", &prop) < 0) {
9119d9
+            virReportError(VIR_ERR_INTERNAL_ERROR,
9119d9
+                           _("QOM Objext '%s' has no property 'vram_size'"),
9119d9
+                           path);
9119d9
+            return -1;
9119d9
+        }
9119d9
+        video->vram = prop.val.ul / 1024;
9119d9
+        if (qemuMonitorJSONGetObjectProperty(mon, path, "ram_size", &prop) < 0) {
9119d9
+            virReportError(VIR_ERR_INTERNAL_ERROR,
9119d9
+                           _("QOM Objext '%s' has no property 'ram_size'"),
9119d9
+                           path);
9119d9
+            return -1;
9119d9
+        }
9119d9
+        video->ram = prop.val.ul / 1024;
9119d9
+        if (qemuMonitorJSONGetObjectProperty(mon, path, "vgamem_mb", &prop) < 0) {
9119d9
+            virReportError(VIR_ERR_INTERNAL_ERROR,
9119d9
+                           _("QOM Objext '%s' has no property 'vgamem_mb'"),
9119d9
+                           path);
9119d9
+            return -1;
9119d9
+        }
9119d9
+        video->vgamem = prop.val.ul * 1024;
9119d9
+        break;
9119d9
+    case VIR_DOMAIN_VIDEO_TYPE_VMVGA:
9119d9
+        if (qemuMonitorJSONGetObjectProperty(mon, path, "vgamem_mb", &prop) < 0) {
9119d9
+            virReportError(VIR_ERR_INTERNAL_ERROR,
9119d9
+                           _("QOM Objext '%s' has no property 'vgamem_mb'"),
9119d9
+                           path);
9119d9
+            return -1;
9119d9
+        }
9119d9
+        video->vram = prop.val.ul * 1024;
9119d9
+        break;
9119d9
+    case VIR_DOMAIN_VIDEO_TYPE_CIRRUS:
9119d9
+    case VIR_DOMAIN_VIDEO_TYPE_XEN:
9119d9
+    case VIR_DOMAIN_VIDEO_TYPE_VBOX:
9119d9
+    case VIR_DOMAIN_VIDEO_TYPE_LAST:
9119d9
+        break;
9119d9
+    }
9119d9
+
9119d9
+    return 0;
9119d9
+}
9119d9
+
9119d9
+
9119d9
 /*
9119d9
  * Returns: 0 if balloon not supported, +1 if balloon query worked
9119d9
  * or -1 on failure
9119d9
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
9119d9
index d039991..ff20029 100644
9119d9
--- a/src/qemu/qemu_monitor_json.h
9119d9
+++ b/src/qemu/qemu_monitor_json.h
9119d9
@@ -57,6 +57,9 @@ int qemuMonitorJSONGetCPUInfo(qemuMonitorPtr mon,
9119d9
                               int **pids);
9119d9
 int qemuMonitorJSONGetVirtType(qemuMonitorPtr mon,
9119d9
                                int *virtType);
9119d9
+int qemuMonitorJSONUpdateVideoMemorySize(qemuMonitorPtr mon,
9119d9
+                                         virDomainVideoDefPtr video,
9119d9
+                                         char *path);
9119d9
 int qemuMonitorJSONGetBalloonInfo(qemuMonitorPtr mon,
9119d9
                                   unsigned long long *currmem);
9119d9
 int qemuMonitorJSONGetMemoryStats(qemuMonitorPtr mon,
9119d9
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
9119d9
index d7b2688..d965938 100644
9119d9
--- a/src/qemu/qemu_process.c
9119d9
+++ b/src/qemu/qemu_process.c
9119d9
@@ -3032,6 +3032,85 @@ qemuProcessCleanupChardevDevice(virDomainDefPtr def ATTRIBUTE_UNUSED,
9119d9
 }
9119d9
 
9119d9
 
9119d9
+/**
9119d9
+ * Loads and update video memory size for video devices according to QEMU
9119d9
+ * process as the QEMU will silently update the values that we pass to QEMU
9119d9
+ * through command line.  We need to load these updated values and store them
9119d9
+ * into the status XML.
9119d9
+ *
9119d9
+ * We will fail if for some reason the values cannot be loaded from QEMU because
9119d9
+ * its mandatory to get the correct video memory size to status XML to not break
9119d9
+ * migration.
9119d9
+ */
9119d9
+static int
9119d9
+qemuProcessUpdateVideoRamSize(virQEMUDriverPtr driver,
9119d9
+                              virDomainObjPtr vm,
9119d9
+                              int asyncJob)
9119d9
+{
9119d9
+    int ret = -1;
9119d9
+    ssize_t i;
9119d9
+    qemuDomainObjPrivatePtr priv = vm->privateData;
9119d9
+    virDomainVideoDefPtr video = NULL;
9119d9
+    virQEMUDriverConfigPtr cfg = NULL;
9119d9
+
9119d9
+    if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
9119d9
+        return -1;
9119d9
+
9119d9
+    for (i = 0; i < vm->def->nvideos; i++) {
9119d9
+        video = vm->def->videos[i];
9119d9
+
9119d9
+        switch (video->type) {
9119d9
+        case VIR_DOMAIN_VIDEO_TYPE_VGA:
9119d9
+            if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VGA_VGAMEM)) {
9119d9
+                if (qemuMonitorUpdateVideoMemorySize(priv->mon, video, "VGA") < 0)
9119d9
+                    goto error;
9119d9
+            }
9119d9
+            break;
9119d9
+        case VIR_DOMAIN_VIDEO_TYPE_QXL:
9119d9
+            if (i == 0) {
9119d9
+                if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_QXL_VGA_VGAMEM)) {
9119d9
+                    if (qemuMonitorUpdateVideoMemorySize(priv->mon, video,
9119d9
+                                                         "qxl-vga") < 0)
9119d9
+                        goto error;
9119d9
+                }
9119d9
+            } else {
9119d9
+                if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_QXL_VGAMEM)) {
9119d9
+                    if (qemuMonitorUpdateVideoMemorySize(priv->mon, video,
9119d9
+                                                         "qxl") < 0)
9119d9
+                        goto error;
9119d9
+                }
9119d9
+            }
9119d9
+            break;
9119d9
+        case VIR_DOMAIN_VIDEO_TYPE_VMVGA:
9119d9
+            if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VMWARE_SVGA_VGAMEM)) {
9119d9
+                if (qemuMonitorUpdateVideoMemorySize(priv->mon, video,
9119d9
+                                                     "vmware-svga") < 0)
9119d9
+                    goto error;
9119d9
+            }
9119d9
+            break;
9119d9
+        case VIR_DOMAIN_VIDEO_TYPE_CIRRUS:
9119d9
+        case VIR_DOMAIN_VIDEO_TYPE_XEN:
9119d9
+        case VIR_DOMAIN_VIDEO_TYPE_VBOX:
9119d9
+        case VIR_DOMAIN_VIDEO_TYPE_LAST:
9119d9
+            break;
9119d9
+        }
9119d9
+
9119d9
+    }
9119d9
+
9119d9
+    qemuDomainObjExitMonitor(driver, vm);
9119d9
+
9119d9
+    cfg = virQEMUDriverGetConfig(driver);
9119d9
+    ret = virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm);
9119d9
+    virObjectUnref(cfg);
9119d9
+
9119d9
+    return ret;
9119d9
+
9119d9
+ error:
9119d9
+    qemuDomainObjExitMonitor(driver, vm);
9119d9
+    return -1;
9119d9
+}
9119d9
+
9119d9
+
9119d9
 struct qemuProcessHookData {
9119d9
     virConnectPtr conn;
9119d9
     virDomainObjPtr vm;
9119d9
@@ -4795,6 +4874,10 @@ int qemuProcessStart(virConnectPtr conn,
9119d9
     }
9119d9
     qemuDomainObjExitMonitor(driver, vm);
9119d9
 
9119d9
+    VIR_DEBUG("Detecting actual memory size for video device");
9119d9
+    if (qemuProcessUpdateVideoRamSize(driver, vm, asyncJob) < 0)
9119d9
+        goto cleanup;
9119d9
+
9119d9
     if (!(flags & VIR_QEMU_PROCESS_START_PAUSED)) {
9119d9
         VIR_DEBUG("Starting domain CPUs");
9119d9
         /* Allow the CPUS to start executing */
9119d9
-- 
9119d9
2.2.1
9119d9