@@ -1805,6 +1805,7 @@ typedef struct set_vcpuonline_state {
libxl_dominfo info;
libxl_bitmap final_map;
int index; /* for loop on final_map */
+ const char *cpu_driver;
} set_vcpuonline_state;
static void set_vcpuonline_qmp_cpus_fast_queried(libxl__egc *,
@@ -1814,6 +1815,10 @@ static void set_vcpuonline_qmp_cpus_queried(libxl__egc *,
static void set_vcpuonline_qmp_query_cpus_parse(libxl__egc *,
libxl__ev_qmp *qmp, const libxl__json_object *,
bool query_cpus_fast, int rc);
+static void set_vcpuonline_qmp_query_hotpluggable_cpus(libxl__egc *egc,
+ libxl__ev_qmp *qmp, const libxl__json_object *response, int rc);
+static void set_vcpuonline_qmp_device_add_cpu(libxl__egc *,
+ libxl__ev_qmp *, const libxl__json_object *response, int rc);
static void set_vcpuonline_qmp_add_cpu(libxl__egc *,
libxl__ev_qmp *, const libxl__json_object *response, int rc);
static void set_vcpuonline_timeout(libxl__egc *egc,
@@ -1951,13 +1956,54 @@ static void set_vcpuonline_qmp_query_cpus_parse(libxl__egc *egc,
libxl_bitmap_reset(final_map, i);
}
+ qmp->callback = set_vcpuonline_qmp_query_hotpluggable_cpus;
+ rc = libxl__ev_qmp_send(egc, qmp, "query-hotpluggable-cpus", NULL);
+
out:
libxl_bitmap_dispose(¤t_map);
+ if (rc)
+ set_vcpuonline_done(egc, svos, rc); /* must be last */
+}
+
+static void set_vcpuonline_qmp_query_hotpluggable_cpus(libxl__egc *egc,
+ libxl__ev_qmp *qmp, const libxl__json_object *response, int rc)
+{
+ set_vcpuonline_state *svos = CONTAINER_OF(qmp, *svos, qmp);
+ const libxl__json_object *cpu;
+ const libxl__json_object *cpu_driver;
+
+ if (rc == ERROR_QMP_COMMAND_NOT_FOUND) {
+ /* We are probably connected to a version of QEMU older than 2.7,
+ * let's fallback to using "cpu-add" command. */
+ svos->index = -1;
+ set_vcpuonline_qmp_add_cpu(egc, qmp, NULL, 0); /* must be last */
+ return;
+ }
+
+ if (rc) goto out;
+
+ /* Parse response to QMP command "query-hotpluggable-cpus"
+ * [ { 'type': 'str', ... ]
+ *
+ * We are looking for the driver name for CPU to be hotplug. We'll
+ * assume that cpus property are core-id=0, thread-id=0 and
+ * socket-id=$cpu_index, as we start qemu with "-smp %d,maxcpus=%d", so
+ * we don't parse the properties listed for each hotpluggable cpus.
+ */
+
+ cpu = libxl__json_array_get(response, 0);
+ cpu_driver = libxl__json_map_get("type", cpu, JSON_STRING);
+ svos->cpu_driver = libxl__json_object_get_string(cpu_driver);
+
+ if (!svos->cpu_driver)
+ rc = ERROR_QEMU_API;
+
+out:
svos->index = -1;
- set_vcpuonline_qmp_add_cpu(egc, qmp, NULL, rc); /* must be last */
+ set_vcpuonline_qmp_device_add_cpu(egc, qmp, NULL, rc); /* must be last */
}
-static void set_vcpuonline_qmp_add_cpu(libxl__egc *egc,
+static void set_vcpuonline_qmp_device_add_cpu(libxl__egc *egc,
libxl__ev_qmp *qmp, const libxl__json_object *response, int rc)
{
STATE_AO_GC(qmp->ao);
@@ -1969,6 +2015,43 @@ static void set_vcpuonline_qmp_add_cpu(libxl__egc *egc,
if (rc) goto out;
+ while (libxl_bitmap_cpu_valid(map, ++svos->index)) {
+ if (libxl_bitmap_test(map, svos->index)) {
+ qmp->callback = set_vcpuonline_qmp_device_add_cpu;
+ libxl__qmp_param_add_string(gc, &args, "id", GCSPRINTF("cpu-%d", svos->index));
+ libxl__qmp_param_add_string(gc, &args, "driver", svos->cpu_driver);
+ /* We'll assume that we start QEMU with -smp %d,maxcpus=%d, so
+ * that "core-id" and "thread-id" are always 0 so that
+ * "socket-id" correspond the cpu index.
+ * Those properties are otherwise listed by
+ * "query-hotpluggable-cpus". */
+ libxl__qmp_param_add_integer(gc, &args, "socket-id", svos->index);
+ libxl__qmp_param_add_integer(gc, &args, "core-id", 0);
+ libxl__qmp_param_add_integer(gc, &args, "thread-id", 0);
+ rc = libxl__ev_qmp_send(egc, qmp, "device_add", args);
+ if (rc) goto out;
+ return;
+ }
+ }
+
+out:
+ set_vcpuonline_done(egc, svos, rc);
+}
+
+/* Fallback function for QEMU older than 2.7, when
+ * 'query-hotpluggable-cpus' wasn't available and vcpu object couldn't be
+ * added with 'device_add'. */
+static void set_vcpuonline_qmp_add_cpu(libxl__egc *egc, libxl__ev_qmp *qmp,
+ const libxl__json_object *response,
+ int rc) { STATE_AO_GC(qmp->ao);
+ set_vcpuonline_state *svos = CONTAINER_OF(qmp, *svos, qmp);
+ libxl__json_object *args = NULL;
+
+ /* Convenience aliases */
+ libxl_bitmap *map = &svos->final_map;
+
+ if (rc) goto out;
+
while (libxl_bitmap_cpu_valid(map, ++svos->index)) {
if (libxl_bitmap_test(map, svos->index)) {
qmp->callback = set_vcpuonline_qmp_add_cpu;
The command "cpu-add" for CPU hotplug is deprecated and has been removed from QEMU 6.0 (April 2021). We need to add cpus with the command "device_add" now. In order to find out which parameters to pass to "device_add" we first make a call to "query-hotpluggable-cpus" which list the cpus drivers and properties. The algorithm to figure out which CPU to add, and by extension if any CPU needs to be hotplugged, is in the function that adds the cpus. Because of that, the command "query-hotpluggable-cpus" is always called, even when not needed. In case we are using a version of QEMU older than 2.7 (Sept 2016) which don't have "query-hotpluggable-cpus", we fallback to using "cpu-add". Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> --- tools/libs/light/libxl_domain.c | 87 ++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 2 deletions(-)