From 4f81919ad256f5c3f17ff3c93fb96a0bd8032948 Mon Sep 17 00:00:00 2001
From: "Daniel P. Berrange" <berrange@redhat.com>
Date: Mon, 12 Apr 2010 12:31:15 +0100
Subject: [PATCH] Fix QEMU memory stats JSON mode

The QEMU driver is mistakenly calling directly into the text
mode monitor for the domain memory stats query.

* src/qemu/qemu_driver.c: Replace qemuMonitorTextGetMemoryStats with
  qemuMonitorGetMemoryStats
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add the new
  wrapper for qemuMonitorGetMemoryStats
* src/qemu/qemu_monitor_json.c, src/qemu/qemu_monitor_json.h: Add
  qemuMonitorJSONGetMemoryStats implementation
---
 src/qemu/qemu_driver.c       |   3 +-
 src/qemu/qemu_monitor.c      |  15 +++++
 src/qemu/qemu_monitor.h      |   3 +
 src/qemu/qemu_monitor_json.c | 115 +++++++++++++++++++++++++++++++++++
 src/qemu/qemu_monitor_json.h |   3 +
 5 files changed, 137 insertions(+), 2 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index f6fdb280f5..0189dcf010 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -60,7 +60,6 @@
 #include "qemu_driver.h"
 #include "qemu_conf.h"
 #include "qemu_monitor.h"
-#include "qemu_monitor_text.h"
 #include "qemu_bridge_filter.h"
 #include "c-ctype.h"
 #include "event.h"
@@ -8699,7 +8698,7 @@ qemudDomainMemoryStats (virDomainPtr dom,
     if (virDomainObjIsActive(vm)) {
         qemuDomainObjPrivatePtr priv = vm->privateData;
         qemuDomainObjEnterMonitor(vm);
-        ret = qemuMonitorTextGetMemoryStats(priv->mon, stats, nr_stats);
+        ret = qemuMonitorGetMemoryStats(priv->mon, stats, nr_stats);
         qemuDomainObjExitMonitor(vm);
     } else {
         qemuReportError(VIR_ERR_OPERATION_INVALID,
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 01e3a464f3..20eaa1165b 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -960,6 +960,21 @@ int qemuMonitorGetBalloonInfo(qemuMonitorPtr mon,
 }
 
 
+int qemuMonitorGetMemoryStats(qemuMonitorPtr mon,
+                              virDomainMemoryStatPtr stats,
+                              unsigned int nr_stats)
+{
+    int ret;
+    DEBUG("mon=%p, fd=%d stats=%p nstats=%u", mon, mon->fd, stats, nr_stats);
+
+    if (mon->json)
+        ret = qemuMonitorJSONGetMemoryStats(mon, stats, nr_stats);
+    else
+        ret = qemuMonitorTextGetMemoryStats(mon, stats, nr_stats);
+    return ret;
+}
+
+
 int qemuMonitorGetBlockStatsInfo(qemuMonitorPtr mon,
                                  const char *devname,
                                  long long *rd_req,
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 21b8989c0b..8410b022f7 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -172,6 +172,9 @@ int qemuMonitorGetCPUInfo(qemuMonitorPtr mon,
                           int **pids);
 int qemuMonitorGetBalloonInfo(qemuMonitorPtr mon,
                               unsigned long *currmem);
+int qemuMonitorGetMemoryStats(qemuMonitorPtr mon,
+                              virDomainMemoryStatPtr stats,
+                              unsigned int nr_stats);
 int qemuMonitorGetBlockStatsInfo(qemuMonitorPtr mon,
                                  const char *devname,
                                  long long *rd_req,
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 29042017ba..0f64ea748c 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -886,6 +886,121 @@ cleanup:
 }
 
 
+int qemuMonitorJSONGetMemoryStats(qemuMonitorPtr mon,
+                                  virDomainMemoryStatPtr stats,
+                                  unsigned int nr_stats)
+{
+    int ret;
+    int got = 0;
+    virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-balloon",
+                                                     NULL);
+    virJSONValuePtr reply = NULL;
+
+    if (!cmd)
+        return -1;
+
+    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+    if (ret == 0) {
+        /* See if balloon soft-failed */
+        if (qemuMonitorJSONHasError(reply, "DeviceNotActive") ||
+            qemuMonitorJSONHasError(reply, "KVMMissingCap"))
+            goto cleanup;
+
+        /* See if any other fatal error occurred */
+        ret = qemuMonitorJSONCheckError(cmd, reply);
+
+        /* Success */
+        if (ret == 0) {
+            virJSONValuePtr data;
+            unsigned long long mem;
+
+            if (!(data = virJSONValueObjectGet(reply, "return"))) {
+                qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                                _("info balloon reply was missing return data"));
+                ret = -1;
+                goto cleanup;
+            }
+
+            if (virJSONValueObjectHasKey(data, "mem_swapped_in") && (got < nr_stats)) {
+                if (virJSONValueObjectGetNumberUlong(data, "mem_swapped_in", &mem) < 0) {
+                    qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                                    _("info balloon reply was missing balloon mem_swapped_in"));
+                    ret = -1;
+                    goto cleanup;
+                }
+                stats[got].tag = VIR_DOMAIN_MEMORY_STAT_SWAP_IN;
+                stats[got].val = (mem/1024);
+                got++;
+            }
+            if (virJSONValueObjectHasKey(data, "mem_swapped_out") && (got < nr_stats)) {
+                if (virJSONValueObjectGetNumberUlong(data, "mem_swapped_out", &mem) < 0) {
+                    qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                                    _("info balloon reply was missing balloon mem_swapped_out"));
+                    ret = -1;
+                    goto cleanup;
+                }
+                stats[got].tag = VIR_DOMAIN_MEMORY_STAT_SWAP_OUT;
+                stats[got].val = (mem/1024);
+                got++;
+            }
+            if (virJSONValueObjectHasKey(data, "major_page_faults") && (got < nr_stats)) {
+                if (virJSONValueObjectGetNumberUlong(data, "major_page_faults", &mem) < 0) {
+                    qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                                    _("info balloon reply was missing balloon major_page_faults"));
+                    ret = -1;
+                    goto cleanup;
+                }
+                stats[got].tag = VIR_DOMAIN_MEMORY_STAT_MAJOR_FAULT;
+                stats[got].val = mem;
+                got++;
+            }
+            if (virJSONValueObjectHasKey(data, "minor_page_faults") && (got < nr_stats)) {
+                if (virJSONValueObjectGetNumberUlong(data, "minor_page_faults", &mem) < 0) {
+                    qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                                    _("info balloon reply was missing balloon minor_page_faults"));
+                    ret = -1;
+                    goto cleanup;
+                }
+                stats[got].tag = VIR_DOMAIN_MEMORY_STAT_MINOR_FAULT;
+                stats[got].val = mem;
+                got++;
+            }
+            if (virJSONValueObjectHasKey(data, "free_mem") && (got < nr_stats)) {
+                if (virJSONValueObjectGetNumberUlong(data, "free_mem", &mem) < 0) {
+                    qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                                    _("info balloon reply was missing balloon free_mem"));
+                    ret = -1;
+                    goto cleanup;
+                }
+                stats[got].tag = VIR_DOMAIN_MEMORY_STAT_UNUSED;
+                stats[got].val = (mem/1024);
+                got++;
+            }
+            if (virJSONValueObjectHasKey(data, "total_mem") && (got < nr_stats)) {
+                if (virJSONValueObjectGetNumberUlong(data, "total_mem", &mem) < 0) {
+                    qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                                    _("info balloon reply was missing balloon total_mem"));
+                    ret = -1;
+                    goto cleanup;
+                }
+                stats[got].tag = VIR_DOMAIN_MEMORY_STAT_AVAILABLE;
+                stats[got].val = (mem/1024);
+                got++;
+            }
+        }
+    }
+
+    if (got > 0)
+        ret = got;
+
+cleanup:
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+}
+
+
 int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
                                      const char *devname,
                                      long long *rd_req,
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index e7baf8489f..53d374e5ab 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -46,6 +46,9 @@ int qemuMonitorJSONGetCPUInfo(qemuMonitorPtr mon,
                               int **pids);
 int qemuMonitorJSONGetBalloonInfo(qemuMonitorPtr mon,
                                   unsigned long *currmem);
+int qemuMonitorJSONGetMemoryStats(qemuMonitorPtr mon,
+                                  virDomainMemoryStatPtr stats,
+                                  unsigned int nr_stats);
 int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
                                      const char *devname,
                                      long long *rd_req,