303 lines
9.7 KiB
Diff
303 lines
9.7 KiB
Diff
From 3be8bb571d13795c2824dd6d2089035a1be6cf57 Mon Sep 17 00:00:00 2001
|
|
From: jiang-dawei15 <jiangdawei15@huawei.com>
|
|
Date: Wed, 26 Jan 2022 15:18:10 +0800
|
|
Subject: [PATCH] hotpatch: virsh support autoload mode
|
|
|
|
---
|
|
include/libvirt/libvirt-domain.h | 1 +
|
|
src/qemu/qemu_conf.c | 9 +++
|
|
src/qemu/qemu_conf.h | 1 +
|
|
src/qemu/qemu_driver.c | 5 ++
|
|
src/qemu/qemu_hotpatch.c | 122 +++++++++++++++++++++++++++++++
|
|
src/qemu/qemu_hotpatch.h | 3 +
|
|
src/qemu/qemu_process.c | 6 ++
|
|
tools/virsh-domain.c | 5 +-
|
|
8 files changed, 150 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
|
|
index 2d6432cab2..4ab0c9c0b2 100644
|
|
--- a/include/libvirt/libvirt-domain.h
|
|
+++ b/include/libvirt/libvirt-domain.h
|
|
@@ -4997,6 +4997,7 @@ typedef enum {
|
|
VIR_DOMAIN_HOTPATCH_APPLY, /* Apply hotpatch */
|
|
VIR_DOMAIN_HOTPATCH_UNAPPLY, /* Unapply hotpatch */
|
|
VIR_DOMAIN_HOTPATCH_QUERY, /* Query hotpatch */
|
|
+ VIR_DOMAIN_HOTPATCH_AUTOLOAD, /* Autoload hotpatch */
|
|
|
|
# ifdef VIR_ENUM_SENTINELS
|
|
VIR_DOMAIN_HOTPATCH_LAST
|
|
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
|
|
index 809e8fe526..bd96ccb78e 100644
|
|
--- a/src/qemu/qemu_conf.c
|
|
+++ b/src/qemu/qemu_conf.c
|
|
@@ -1006,6 +1006,12 @@ virQEMUDriverConfigLoadCapsFiltersEntry(virQEMUDriverConfigPtr cfg,
|
|
return 0;
|
|
}
|
|
|
|
+static int
|
|
+virQEMUDriverConfigLoadHotpatchPathEntry(virQEMUDriverConfigPtr cfg,
|
|
+ virConfPtr conf)
|
|
+{
|
|
+ return virConfGetValueString(conf, "hotpatch_path", &cfg->hotpatchPath);
|
|
+}
|
|
|
|
int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg,
|
|
const char *filename,
|
|
@@ -1078,6 +1084,9 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg,
|
|
if (virQEMUDriverConfigLoadCapsFiltersEntry(cfg, conf) < 0)
|
|
return -1;
|
|
|
|
+ if (virQEMUDriverConfigLoadHotpatchPathEntry(cfg, conf) < 0)
|
|
+ return -1;
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
|
|
index 14f9b9e81e..f0124a0fe2 100644
|
|
--- a/src/qemu/qemu_conf.h
|
|
+++ b/src/qemu/qemu_conf.h
|
|
@@ -220,6 +220,7 @@ struct _virQEMUDriverConfig {
|
|
gid_t swtpm_group;
|
|
|
|
char **capabilityfilters;
|
|
+ char *hotpatchPath;
|
|
};
|
|
|
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC(virQEMUDriverConfig, virObjectUnref);
|
|
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
|
|
index 2b24881f75..37b2c4a2da 100644
|
|
--- a/src/qemu/qemu_driver.c
|
|
+++ b/src/qemu/qemu_driver.c
|
|
@@ -23186,6 +23186,7 @@ qemuDomainHotpatchManage(virDomainPtr domain,
|
|
virQEMUDriverPtr driver = domain->conn->privateData;
|
|
char *ret = NULL;
|
|
size_t len;
|
|
+ g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
|
|
|
|
virCheckFlags(0, NULL);
|
|
|
|
@@ -23214,6 +23215,10 @@ qemuDomainHotpatchManage(virDomainPtr domain,
|
|
ret = qemuDomainHotpatchQuery(vm);
|
|
break;
|
|
|
|
+ case VIR_DOMAIN_HOTPATCH_AUTOLOAD:
|
|
+ ret = qemuDomainHotpatchAutoload(vm, cfg->hotpatchPath);
|
|
+ break;
|
|
+
|
|
default:
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
_("Unknow hotpatch action"));
|
|
diff --git a/src/qemu/qemu_hotpatch.c b/src/qemu/qemu_hotpatch.c
|
|
index 03e63c1341..02f511cc38 100644
|
|
--- a/src/qemu/qemu_hotpatch.c
|
|
+++ b/src/qemu/qemu_hotpatch.c
|
|
@@ -25,6 +25,8 @@
|
|
#include "virerror.h"
|
|
#include "virfile.h"
|
|
#include "virlog.h"
|
|
+#include "virbuffer.h"
|
|
+#include "virstring.h"
|
|
#include "vircommand.h"
|
|
#include "qemu/qemu_domain.h"
|
|
#include "qemu_hotpatch.h"
|
|
@@ -32,6 +34,7 @@
|
|
#define LIBCARE_CTL "libcare-ctl"
|
|
#define LIBCARE_ERROR_NUMBER 255
|
|
#define MAX_PATCHID_LEN 8
|
|
+#define MAX_FILE_SIZE (1024*1024)
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_QEMU
|
|
|
|
@@ -204,3 +207,122 @@ qemuDomainHotpatchUnapply(virDomainObjPtr vm,
|
|
VIR_FREE(output);
|
|
return NULL;
|
|
}
|
|
+
|
|
+char *
|
|
+qemuDomainHotpatchAutoload(virDomainObjPtr vm, char *hotpatch_path)
|
|
+{
|
|
+ VIR_AUTOSTRINGLIST applied_patches = NULL;
|
|
+ VIR_AUTOSTRINGLIST lines = NULL;
|
|
+ g_autofree char *applied_patch = NULL;
|
|
+ g_autofree char *libvirtd_conf = NULL;
|
|
+ g_autofree char *patch_conf = NULL;
|
|
+ g_autofree char *buf = NULL;
|
|
+ char *ret = NULL;
|
|
+ int i, j, len;
|
|
+
|
|
+ if (hotpatch_path == NULL) {
|
|
+ virReportError(VIR_ERR_INVALID_ARG, "%s",
|
|
+ _("Invalid hotpatch path."));
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ /* get hotpatch info from Patch.conf */
|
|
+ patch_conf = g_strdup_printf("%s/Patch.conf", hotpatch_path);
|
|
+ if ((len = virFileReadAll(patch_conf, MAX_FILE_SIZE, &buf)) < 0) {
|
|
+ virReportError(VIR_ERR_INVALID_ARG, "%s",
|
|
+ _("Failed to read Patch.conf file."));
|
|
+ return NULL;
|
|
+ }
|
|
+ if (len > 0)
|
|
+ buf[len-1] = '\0';
|
|
+
|
|
+ lines = virStringSplit(buf, "\n", 0);
|
|
+ if (!lines)
|
|
+ return NULL;
|
|
+
|
|
+ /* get domain hotpatch infomation */
|
|
+ applied_patch = qemuDomainHotpatchQuery(vm);
|
|
+ if (!applied_patch)
|
|
+ return NULL;
|
|
+
|
|
+ applied_patches = virStringSplit(applied_patch, "\n", 0);
|
|
+ if (!applied_patches)
|
|
+ return NULL;
|
|
+
|
|
+ /* load all hotpatch which are listed in Patch.conf one by one */
|
|
+ for (i = 0; lines[i] != NULL; i++) {
|
|
+ VIR_AUTOSTRINGLIST patch_info = NULL;
|
|
+ g_autofree char *kpatch_dir = NULL;
|
|
+ g_autofree char *file_path = NULL;
|
|
+ struct dirent *de;
|
|
+ DIR *dh;
|
|
+ int direrr;
|
|
+
|
|
+ if (!strstr(lines[i], "QEMU-"))
|
|
+ continue;
|
|
+
|
|
+ patch_info = virStringSplit(lines[i], " ", 0);
|
|
+ if (!patch_info)
|
|
+ continue;
|
|
+
|
|
+ /* skip already applied patch */
|
|
+ if (strstr(applied_patch, patch_info[2]))
|
|
+ continue;
|
|
+
|
|
+ /* get the kpatch file name */
|
|
+ kpatch_dir = g_strdup_printf("%s/%s", hotpatch_path, patch_info[1]);
|
|
+ if (!kpatch_dir || !virFileExists(kpatch_dir))
|
|
+ return NULL;
|
|
+
|
|
+ if (virDirOpen(&dh, kpatch_dir) < 0)
|
|
+ return NULL;
|
|
+ if ((direrr = virDirRead(dh, &de, kpatch_dir)) > 0) {
|
|
+ GStatBuf sb;
|
|
+
|
|
+ file_path = g_strdup_printf("%s/%s", kpatch_dir, de->d_name);
|
|
+ if (g_lstat(file_path, &sb) < 0) {
|
|
+ virReportSystemError(errno, _("Cannot access '%s'"),
|
|
+ file_path);
|
|
+ VIR_DIR_CLOSE(dh);
|
|
+ return NULL;
|
|
+ }
|
|
+ }
|
|
+ VIR_DIR_CLOSE(dh);
|
|
+
|
|
+ if (qemuDomainHotpatchApply(vm, file_path) == NULL) {
|
|
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
+ _("failed to apply the hotpatch."));
|
|
+ return NULL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* unload the hotpatch which are not listed in Patch.conf */
|
|
+ for (i = 0; applied_patches[i] != NULL; i++) {
|
|
+ const char *patch_id = NULL;
|
|
+ bool is_need_unload = true;
|
|
+
|
|
+ if (!strstr(applied_patches[i], "Patch id"))
|
|
+ continue;
|
|
+
|
|
+ patch_id = strstr(applied_patches[i], ":") + 1;
|
|
+ virSkipSpaces(&patch_id);
|
|
+
|
|
+ for (j = 0; lines[j] != NULL; j++) {
|
|
+ if (!strstr(lines[j], "QEMU-"))
|
|
+ continue;
|
|
+ if (strstr(lines[j], patch_id)) {
|
|
+ is_need_unload = false;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ if (is_need_unload == true)
|
|
+ if (qemuDomainHotpatchUnapply(vm, patch_id) == NULL) {
|
|
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
+ _("failed to unapply the hotpatch."));
|
|
+ return NULL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ret = g_strdup_printf("Hotpatch autoload successfully.\n");
|
|
+ return ret;
|
|
+}
|
|
diff --git a/src/qemu/qemu_hotpatch.h b/src/qemu/qemu_hotpatch.h
|
|
index 4c84a57950..8e0bfe348a 100644
|
|
--- a/src/qemu/qemu_hotpatch.h
|
|
+++ b/src/qemu/qemu_hotpatch.h
|
|
@@ -34,3 +34,6 @@ qemuDomainHotpatchApply(virDomainObjPtr vm,
|
|
char *
|
|
qemuDomainHotpatchUnapply(virDomainObjPtr vm,
|
|
const char *id);
|
|
+
|
|
+char *
|
|
+qemuDomainHotpatchAutoload(virDomainObjPtr vm, char *path_config);
|
|
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
|
|
index 818a72d8f9..24dd9f052c 100644
|
|
--- a/src/qemu/qemu_process.c
|
|
+++ b/src/qemu/qemu_process.c
|
|
@@ -59,6 +59,7 @@
|
|
#include "qemu_firmware.h"
|
|
#include "qemu_backup.h"
|
|
#include "qemu_dbus.h"
|
|
+#include "qemu_hotpatch.h"
|
|
|
|
#include "cpu/cpu.h"
|
|
#include "cpu/cpu_x86.h"
|
|
@@ -6684,6 +6685,7 @@ qemuProcessLaunch(virConnectPtr conn,
|
|
g_autoptr(virQEMUDriverConfig) cfg = NULL;
|
|
size_t nnicindexes = 0;
|
|
g_autofree int *nicindexes = NULL;
|
|
+ g_autofree char *autoLoadStatus = NULL;
|
|
size_t i;
|
|
|
|
VIR_DEBUG("conn=%p driver=%p vm=%p name=%s if=%d asyncJob=%d "
|
|
@@ -6993,6 +6995,10 @@ qemuProcessLaunch(virConnectPtr conn,
|
|
qemuProcessAutoDestroyAdd(driver, vm, conn) < 0)
|
|
goto cleanup;
|
|
|
|
+ /* Autoload hotpatch */
|
|
+ if ((autoLoadStatus = qemuDomainHotpatchAutoload(vm, cfg->hotpatchPath)) == NULL) {
|
|
+ VIR_WARN("Failed to autoload the hotpatch for %s.", vm->def->name);
|
|
+ }
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
|
|
index 813be4a0db..b5375ebd3e 100644
|
|
--- a/tools/virsh-domain.c
|
|
+++ b/tools/virsh-domain.c
|
|
@@ -14344,7 +14344,7 @@ static const vshCmdOptDef opts_hotpatch[] = {
|
|
{.name = "action",
|
|
.type = VSH_OT_DATA,
|
|
.flags = VSH_OFLAG_REQ,
|
|
- .help = N_("hotpatch action, choose from <apply>, <unapply> and <query>")
|
|
+ .help = N_("hotpatch action, choose from <apply>, <unapply>, <query> and <autoload>")
|
|
},
|
|
{.name = "patch",
|
|
.type = VSH_OT_STRING,
|
|
@@ -14363,7 +14363,8 @@ VIR_ENUM_IMPL(virDomainHotpatchAction,
|
|
"none",
|
|
"apply",
|
|
"unapply",
|
|
- "query");
|
|
+ "query",
|
|
+ "autoload");
|
|
|
|
static bool
|
|
cmdHotpatch(vshControl *ctl,
|
|
--
|
|
2.30.0
|
|
|