mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-05-12 10:25:18 +00:00
302 lines
8.0 KiB
Diff
302 lines
8.0 KiB
Diff
From 901fb71c77144b170465611617f0f25099d8a780 Mon Sep 17 00:00:00 2001
|
|
From: Chao Wu <chaowu@linux.alibaba.com>
|
|
Date: Mon, 21 Nov 2022 19:44:50 +0800
|
|
Subject: [PATCH 3/4] upcall: add cpu hotplug/hot-unplug into device manager
|
|
service
|
|
|
|
Add cpu hotplug and hot-unplug support into device manager. In the
|
|
`devmgr_req` message, `msg_type` ADD_CPU in `msg_header` will trigger
|
|
`add_cpu_dev` action and DEL_CPU will trigger `del_cpu_dev` action, and
|
|
we use `apic_ids` and `count` delivered in `cpu_dev_info` to notify
|
|
which and how many cpus will be hotplugged / hot-unplugged.
|
|
|
|
`add_cpu_dev` and `del_cpu_dev` will eventually trigger `add_cpu_upcall`
|
|
and `del_cpu_upcall` to trigger the cpu hotplug / hot-unplug process in
|
|
the kernel. After the cpu hotplug / hot-unplug process,
|
|
`cpu_event_notification` will generate device manager reply to the
|
|
client side.
|
|
|
|
Signed-off-by: Liu Jiang <gerry@linux.alibaba.com>
|
|
Signed-off-by: Zizheng Bian <zizheng.bian@linux.alibaba.com>
|
|
Signed-off-by: Chao Wu <chaowu@linux.alibaba.com>
|
|
Signed-off-by: WangYu <WangYu@linux.alibaba.com>
|
|
Signed-off-by: Xingjun Liu <xingjun.liu@linux.alibaba.com>
|
|
---
|
|
drivers/misc/dragonball/upcall_srv/Kconfig | 11 +
|
|
.../upcall_srv/dragonball_device_manager.c | 219 ++++++++++++++++++
|
|
2 files changed, 230 insertions(+)
|
|
|
|
diff --git a/drivers/misc/dragonball/upcall_srv/Kconfig b/drivers/misc/dragonball/upcall_srv/Kconfig
|
|
index 6554a9741c00..b237882a2928 100644
|
|
--- a/drivers/misc/dragonball/upcall_srv/Kconfig
|
|
+++ b/drivers/misc/dragonball/upcall_srv/Kconfig
|
|
@@ -24,3 +24,14 @@ config DRAGONBALL_DEVICE_MANAGER
|
|
devices etc.
|
|
|
|
If unsure, say N.
|
|
+
|
|
+config DRAGONBALL_HOTPLUG_CPU
|
|
+ bool "CPU hotplug/hotunplug support"
|
|
+ depends on DRAGONBALL_DEVICE_MANAGER
|
|
+ default y
|
|
+ help
|
|
+ This configure implements a vCPU hotplug/hotunplug support, vmm
|
|
+ should send hotplug request by vsock which follow special data
|
|
+ structure with command and parameter to hot-pluging an vCPU.
|
|
+
|
|
+ If unsure, say N.
|
|
diff --git a/drivers/misc/dragonball/upcall_srv/dragonball_device_manager.c b/drivers/misc/dragonball/upcall_srv/dragonball_device_manager.c
|
|
index ebcb6ef74285..210ef5d6c9d5 100644
|
|
--- a/drivers/misc/dragonball/upcall_srv/dragonball_device_manager.c
|
|
+++ b/drivers/misc/dragonball/upcall_srv/dragonball_device_manager.c
|
|
@@ -75,9 +75,20 @@ struct devmgr_req {
|
|
struct devmgr_msg_header msg_header;
|
|
union {
|
|
char pad[DEV_MGR_MSG_SIZE - sizeof(struct devmgr_msg_header)];
|
|
+#if defined(CONFIG_DRAGONBALL_HOTPLUG_CPU)
|
|
+ struct {
|
|
+ uint8_t count;
|
|
+ uint8_t apic_ver;
|
|
+ uint8_t apic_ids[256];
|
|
+ } cpu_dev_info;
|
|
+#endif
|
|
} msg_load;
|
|
};
|
|
|
|
+struct cpu_dev_reply_info {
|
|
+ uint32_t apic_index;
|
|
+};
|
|
+
|
|
struct devmgr_reply {
|
|
struct devmgr_msg_header msg_header;
|
|
/*
|
|
@@ -87,6 +98,9 @@ struct devmgr_reply {
|
|
int32_t ret;
|
|
union {
|
|
char pad[DEV_MGR_MSG_SIZE - sizeof(struct devmgr_msg_header) - sizeof(int32_t)];
|
|
+#if defined(CONFIG_DRAGONBALL_HOTPLUG_CPU)
|
|
+ struct cpu_dev_reply_info cpu_dev_info;
|
|
+#endif
|
|
} msg_load;
|
|
};
|
|
|
|
@@ -109,10 +123,215 @@ static void _fill_msg_header(struct devmgr_msg_header *msg, uint32_t msg_size,
|
|
msg->msg_flags = msg_flags;
|
|
}
|
|
|
|
+#if defined(CONFIG_DRAGONBALL_HOTPLUG_CPU) && defined(CONFIG_X86_64)
|
|
+static int get_cpu_id(int apic_id)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < num_processors; i++) {
|
|
+ if (cpu_physical_id(i) == apic_id)
|
|
+ return i;
|
|
+ }
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Return the first failed hotplug index of the apic_ids to dragonball.
|
|
+ * If it is not equal to the count of all hotplug needed vcpus,
|
|
+ * we will rollback the vcpus from apics_ids[0] to apic_ids[i-1] in dragonball.
|
|
+ */
|
|
+static void cpu_event_notification(
|
|
+ uint8_t apic_ids_index,
|
|
+ int ret,
|
|
+ uint32_t action_type,
|
|
+ struct devmgr_reply *rep)
|
|
+{
|
|
+ pr_info("cpu event notification: apic ids index %d", apic_ids_index);
|
|
+ rep->msg_load.cpu_dev_info.apic_index = apic_ids_index;
|
|
+ rep->ret = ret;
|
|
+ _fill_msg_header(&rep->msg_header,
|
|
+ sizeof(struct cpu_dev_reply_info), action_type, 0);
|
|
+}
|
|
+#endif
|
|
+
|
|
+#if defined(CONFIG_DRAGONBALL_HOTPLUG_CPU) && defined(CONFIG_X86_64)
|
|
+static int add_cpu_upcall(int apic_id, uint8_t apic_ver)
|
|
+{
|
|
+ int cpu_id, node_id;
|
|
+ int ret;
|
|
+
|
|
+ pr_info("adding vcpu apic_id %d", apic_id);
|
|
+
|
|
+ /**
|
|
+ * Get the mutex lock for hotplug and cpu update and cpu write lock.
|
|
+ * So that other threads won't influence the hotplug process.
|
|
+ */
|
|
+ lock_device_hotplug();
|
|
+ cpu_maps_update_begin();
|
|
+ cpu_hotplug_begin();
|
|
+
|
|
+ cpu_id = generic_processor_info(apic_id, apic_ver);
|
|
+ if (cpu_id < 0) {
|
|
+ pr_err("cpu (apic id %d) cannot be added, generic processor info failed", apic_id);
|
|
+ ret = -EINVAL;
|
|
+ goto rollback_generic_cpu;
|
|
+ }
|
|
+
|
|
+ /* update numa mapping for hot-plugged cpus. */
|
|
+ node_id = numa_cpu_node(cpu_id);
|
|
+ if (node_id != NUMA_NO_NODE)
|
|
+ numa_set_node(cpu_id, node_id);
|
|
+
|
|
+ ret = arch_register_cpu(cpu_id);
|
|
+ if (ret) {
|
|
+ pr_err("cpu %d cannot be added, register cpu failed %d", cpu_id, ret);
|
|
+ goto rollback_register_cpu;
|
|
+ }
|
|
+
|
|
+ cpu_hotplug_done();
|
|
+ cpu_maps_update_done();
|
|
+ unlock_device_hotplug();
|
|
+
|
|
+ ret = add_cpu(cpu_id);
|
|
+ if (ret) {
|
|
+ pr_err("cpu %d cannot be added, cpu up failed: %d", cpu_id, ret);
|
|
+ goto rollback_cpu_up;
|
|
+ }
|
|
+ return ret;
|
|
+
|
|
+rollback_cpu_up:
|
|
+ arch_unregister_cpu(cpu_id);
|
|
+ set_cpu_present(cpu_id, false);
|
|
+ per_cpu(x86_cpu_to_apicid, cpu_id) = -1;
|
|
+ num_processors--;
|
|
+ return ret;
|
|
+
|
|
+rollback_register_cpu:
|
|
+ set_cpu_present(cpu_id, false);
|
|
+ per_cpu(x86_cpu_to_apicid, cpu_id) = -1;
|
|
+ num_processors--;
|
|
+rollback_generic_cpu:
|
|
+ cpu_hotplug_done();
|
|
+ cpu_maps_update_done();
|
|
+ unlock_device_hotplug();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int del_cpu_upcall(int apic_id)
|
|
+{
|
|
+ int cpu_id = get_cpu_id(apic_id);
|
|
+ int ret;
|
|
+
|
|
+ if (cpu_id == 0) {
|
|
+ pr_err("cannot del bootstrap processor.");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ pr_info("deleting vcpu %d", cpu_id);
|
|
+ ret = remove_cpu(cpu_id);
|
|
+ if (ret) {
|
|
+ pr_err("del vcpu failed, err: %d", ret);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ lock_device_hotplug();
|
|
+ cpu_maps_update_begin();
|
|
+ cpu_hotplug_begin();
|
|
+
|
|
+ arch_unregister_cpu(cpu_id);
|
|
+ set_cpu_present(cpu_id, false);
|
|
+ per_cpu(x86_cpu_to_apicid, cpu_id) = -1;
|
|
+ num_processors--;
|
|
+
|
|
+ cpu_hotplug_done();
|
|
+ cpu_maps_update_done();
|
|
+ unlock_device_hotplug();
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int add_cpu_dev(struct devmgr_req *req,
|
|
+ struct devmgr_reply *rep)
|
|
+{
|
|
+ int ret;
|
|
+ uint8_t i;
|
|
+ int apic_id;
|
|
+
|
|
+ uint8_t count = req->msg_load.cpu_dev_info.count;
|
|
+ uint8_t apic_ver = req->msg_load.cpu_dev_info.apic_ver;
|
|
+ uint8_t *apic_ids = req->msg_load.cpu_dev_info.apic_ids;
|
|
+
|
|
+ pr_info("add vcpu number: %d", count);
|
|
+
|
|
+ for (i = 0; i < count; ++i) {
|
|
+ apic_id = apic_ids[i];
|
|
+ if (get_cpu_id(apic_id) != -1) {
|
|
+ pr_err("cpu cannot be added: apci_id %d is already been used.", apic_id);
|
|
+ ret = -EINVAL;
|
|
+ return ret;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < count; ++i) {
|
|
+ apic_id = apic_ids[i];
|
|
+ ret = add_cpu_upcall(apic_id, apic_ver);
|
|
+ if (ret != 0)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (!ret)
|
|
+ cpu_event_notification(i, ret, ADD_CPU, rep);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int del_cpu_dev(struct devmgr_req *req,
|
|
+ struct devmgr_reply *rep)
|
|
+{
|
|
+ int ret;
|
|
+ uint8_t i;
|
|
+ int cpu_id;
|
|
+
|
|
+ uint8_t count = req->msg_load.cpu_dev_info.count;
|
|
+ uint8_t *apic_ids = req->msg_load.cpu_dev_info.apic_ids;
|
|
+
|
|
+ pr_info("del vcpu number : %d", count);
|
|
+
|
|
+ if (count >= num_processors) {
|
|
+ pr_err("cpu del parameter check error: cannot remove all vcpus");
|
|
+ ret = -EINVAL;
|
|
+ cpu_event_notification(0, ret, DEL_CPU, rep);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < count; ++i) {
|
|
+ cpu_id = get_cpu_id(apic_ids[i]);
|
|
+ if (!cpu_possible(cpu_id)) {
|
|
+ pr_err("cpu %d cannot be deleted: cpu not possible", cpu_id);
|
|
+ ret = -EINVAL;
|
|
+ cpu_event_notification(0, ret, DEL_CPU, rep);
|
|
+ return ret;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < count; ++i) {
|
|
+ ret = del_cpu_upcall(apic_ids[i]);
|
|
+ if (ret != 0)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (!ret)
|
|
+ cpu_event_notification(i, ret, DEL_CPU, rep);
|
|
+ return ret;
|
|
+}
|
|
+#endif
|
|
+
|
|
static struct {
|
|
enum devmgr_msg_type cmd;
|
|
action_route_t fn;
|
|
} opt_map[] = {
|
|
+#if defined(CONFIG_DRAGONBALL_HOTPLUG_CPU) && defined(CONFIG_X86_64)
|
|
+ {ADD_CPU, add_cpu_dev},
|
|
+ {DEL_CPU, del_cpu_dev},
|
|
+#endif
|
|
};
|
|
|
|
static action_route_t get_action(struct devmgr_req *req)
|
|
--
|
|
2.19.1.6.gb485710b
|
|
|