Patchwork [RFC,v4,26/30] Implement qmp and hmp commands for notification lists

login
register
mail settings
Submitter Vasilis Liaskovitis
Date Dec. 18, 2012, 12:41 p.m.
Message ID <1355834518-17989-27-git-send-email-vasilis.liaskovitis@profitbricks.com>
Download mbox | patch
Permalink /patch/207123/
State New
Headers show

Comments

Vasilis Liaskovitis - Dec. 18, 2012, 12:41 p.m.
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(-)
Eric Blake - Jan. 9, 2013, 12:23 a.m.
On 12/18/2012 05:41 AM, Vasilis Liaskovitis wrote:
> 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
> 

> +++ b/qapi-schema.json
> @@ -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

Didn't document @request.

> +#
> +# @result: the result of the hotplug command
> +#
> +# Since: 1.4
> +#
> +##
> +{ 'type': 'MemHpInfo',
> +  'data': {'dimm': 'str', 'request': 'str', 'result': 'str'} }

Instead of open-coding 'request' and 'result' as an arbitrary string, it
would be nicer to have them be an enum type with a finite subset of
expected values.

> +
> +##
> +# @query-memory-hotplug:
> +#
> +# Returns a list of information about pending hotplug commands
> +#
> +# Returns: a list of @MemhpInfo

s/MemhpInfo/MemHpInfo/

> +#
> +# Since: 1.4
> +##
> +{ 'command': 'query-memory-hotplug', 'returns': ['MemHpInfo'] }
> +
> +##
>  # @QKeyCode:
>  #

Patch

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 65d799e..b94b7a2 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1574,6 +1574,8 @@  show roms
 show memory-total
 @item info dimm
 show dimm
+@item info memory-hotplug
+show memory-hotplug
 @end table
 ETEXI
 
diff --git a/hmp.c b/hmp.c
index f8456fd..727ed80 100644
--- a/hmp.c
+++ b/hmp.c
@@ -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);
diff --git a/hmp.h b/hmp.h
index 74ac061..92095df 100644
--- a/hmp.h
+++ b/hmp.h
@@ -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);
diff --git a/hw/dimm.c b/hw/dimm.c
index 0b4e22d..4670ae6 100644
--- a/hw/dimm.c
+++ b/hw/dimm.c
@@ -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;
     }
 }
diff --git a/hw/dimm.h b/hw/dimm.h
index 86c7cd5..8f9546b 100644
--- a/hw/dimm.h
+++ b/hw/dimm.h
@@ -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;
 
diff --git a/monitor.c b/monitor.c
index de1dcf1..40a7b7e 100644
--- a/monitor.c
+++ b/monitor.c
@@ -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     = "",
diff --git a/qapi-schema.json b/qapi-schema.json
index 5a20577..d2e9831 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -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.
diff --git a/qmp-commands.hx b/qmp-commands.hx
index a99117a..ad0dac7 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -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