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(-)
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