Patchwork [RFC,v2,21/21] Implement mem_increase, mem_decrease hmp/qmp commands

login
register
mail settings
Submitter Vasilis Liaskovitis
Date July 11, 2012, 10:32 a.m.
Message ID <1342002726-18258-22-git-send-email-vasilis.liaskovitis@profitbricks.com>
Download mbox | patch
Permalink /patch/170448/
State New
Headers show

Comments

Vasilis Liaskovitis - July 11, 2012, 10:32 a.m.
This implements batch monitor operations for hot-add and hot-remove. These are
probably better suited for a higher-level management layer, but are useful for
testing. Let me know if there is interest for such commands upstream.

syntax: mem_increase poolid num
will hotplug num dimms from pool poolid. This starts from lowest unpopulated
physical memory (dimm) and trying to cover any existing physical holes.

syntax: mem_decrease poolid num
will hot-unplug num dimms from pool poolid, This starts from highest populated
physical memory (dimm).

Respective qmp commands are "mem-increase", "mem-decrease".

Signed-off-by: Vasilis Liaskovitis <vasilis.liaskovitis@profitbricks.com>
---
 hmp-commands.hx |   31 ++++++++++++++++
 hw/dimm.c       |  104 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/dimm.h       |    7 ++++
 monitor.c       |   10 +++++
 monitor.h       |    2 +
 qmp-commands.hx |   40 +++++++++++++++++++++
 6 files changed, 194 insertions(+), 0 deletions(-)

Patch

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 016062e..e0c1cf4 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -648,6 +648,37 @@  STEXI
 
 Hot-add dimm.
 ETEXI
+    {
+        .name       = "mem_increase",
+        .args_type  = "pfx:s,num:s",
+        .params     = "pfx num",
+        .help       = "hot-plug num dimms of memory pool pfx",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_dimm_add_range,
+    },
+
+STEXI
+@item mem_increase @var{config}
+@findex mem_increase
+
+Hotplug dimms.
+ETEXI
+
+    {
+        .name       = "mem_decrease",
+        .args_type  = "pfx:s,num:s",
+        .params     = "pfx num",
+        .help       = "hot-unplug num dimms of memory pool pfx",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_dimm_del_range,
+    },
+
+STEXI
+@item mem_decrease @var{config}
+@findex mem_decrease
+
+Hot-unplug dimms.
+ETEXI
 
     {
         .name       = "device_del",
diff --git a/hw/dimm.c b/hw/dimm.c
index b544173..48542ba 100644
--- a/hw/dimm.c
+++ b/hw/dimm.c
@@ -166,6 +166,110 @@  int dimm_do(Monitor *mon, const QDict *qdict, bool add)
     return 0;
 }
 
+/* Find for dimm_do_range operation
+    DIMM_MIN_UNPOPULATED: used for finding next DIMM to hotplug
+    DIMM_MAX_POPULATED: used for finding next DIMM for hot-unplug
+ */
+
+DimmState *dimm_find_next(char *pfx, uint32_t mode)
+{
+    DeviceState *dev;
+    DimmState *slot, *ret;
+    const char *type;
+    uint32_t idx;
+
+    Error *err = NULL;
+    BusChild *kid;
+    BusState *bus = sysbus_get_default();
+    ret = NULL;
+
+    if (mode == DIMM_MIN_UNPOPULATED)
+        idx =  MAX_DIMMS;
+    else if (mode == DIMM_MAX_POPULATED)
+        idx = 0;
+    else
+        return false;
+
+    QTAILQ_FOREACH(kid, &bus->children, sibling) {
+        dev = kid->child;
+        type = object_property_get_str(OBJECT(dev), "type", &err);
+        if (err) {
+            error_free(err);
+            fprintf(stderr, "error getting device type\n");
+            exit(1);
+        }
+
+        if (!strcmp(type, "dimm")) {
+            slot = DIMM(dev);
+            if (strstr(dev->id, pfx) && strcmp(dev->id, pfx)) {
+                if (mode == DIMM_MIN_UNPOPULATED &&
+                        (slot->populated == false) &&
+                        (slot->pending == false) &&
+                        (idx > slot->idx)) {
+                    idx = slot->idx;
+                    ret = slot;
+                }
+                else if (mode == DIMM_MAX_POPULATED &&
+                        (slot->populated == true) &&
+                        (slot->pending == false) &&
+                        (idx <= slot->idx)) {
+                    idx = slot->idx;
+                    ret = slot;
+                }
+            }
+        }
+    }
+    return ret;
+}
+
+int dimm_do_range(Monitor *mon, const QDict *qdict, bool add)
+{
+    DimmState *slot = NULL;
+    uint32_t mode;
+    uint32_t idx;
+    int num, ndimms;
+
+    char *pfx = (char*) qdict_get_try_str(qdict, "pfx");
+    if (!pfx) {
+        fprintf(stderr, "ERROR %s invalid pfx\n",__FUNCTION__);
+        return 1;
+    }
+
+    char *value = (char*) qdict_get_try_str(qdict, "num");
+    if (!value) {
+        fprintf(stderr, "ERROR %s invalid pfx\n",__FUNCTION__);
+        return 1;
+    }
+    num = atoi(value);
+
+    if (add)
+        mode = DIMM_MIN_UNPOPULATED;
+    else
+        mode = DIMM_MAX_POPULATED;
+
+    ndimms = 0;
+    while (ndimms < num) {
+        slot = dimm_find_next(pfx, mode);
+        if (slot == NULL) {
+            fprintf(stderr, "%s no further slot found for pool %s\n",
+                    __FUNCTION__, pfx);
+            fprintf(stderr, "%s operated on %d / %d requested dimms\n",
+                    __FUNCTION__, ndimms, num);
+            return 1;
+        }
+
+        if (add) {
+            dimm_activate(slot);
+        }
+        else {
+            dimm_deactivate(slot);
+        }
+        ndimms++;
+        idx++;
+    }
+
+    return 0;
+}
 DimmState *dimm_find_from_idx(uint32_t idx)
 {
     DimmState *slot;
diff --git a/hw/dimm.h b/hw/dimm.h
index 0fdf59b..7c456fa 100644
--- a/hw/dimm.h
+++ b/hw/dimm.h
@@ -11,6 +11,11 @@ 
 #define DIMM_BITMAP_BYTES (MAX_DIMMS + 7) / 8
 #define DEFAULT_DIMMSIZE 1024*1024*1024
 
+enum {
+    DIMM_MIN_UNPOPULATED= 0,
+    DIMM_MAX_POPULATED = 1
+};
+
 typedef enum {
     DIMM_REMOVE_SUCCESS = 0,
     DIMM_REMOVE_FAIL = 1,
@@ -61,5 +66,7 @@  void dimm_deactivate(DimmState *slot);
 void dimm_scan_populated(void);
 void dimm_notify(uint32_t idx, uint32_t event);
 int dimm_set_populated(DimmState *s);
+DimmState *dimm_find_next(char *pfx, uint32_t mode);
+int dimm_do_range(Monitor *mon, const QDict *qdict, bool add);
 
 #endif
diff --git a/monitor.c b/monitor.c
index 1dd646c..2e0ce1f 100644
--- a/monitor.c
+++ b/monitor.c
@@ -4838,3 +4838,13 @@  int do_dimm_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     return dimm_do(mon, qdict, false);
 }
+
+int do_dimm_add_range(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    return dimm_do_range(mon, qdict, true);
+}
+
+int do_dimm_del_range(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    return dimm_do_range(mon, qdict, false);
+}
diff --git a/monitor.h b/monitor.h
index afdd721..8224301 100644
--- a/monitor.h
+++ b/monitor.h
@@ -88,5 +88,7 @@  int qmp_qom_get(Monitor *mon, const QDict *qdict, QObject **ret);
 
 int do_dimm_add(Monitor *mon, const QDict *qdict, QObject **ret_data);
 int do_dimm_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
+int do_dimm_add_range(Monitor *mon, const QDict *qdict, QObject **ret_data);
+int do_dimm_del_range(Monitor *mon, const QDict *qdict, QObject **ret_data);
 
 #endif /* !MONITOR_H */
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 6c71696..c3f74ea 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2306,3 +2306,43 @@  Example:
    }
 
 EQMP
+
+    {
+        .name       = "mem-increase",
+        .args_type  = "pfx:s,num:s",
+        .mhandler.cmd_new = do_dimm_add_range,
+    },
+SQMP
+mem-increase
+-------------
+
+Hotplug memory DIMMs from memory pool
+
+Will hotplug num memory DIMMs from pool with name pfx.
+
+Example:
+
+-> { "execute": "mem-increase", "arguments": { "pfx" : "pool", "num": "10" } }
+<- { "return": {} }
+
+EQMP
+
+    {
+        .name       = "mem-decrease",
+        .args_type  = "pfx:s,num:s",
+        .mhandler.cmd_new = do_dimm_del_range,
+    },
+SQMP
+mem-decrease
+-------------
+
+Hot-unplug memory DIMMs from memory pool
+
+Will hot-unplug num memory DIMMs from pool with name pfx.
+
+Example:
+
+-> { "execute": "mem-decrease", "arguments": { "pfx" : "pool", "num": "10" } }
+<- { "return": {} }
+
+EQMP