@@ -1574,6 +1574,8 @@ show roms
show memory-total
@item info dimm
show dimm
+@item info memory-hotplug
+show memory-hotplug
@end table
ETEXI
@@ -652,6 +652,23 @@ void hmp_info_dimm(Monitor *mon)
qapi_free_DimmInfoList(info);
}
+void hmp_info_memory_hotplug(Monitor *mon)
+{
+ MemHpInfoList *info;
+ MemHpInfoList *item;
+ MemHpInfo *dimm;
+
+ info = qmp_query_memory_hotplug(NULL);
+ for (item = info; item; item = item->next) {
+ dimm = item->value;
+ monitor_printf(mon, "dimm: %s %s %s\n", dimm->dimm,
+ dimm->request, dimm->result);
+ dimm->dimm = NULL;
+ }
+
+ qapi_free_MemHpInfoList(info);
+}
+
void hmp_quit(Monitor *mon, const QDict *qdict)
{
monitor_suspend(mon);
@@ -38,6 +38,7 @@ void hmp_info_pci(Monitor *mon);
void hmp_info_block_jobs(Monitor *mon);
void hmp_info_memory_total(Monitor *mon);
void hmp_info_dimm(Monitor *mon);
+void hmp_info_memory_hotplug(Monitor *mon);
void hmp_quit(Monitor *mon, const QDict *qdict);
void hmp_stop(Monitor *mon, const QDict *qdict);
void hmp_system_reset(Monitor *mon, const QDict *qdict);
@@ -67,6 +67,7 @@ static void dimm_bus_initfn(Object *obj)
DimmBus *bus = DIMM_BUS(obj);
QTAILQ_INIT(&bus->dimmconfig_list);
QTAILQ_INIT(&bus->dimmlist);
+ QTAILQ_INIT(&bus->dimm_hp_result_queue);
}
static const TypeInfo dimm_bus_info = {
@@ -278,6 +279,58 @@ DimmInfoList *qmp_query_dimm_info(Error **errp)
return head;
}
+MemHpInfoList *qmp_query_memory_hotplug(Error **errp)
+{
+ DimmBus *bus;
+ MemHpInfoList *head = NULL, *cur_item = NULL, *info;
+ struct dimm_hp_result *item, *nextitem;
+
+ QLIST_FOREACH(bus, &memory_buses, next) {
+ QTAILQ_FOREACH_SAFE(item, &bus->dimm_hp_result_queue, next, nextitem) {
+
+ info = g_malloc0(sizeof(*info));
+ info->value = g_malloc0(sizeof(*info->value));
+ info->value->dimm = g_malloc0(sizeof(char) * 32);
+ info->value->request = g_malloc0(sizeof(char) * 16);
+ info->value->result = g_malloc0(sizeof(char) * 16);
+ switch (item->ret) {
+ case DIMM_REMOVE_SUCCESS:
+ strcpy(info->value->request, "hot-remove");
+ strcpy(info->value->result, "success");
+ break;
+ case DIMM_REMOVE_FAIL:
+ strcpy(info->value->request, "hot-remove");
+ strcpy(info->value->result, "failure");
+ break;
+ case DIMM_ADD_SUCCESS:
+ strcpy(info->value->request, "hot-add");
+ strcpy(info->value->result, "success");
+ break;
+ case DIMM_ADD_FAIL:
+ strcpy(info->value->request, "hot-add");
+ strcpy(info->value->result, "failure");
+ break;
+ default:
+ break;
+ }
+ strcpy(info->value->dimm, item->dimmname);
+ /* XXX: waiting for the qapi to support GSList */
+ if (!cur_item) {
+ head = cur_item = info;
+ } else {
+ cur_item->next = info;
+ cur_item = info;
+ }
+
+ /* hotplug notification copied to qmp list, delete original item */
+ QTAILQ_REMOVE(&bus->dimm_hp_result_queue, item, next);
+ g_free(item);
+ }
+ }
+
+ return head;
+}
+
static int dimm_init(DeviceState *s)
{
DimmBus *bus = DIMM_BUS(qdev_get_parent_bus(s));
@@ -311,17 +364,25 @@ void dimm_notify(uint32_t idx, uint32_t event)
{
DimmBus *bus;
DimmDevice *slot;
+ DimmConfig *slotcfg;
+ struct dimm_hp_result *result;
slot = dimm_find_from_idx(idx);
assert(slot != NULL);
bus = DIMM_BUS(qdev_get_parent_bus(&slot->qdev));
+ result = g_malloc0(sizeof(*result));
+ slotcfg = dimmcfg_find_from_name(bus, slot->qdev.id);
+ result->dimmname = slotcfg->name;
+
switch (event) {
case DIMM_REMOVE_SUCCESS:
qdev_unplug_complete((DeviceState *)slot, NULL);
QTAILQ_REMOVE(&bus->dimmlist, slot, nextdimm);
+ QTAILQ_INSERT_TAIL(&bus->dimm_hp_result_queue, result, next);
break;
default:
+ g_free(result);
break;
}
}
@@ -69,6 +69,7 @@ typedef struct DimmBus {
dimm_hotplug_fn dimm_hotplug;
DimmConfiglist dimmconfig_list;
QTAILQ_HEAD(Dimmlist, DimmDevice) dimmlist;
+ QTAILQ_HEAD(dimm_hp_result_head, dimm_hp_result) dimm_hp_result_queue;
QLIST_ENTRY(DimmBus) next;
} DimmBus;
@@ -2715,6 +2715,13 @@ static mon_cmd_t info_cmds[] = {
.mhandler.info = hmp_info_memory_total,
},
{
+ .name = "memory-hotplug",
+ .args_type = "",
+ .params = "",
+ .help = "show memory hotplug status",
+ .mhandler.info = hmp_info_memory_hotplug,
+ },
+ {
.name = "qtree",
.args_type = "",
.params = "",
@@ -2940,6 +2940,32 @@
{ 'command': 'query-dimm-info', 'returns': ['DimmInfo'] }
##
+# @MemHpInfo:
+#
+# Information about status of a memory hotplug command
+#
+# @dimm: the Dimm associated with the result
+#
+# @result: the result of the hotplug command
+#
+# Since: 1.4
+#
+##
+{ 'type': 'MemHpInfo',
+ 'data': {'dimm': 'str', 'request': 'str', 'result': 'str'} }
+
+##
+# @query-memory-hotplug:
+#
+# Returns a list of information about pending hotplug commands
+#
+# Returns: a list of @MemhpInfo
+#
+# Since: 1.4
+##
+{ 'command': 'query-memory-hotplug', 'returns': ['MemHpInfo'] }
+
+##
# @QKeyCode:
#
# An enumeration of key name.
@@ -2674,3 +2674,40 @@ Example:
}
EQMP
+ {
+ .name = "query-memory-hotplug",
+ .args_type = "",
+ .mhandler.cmd_new = qmp_marshal_input_query_memory_hotplug
+ },
+SQMP
+query-memory-hotplug
+----------
+
+Show memory hotplug command notifications.
+
+Return a json-array. Each DIMM that has a pending notification is represented
+by a json-object, which contains:
+
+- "dimm": Dimm name (json-str)
+- "request": type of hot request: hot-add or hot-remove (json-str)
+- "result": result of the hotplug request for this Dimm success or failure (json-str)
+
+Example:
+
+-> { "execute": "query-memory-hotplug" }
+<- {
+ "return":[
+ {
+ "result": "failure",
+ "request": "hot-remove",
+ "dimm": "dimm10"
+ },
+ {
+ "result": "success",
+ "request": "hot-add",
+ "dimm": "dimm3"
+ }
+ ]
+ }
+
+EQMP
Guest can respond to ACPI hotplug events e.g. with _EJ or _OST method. This patch implements a tail queue to store guest notifications for memory hot-add and hot-remove requests. Guest responses for memory hotplug command on a per-dimm basis can be detected with the new hmp command "info memory-hotplug" or the new qmp command "query-memory-hotplug" Examples: (qemu) device_add dimm,id=ram0 (qemu) info memory-hotplug dimm: ram0 hot-add success or dimm: ram0 hot-add failure (qemu) device_del ram3 (qemu) info memory-hotplug dimm: ram3 hot-remove success or dimm: ram3 hot-remove failure Results are removed from the queue once read. This patch only queues _EJ events that signal hot-remove success. For _OST event queuing, which cover the hot-remove failure and hot-add success/failure cases, the _OST patches in this series are are also needed. These notification items should probably be part of migration state (not yet implemented). Signed-off-by: Vasilis Liaskovitis <vasilis.liaskovitis@profitbricks.com> --- hmp-commands.hx | 2 + hmp.c | 17 +++++++++++++++ hmp.h | 1 + hw/dimm.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/dimm.h | 1 + monitor.c | 7 ++++++ qapi-schema.json | 26 +++++++++++++++++++++++ qmp-commands.hx | 37 ++++++++++++++++++++++++++++++++ 8 files changed, 152 insertions(+), 0 deletions(-)