From 3be8bb571d13795c2824dd6d2089035a1be6cf57 Mon Sep 17 00:00:00 2001 From: jiang-dawei15 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 , and ") + .help = N_("hotpatch action, choose from , , and ") }, {.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