diff --git a/Hotpatch-introduce-DomainHotpatchManage-API.patch b/Hotpatch-introduce-DomainHotpatchManage-API.patch new file mode 100644 index 0000000000000000000000000000000000000000..26b643df70cca5662374893a66f4fc9de10350d0 --- /dev/null +++ b/Hotpatch-introduce-DomainHotpatchManage-API.patch @@ -0,0 +1,211 @@ +From 9a12606bb5caf3e213ce1564445d88325592e642 Mon Sep 17 00:00:00 2001 +From: AlexChen +Date: Tue, 19 Oct 2021 14:50:32 +0800 +Subject: [PATCH] Hotpatch: introduce DomainHotpatchManage API + +Signed-off-by: Hao Wang +Signed-off-by: Bihong Yu +Signed-off-by: AlexChen +--- + include/libvirt/libvirt-domain.h | 18 ++++++++++ + scripts/check-aclrules.py | 1 + + src/driver-hypervisor.h | 8 +++++ + src/libvirt-domain.c | 58 ++++++++++++++++++++++++++++++++ + src/libvirt_public.syms | 4 +++ + src/remote/remote_driver.c | 1 + + src/remote/remote_protocol.x | 20 ++++++++++- + 7 files changed, 109 insertions(+), 1 deletion(-) + +diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h +index 90cb652db1..f91061724b 100644 +--- a/include/libvirt/libvirt-domain.h ++++ b/include/libvirt/libvirt-domain.h +@@ -4991,4 +4991,22 @@ int virDomainBackupBegin(virDomainPtr domain, + char *virDomainBackupGetXMLDesc(virDomainPtr domain, + unsigned int flags); + ++typedef enum { ++ VIR_DOMAIN_HOTPATCH_NONE = 0, /* No action */ ++ VIR_DOMAIN_HOTPATCH_APPLY, /* Apply hotpatch */ ++ VIR_DOMAIN_HOTPATCH_UNAPPLY, /* Unapply hotpatch */ ++ VIR_DOMAIN_HOTPATCH_QUERY, /* Query hotpatch */ ++ ++# ifdef VIR_ENUM_SENTINELS ++ VIR_DOMAIN_HOTPATCH_LAST ++# endif ++} virDomainHotpatchAction; ++ ++char * ++virDomainHotpatchManage(virDomainPtr domain, ++ int action, ++ const char *patch, ++ const char *id, ++ unsigned int flags); ++ + #endif /* LIBVIRT_DOMAIN_H */ +diff --git a/scripts/check-aclrules.py b/scripts/check-aclrules.py +index a1fa473174..e196f81de9 100755 +--- a/scripts/check-aclrules.py ++++ b/scripts/check-aclrules.py +@@ -53,6 +53,7 @@ whitelist = { + "connectURIProbe": True, + "localOnly": True, + "domainQemuAttach": True, ++ "domainHotpatchManage": True, + } + + # XXX this vzDomainMigrateConfirm3Params looks +diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h +index bce023017d..afc21a0b3f 100644 +--- a/src/driver-hypervisor.h ++++ b/src/driver-hypervisor.h +@@ -1387,6 +1387,13 @@ typedef char * + (*virDrvDomainBackupGetXMLDesc)(virDomainPtr domain, + unsigned int flags); + ++typedef char * ++(*virDrvDomainHotpatchManage)(virDomainPtr domain, ++ int action, ++ const char *patch, ++ const char *id, ++ unsigned int flags); ++ + typedef struct _virHypervisorDriver virHypervisorDriver; + typedef virHypervisorDriver *virHypervisorDriverPtr; + +@@ -1650,4 +1657,5 @@ struct _virHypervisorDriver { + virDrvDomainAgentSetResponseTimeout domainAgentSetResponseTimeout; + virDrvDomainBackupBegin domainBackupBegin; + virDrvDomainBackupGetXMLDesc domainBackupGetXMLDesc; ++ virDrvDomainHotpatchManage domainHotpatchManage; + }; +diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c +index a12809c2d5..068ab52f54 100644 +--- a/src/libvirt-domain.c ++++ b/src/libvirt-domain.c +@@ -12733,3 +12733,61 @@ virDomainBackupGetXMLDesc(virDomainPtr domain, + virDispatchError(conn); + return NULL; + } ++ ++/** ++ * virDomainHotpatchManage: ++ * @domain: a domain object ++ * @action: the action type from virDomainHotpatchAction ++ * @patch: the target hotpatch file ++ * @id: the patch id of the target hotpatch ++ * @flags: extra flags; not used yet, so callers should always pass 0 ++ * ++ * Manage hotpatch for the current domain according to @action. ++ * ++ * If the @action is set to VIR_DOMAIN_HOTPATCH_APPLY, apply hotpatch ++ * @patch to the current domain. ++ * ++ * If the @action is set to VIR_DOMAIN_HOTPATCH_UNAPPLY, unapply the ++ * hotpatch which is matched with @id from the current domain. ++ * ++ * If the @action is set to VIR_DOMAIN_HOTPATCH_QUERY, query infomations ++ * of the applied hotpatch of the current domain. ++ * ++ * Returns success messages in case of success, NULL otherwise. ++ */ ++char * ++virDomainHotpatchManage(virDomainPtr domain, ++ int action, ++ const char *patch, ++ const char *id, ++ unsigned int flags) ++{ ++ virConnectPtr conn; ++ ++ virResetLastError(); ++ ++ virCheckDomainReturn(domain, NULL); ++ conn = domain->conn; ++ ++ virCheckReadOnlyGoto(conn->flags, error); ++ ++ if (action == VIR_DOMAIN_HOTPATCH_APPLY) ++ virCheckNonNullArgGoto(patch, error); ++ ++ if (action == VIR_DOMAIN_HOTPATCH_UNAPPLY) ++ virCheckNonNullArgGoto(id, error); ++ ++ if (conn->driver->domainHotpatchManage) { ++ char *ret; ++ ret = conn->driver->domainHotpatchManage(domain, action, patch, id, flags); ++ if (!ret) ++ goto error; ++ ++ return ret; ++ } ++ ++ virReportUnsupportedError(); ++ error: ++ virDispatchError(conn); ++ return NULL; ++} +diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms +index 539d2e3943..0ad0b9e489 100644 +--- a/src/libvirt_public.syms ++++ b/src/libvirt_public.syms +@@ -873,4 +873,8 @@ LIBVIRT_6.0.0 { + virDomainBackupGetXMLDesc; + } LIBVIRT_5.10.0; + ++LIBVIRT_6.2.0 { ++ global: ++ virDomainHotpatchManage; ++} LIBVIRT_6.0.0; + # .... define new API here using predicted next version number .... +diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c +index 7bae0c2514..1202d44017 100644 +--- a/src/remote/remote_driver.c ++++ b/src/remote/remote_driver.c +@@ -8684,6 +8684,7 @@ static virHypervisorDriver hypervisor_driver = { + .domainAgentSetResponseTimeout = remoteDomainAgentSetResponseTimeout, /* 5.10.0 */ + .domainBackupBegin = remoteDomainBackupBegin, /* 6.0.0 */ + .domainBackupGetXMLDesc = remoteDomainBackupGetXMLDesc, /* 6.0.0 */ ++ .domainHotpatchManage = remoteDomainHotpatchManage, /* 6.2.0 */ + }; + + static virNetworkDriver network_driver = { +diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x +index 8b05082b61..ee13075ce1 100644 +--- a/src/remote/remote_protocol.x ++++ b/src/remote/remote_protocol.x +@@ -3771,6 +3771,18 @@ struct remote_domain_backup_get_xml_desc_ret { + remote_nonnull_string xml; + }; + ++struct remote_domain_hotpatch_manage_args { ++ remote_nonnull_domain dom; ++ int action; ++ remote_string patch; ++ remote_string id; ++ unsigned int flags; ++}; ++ ++struct remote_domain_hotpatch_manage_ret { ++ remote_string info; ++}; ++ + /*----- Protocol. -----*/ + + /* Define the program number, protocol version and procedure numbers here. */ +@@ -6668,5 +6680,11 @@ enum remote_procedure { + * @priority: high + * @acl: domain:read + */ +- REMOTE_PROC_DOMAIN_BACKUP_GET_XML_DESC = 422 ++ REMOTE_PROC_DOMAIN_BACKUP_GET_XML_DESC = 422, ++ ++ /** ++ * @generate: both ++ * @acl: domain:read ++ */ ++ REMOTE_PROC_DOMAIN_HOTPATCH_MANAGE = 800 + }; +-- +2.27.0 + diff --git a/domain-add-logs-for-virDomainHotpatchManage.patch b/domain-add-logs-for-virDomainHotpatchManage.patch new file mode 100644 index 0000000000000000000000000000000000000000..ef63bf495abf03a2d6f94e65d3489eb050205505 --- /dev/null +++ b/domain-add-logs-for-virDomainHotpatchManage.patch @@ -0,0 +1,45 @@ +From e59b2064ffefbc94c729d38ec0180197e2b1f8ed Mon Sep 17 00:00:00 2001 +From: AlexChen +Date: Mon, 12 Jul 2021 21:28:41 +0800 +Subject: [PATCH] domain: add logs for virDomainHotpatchManage + +Add logs for virDomainHotpatchManage to facilitate the location of +issues related to subsequent hotpatch. + +Signed-off-by: Bihong Yu +Signed-off-by: AlexChen +--- + src/libvirt-domain.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c +index 068ab52f54..3cf6bcb3b4 100644 +--- a/src/libvirt-domain.c ++++ b/src/libvirt-domain.c +@@ -12777,12 +12777,21 @@ virDomainHotpatchManage(virDomainPtr domain, + if (action == VIR_DOMAIN_HOTPATCH_UNAPPLY) + virCheckNonNullArgGoto(id, error); + ++ VIR_INFO("enter virDomainHotpatchManage domainname=%s, action=%d, " ++ "patch=%s, id=%s, flags=%d", ++ NULLSTR(domain->name), action, ++ NULLSTR(patch), NULLSTR(id), flags); ++ + if (conn->driver->domainHotpatchManage) { + char *ret; + ret = conn->driver->domainHotpatchManage(domain, action, patch, id, flags); +- if (!ret) ++ if (!ret) { ++ VIR_ERROR("domain %s managed hotpatch failed", ++ NULLSTR(domain->name)); + goto error; +- ++ } ++ VIR_INFO("domain %s managed hotpatch successfully", ++ NULLSTR(domain->name)); + return ret; + } + +-- +2.27.0 + diff --git a/hotpatch-Implement-qemuDomainHotpatchManage.patch b/hotpatch-Implement-qemuDomainHotpatchManage.patch new file mode 100644 index 0000000000000000000000000000000000000000..79bcd38a37d2ee86a6278a2bd08d8df245736644 --- /dev/null +++ b/hotpatch-Implement-qemuDomainHotpatchManage.patch @@ -0,0 +1,336 @@ +From b255a024007eb236745b703586a2fed8bdedae6c Mon Sep 17 00:00:00 2001 +From: AlexChen +Date: Tue, 19 Oct 2021 22:11:45 +0800 +Subject: [PATCH] hotpatch: Implement qemuDomainHotpatchManage + +Signed-off-by: Hao Wang +Signed-off-by: Bihong Yu +Signed-off-by: AlexChen +--- + src/qemu/Makefile.inc.am | 2 + + src/qemu/qemu_driver.c | 48 +++++++++++ + src/qemu/qemu_hotpatch.c | 182 +++++++++++++++++++++++++++++++++++++++ + src/qemu/qemu_hotpatch.h | 36 ++++++++ + 4 files changed, 268 insertions(+) + create mode 100644 src/qemu/qemu_hotpatch.c + create mode 100644 src/qemu/qemu_hotpatch.h + +diff --git a/src/qemu/Makefile.inc.am b/src/qemu/Makefile.inc.am +index 51cd79879d..a1a8bfa17c 100644 +--- a/src/qemu/Makefile.inc.am ++++ b/src/qemu/Makefile.inc.am +@@ -73,6 +73,8 @@ QEMU_DRIVER_SOURCES = \ + qemu/qemu_checkpoint.h \ + qemu/qemu_backup.c \ + qemu/qemu_backup.h \ ++ qemu/qemu_hotpatch.c \ ++ qemu/qemu_hotpatch.h \ + $(NULL) + + +diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c +index 5901f922bf..f6d99957a5 100644 +--- a/src/qemu/qemu_driver.c ++++ b/src/qemu/qemu_driver.c +@@ -50,6 +50,7 @@ + #include "qemu_security.h" + #include "qemu_checkpoint.h" + #include "qemu_backup.h" ++#include "qemu_hotpatch.h" + + #include "virerror.h" + #include "virlog.h" +@@ -23171,6 +23172,52 @@ qemuDomainAgentSetResponseTimeout(virDomainPtr dom, + return ret; + } + ++static char * ++qemuDomainHotpatchManage(virDomainPtr domain, ++ int action, ++ const char *patch, ++ const char *id, ++ unsigned int flags) ++{ ++ virDomainObjPtr vm; ++ char *ret = NULL; ++ size_t len; ++ ++ virCheckFlags(0, NULL); ++ ++ if (!(vm = qemuDomainObjFromDomain(domain))) ++ goto cleanup; ++ ++ switch (action) { ++ case VIR_DOMAIN_HOTPATCH_APPLY: ++ ret = qemuDomainHotpatchApply(vm, patch); ++ break; ++ ++ case VIR_DOMAIN_HOTPATCH_UNAPPLY: ++ ret = qemuDomainHotpatchUnapply(vm, id); ++ break; ++ ++ case VIR_DOMAIN_HOTPATCH_QUERY: ++ ret = qemuDomainHotpatchQuery(vm); ++ break; ++ ++ default: ++ virReportError(VIR_ERR_OPERATION_INVALID, "%s", ++ _("Unknow hotpatch action")); ++ } ++ ++ if (!ret) ++ goto endjob; ++ ++ /* Wipeout redundant empty line */ ++ len = strlen(ret); ++ if (len > 0) ++ ret[len - 1] = '\0'; ++ ++ cleanup: ++ virDomainObjEndAPI(&vm); ++ return ret; ++} + + static virHypervisorDriver qemuHypervisorDriver = { + .name = QEMU_DRIVER_NAME, +@@ -23411,6 +23458,7 @@ static virHypervisorDriver qemuHypervisorDriver = { + .domainAgentSetResponseTimeout = qemuDomainAgentSetResponseTimeout, /* 5.10.0 */ + .domainBackupBegin = qemuDomainBackupBegin, /* 6.0.0 */ + .domainBackupGetXMLDesc = qemuDomainBackupGetXMLDesc, /* 6.0.0 */ ++ .domainHotpatchManage = qemuDomainHotpatchManage, /* 6.2.0 */ + }; + + +diff --git a/src/qemu/qemu_hotpatch.c b/src/qemu/qemu_hotpatch.c +new file mode 100644 +index 0000000000..45796b3f24 +--- /dev/null ++++ b/src/qemu/qemu_hotpatch.c +@@ -0,0 +1,182 @@ ++/* ++ * huawei_qemu_hotpatch.h: huawei qemu hotpatch functions ++ * ++ * Copyright (C) 2021-2021 HUAWEI, Inc. ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library. If not, see ++ * . ++ * ++ */ ++ ++ ++#include ++#include "viralloc.h" ++#include "virerror.h" ++#include "virfile.h" ++#include "virlog.h" ++#include "vircommand.h" ++#include "qemu/qemu_domain.h" ++#include "qemu_hotpatch.h" ++ ++#define LIBCARE_CTL "libcare-ctl" ++#define LIBCARE_ERROR_NUMBER 255 ++#define MAX_PATCHID_LEN 8 ++ ++#define VIR_FROM_THIS VIR_FROM_QEMU ++ ++VIR_LOG_INIT("qemu_hotpatch"); ++ ++char * ++qemuDomainHotpatchQuery(virDomainObjPtr vm) ++{ ++ g_autoptr(virCommand) cmd = NULL; ++ g_autofree char *binary = NULL; ++ char *output = NULL; ++ int ret = -1; ++ ++ if (!(binary = virFindFileInPath(LIBCARE_CTL))) { ++ virReportError(VIR_ERR_OPERATION_FAILED, "%s", ++ _("Failed to find libcare-ctl command.")); ++ return NULL; ++ } ++ ++ cmd = virCommandNewArgList(binary, "info", "-p", NULL); ++ virCommandAddArgFormat(cmd, "%d", vm->pid); ++ virCommandSetOutputBuffer(cmd, &output); ++ ++ VIR_DEBUG("Querying hotpatch for domain %s. (%s info -p %d)", ++ vm->def->name, binary, vm->pid); ++ ++ if (virCommandRun(cmd, &ret) < 0) ++ goto error; ++ ++ if (ret == LIBCARE_ERROR_NUMBER) { ++ virReportError(VIR_ERR_OPERATION_FAILED, "%s", ++ _("Failed to execute libcare-ctl command.")); ++ goto error; ++ } ++ return output; ++ ++ error: ++ VIR_FREE(output); ++ return NULL; ++} ++ ++char * ++qemuDomainHotpatchApply(virDomainObjPtr vm, ++ const char *patch) ++{ ++ g_autoptr(virCommand) cmd = NULL; ++ g_autofree char *binary = NULL; ++ char *output = NULL; ++ int ret = -1; ++ ++ if (!patch || !virFileExists(patch)) { ++ virReportError(VIR_ERR_INVALID_ARG, ++ "%s", _("Invalid hotpatch file.")); ++ return NULL; ++ } ++ ++ if (!(binary = virFindFileInPath(LIBCARE_CTL))) { ++ virReportError(VIR_ERR_OPERATION_FAILED, ++ "%s", _("Failed to find libcare-ctl command.")); ++ return NULL; ++ } ++ ++ cmd = virCommandNewArgList(binary, "patch", "-p", NULL); ++ virCommandAddArgFormat(cmd, "%d", vm->pid); ++ virCommandAddArgList(cmd, patch, NULL); ++ virCommandSetOutputBuffer(cmd, &output); ++ ++ VIR_DEBUG("Applying hotpatch for domain %s. (%s patch -p %d %s)", ++ vm->def->name, binary, vm->pid, patch); ++ ++ if (virCommandRun(cmd, &ret) < 0) ++ goto error; ++ ++ if (ret == LIBCARE_ERROR_NUMBER) { ++ virReportError(VIR_ERR_OPERATION_FAILED, "%s", ++ _("Failed to execute libcare-ctl command.")); ++ goto error; ++ } ++ return output; ++ ++ error: ++ VIR_FREE(output); ++ return NULL; ++} ++ ++static bool ++qemuDomainHotpatchIsPatchidValid(const char *id) ++{ ++ size_t len, i; ++ ++ if (!id) ++ return false; ++ ++ len = strlen(id); ++ if (len > MAX_PATCHID_LEN - 1) ++ return false; ++ ++ for (i = 0; i < len; i++) { ++ if (!g_ascii_isalnum(*(id + i))) ++ return false; ++ } ++ ++ return true; ++} ++ ++char * ++qemuDomainHotpatchUnapply(virDomainObjPtr vm, ++ const char *id) ++{ ++ g_autoptr(virCommand) cmd = NULL; ++ g_autofree char *binary = NULL; ++ char *output = NULL; ++ int ret = -1; ++ ++ if (!id || !qemuDomainHotpatchIsPatchidValid(id)) { ++ virReportError(VIR_ERR_INVALID_ARG, ++ "%s", _("Invalid hotpatch id.")); ++ return NULL; ++ } ++ ++ if (!(binary = virFindFileInPath(LIBCARE_CTL))) { ++ virReportError(VIR_ERR_OPERATION_FAILED, ++ "%s", _("Failed to find libcare-ctl command.")); ++ return NULL; ++ } ++ ++ cmd = virCommandNewArgList(binary, "unpatch", "-p", NULL); ++ virCommandAddArgFormat(cmd, "%d", vm->pid); ++ virCommandAddArgList(cmd, "-i", id, NULL); ++ virCommandSetOutputBuffer(cmd, &output); ++ ++ VIR_DEBUG("Unapplying hotpatch for domain %s. (%s unpatch -p %d -i %s)", ++ vm->def->name, binary, vm->pid, id); ++ ++ if (virCommandRun(cmd, &ret) < 0) ++ goto error; ++ ++ if (ret == LIBCARE_ERROR_NUMBER) { ++ virReportError(VIR_ERR_OPERATION_FAILED, "%s", ++ _("Failed to execute libcare-ctl command.")); ++ goto error; ++ } ++ return output; ++ ++ error: ++ VIR_FREE(output); ++ return NULL; ++} +diff --git a/src/qemu/qemu_hotpatch.h b/src/qemu/qemu_hotpatch.h +new file mode 100644 +index 0000000000..4c84a57950 +--- /dev/null ++++ b/src/qemu/qemu_hotpatch.h +@@ -0,0 +1,36 @@ ++/* ++ * huawei_qemu_hotpatch.h: huawei qemu hotpatch functions ++ * ++ * Copyright (C) 2021-2021 HUAWEI, Inc. ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library. If not, see ++ * . ++ * ++ */ ++ ++#pragma once ++ ++#include ++#include "qemu/qemu_conf.h" ++ ++char * ++qemuDomainHotpatchQuery(virDomainObjPtr vm); ++ ++char * ++qemuDomainHotpatchApply(virDomainObjPtr vm, ++ const char *patch); ++ ++char * ++qemuDomainHotpatchUnapply(virDomainObjPtr vm, ++ const char *id); +-- +2.27.0 + diff --git a/hotpatch-check-vm-id-and-pid-before-using-hotpatch-a.patch b/hotpatch-check-vm-id-and-pid-before-using-hotpatch-a.patch new file mode 100644 index 0000000000000000000000000000000000000000..13d997c3364985fffd88de1446d769b24badaf8b --- /dev/null +++ b/hotpatch-check-vm-id-and-pid-before-using-hotpatch-a.patch @@ -0,0 +1,135 @@ +From 58121fbc3085296364e6b90bc16cb56eeaf36f77 Mon Sep 17 00:00:00 2001 +From: AlexChen +Date: Fri, 9 Jul 2021 10:50:07 +0800 +Subject: [PATCH] hotpatch: check vm id and pid before using hotpatch api + +Check if the vm is alive before using hotpatch api by calling +virDomainObjCheckActive() to check vm id and calling +qemuDomainHotpatchCheckPid() to check vm pid. + +Signed-off-by: Bihong Yu +Signed-off-by: AlexChen +--- + src/qemu/qemu_driver.c | 3 +++ + src/qemu/qemu_hotpatch.c | 36 ++++++++++++++++++++++++++++++------ + 2 files changed, 33 insertions(+), 6 deletions(-) + +diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c +index d4c5f073bb..2b24881f75 100644 +--- a/src/qemu/qemu_driver.c ++++ b/src/qemu/qemu_driver.c +@@ -23196,6 +23196,9 @@ qemuDomainHotpatchManage(virDomainPtr domain, + VIR_DOMAIN_JOB_OPERATION_HOTPATCH, 0) < 0) + goto cleanup; + ++ if (virDomainObjCheckActive(vm) < 0) ++ goto endjob; ++ + qemuDomainObjSetAsyncJobMask(vm, QEMU_JOB_DEFAULT_MASK); + + switch (action) { +diff --git a/src/qemu/qemu_hotpatch.c b/src/qemu/qemu_hotpatch.c +index 45796b3f24..03e63c1341 100644 +--- a/src/qemu/qemu_hotpatch.c ++++ b/src/qemu/qemu_hotpatch.c +@@ -37,12 +37,25 @@ + + VIR_LOG_INIT("qemu_hotpatch"); + ++static int ++qemuDomainHotpatchCheckPid(pid_t pid) ++{ ++ if (pid <= 0) { ++ virReportError(VIR_ERR_INVALID_ARG, ++ "%s", _("Invalid pid")); ++ return -1; ++ } ++ ++ return 0; ++} ++ + char * + qemuDomainHotpatchQuery(virDomainObjPtr vm) + { + g_autoptr(virCommand) cmd = NULL; + g_autofree char *binary = NULL; + char *output = NULL; ++ pid_t pid = vm->pid; + int ret = -1; + + if (!(binary = virFindFileInPath(LIBCARE_CTL))) { +@@ -51,12 +64,15 @@ qemuDomainHotpatchQuery(virDomainObjPtr vm) + return NULL; + } + ++ if (qemuDomainHotpatchCheckPid(pid) < 0) ++ return NULL; ++ + cmd = virCommandNewArgList(binary, "info", "-p", NULL); +- virCommandAddArgFormat(cmd, "%d", vm->pid); ++ virCommandAddArgFormat(cmd, "%d", pid); + virCommandSetOutputBuffer(cmd, &output); + + VIR_DEBUG("Querying hotpatch for domain %s. (%s info -p %d)", +- vm->def->name, binary, vm->pid); ++ vm->def->name, binary, pid); + + if (virCommandRun(cmd, &ret) < 0) + goto error; +@@ -80,6 +96,7 @@ qemuDomainHotpatchApply(virDomainObjPtr vm, + g_autoptr(virCommand) cmd = NULL; + g_autofree char *binary = NULL; + char *output = NULL; ++ pid_t pid = vm->pid; + int ret = -1; + + if (!patch || !virFileExists(patch)) { +@@ -94,13 +111,16 @@ qemuDomainHotpatchApply(virDomainObjPtr vm, + return NULL; + } + ++ if (qemuDomainHotpatchCheckPid(pid) < 0) ++ return NULL; ++ + cmd = virCommandNewArgList(binary, "patch", "-p", NULL); +- virCommandAddArgFormat(cmd, "%d", vm->pid); ++ virCommandAddArgFormat(cmd, "%d", pid); + virCommandAddArgList(cmd, patch, NULL); + virCommandSetOutputBuffer(cmd, &output); + + VIR_DEBUG("Applying hotpatch for domain %s. (%s patch -p %d %s)", +- vm->def->name, binary, vm->pid, patch); ++ vm->def->name, binary, pid, patch); + + if (virCommandRun(cmd, &ret) < 0) + goto error; +@@ -144,6 +164,7 @@ qemuDomainHotpatchUnapply(virDomainObjPtr vm, + g_autoptr(virCommand) cmd = NULL; + g_autofree char *binary = NULL; + char *output = NULL; ++ pid_t pid = vm->pid; + int ret = -1; + + if (!id || !qemuDomainHotpatchIsPatchidValid(id)) { +@@ -158,13 +179,16 @@ qemuDomainHotpatchUnapply(virDomainObjPtr vm, + return NULL; + } + ++ if (qemuDomainHotpatchCheckPid(pid) < 0) ++ return NULL; ++ + cmd = virCommandNewArgList(binary, "unpatch", "-p", NULL); +- virCommandAddArgFormat(cmd, "%d", vm->pid); ++ virCommandAddArgFormat(cmd, "%d", pid); + virCommandAddArgList(cmd, "-i", id, NULL); + virCommandSetOutputBuffer(cmd, &output); + + VIR_DEBUG("Unapplying hotpatch for domain %s. (%s unpatch -p %d -i %s)", +- vm->def->name, binary, vm->pid, id); ++ vm->def->name, binary, pid, id); + + if (virCommandRun(cmd, &ret) < 0) + goto error; +-- +2.27.0 + diff --git a/hotpatch-implement-hotpatch-virsh-api.patch b/hotpatch-implement-hotpatch-virsh-api.patch new file mode 100644 index 0000000000000000000000000000000000000000..552ae2dda8d20bb8266739d61eda1bca9fbb6bac --- /dev/null +++ b/hotpatch-implement-hotpatch-virsh-api.patch @@ -0,0 +1,110 @@ +From cf380e22898f70f5782bcea8b0d22027ff7d86af Mon Sep 17 00:00:00 2001 +From: AlexChen +Date: Wed, 20 Oct 2021 11:07:34 +0800 +Subject: [PATCH] hotpatch: implement hotpatch virsh api + +Signed-off-by: Hao Wang +Signed-off-by: Bihong Yu +Signed-off-by: AlexChen +--- + tools/virsh-domain.c | 78 ++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 78 insertions(+) + +diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c +index f643bd403e..813be4a0db 100644 +--- a/tools/virsh-domain.c ++++ b/tools/virsh-domain.c +@@ -14326,6 +14326,78 @@ cmdGuestInfo(vshControl *ctl, const vshCmd *cmd) + return ret; + } + ++/* ++ * "hotpatch" command ++ */ ++static const vshCmdInfo info_hotpatch[] = { ++ {.name = "help", ++ .data = N_("Manage hotpatch of a live domain") ++ }, ++ {.name = "desc", ++ .data = N_("Manage hotpatch of a live domain") ++ }, ++ {.name = NULL} ++}; ++ ++static const vshCmdOptDef opts_hotpatch[] = { ++ VIRSH_COMMON_OPT_DOMAIN_FULL(0), ++ {.name = "action", ++ .type = VSH_OT_DATA, ++ .flags = VSH_OFLAG_REQ, ++ .help = N_("hotpatch action, choose from , and ") ++ }, ++ {.name = "patch", ++ .type = VSH_OT_STRING, ++ .help = N_("the absolute path of the hotpatch file, mandatory when action=apply") ++ }, ++ {.name = "id", ++ .type = VSH_OT_STRING, ++ .help = N_("the unique id of the target patch, mandatory when action=unapply") ++ }, ++ {.name = NULL} ++}; ++ ++VIR_ENUM_DECL(virDomainHotpatchAction); ++VIR_ENUM_IMPL(virDomainHotpatchAction, ++ VIR_DOMAIN_HOTPATCH_LAST, ++ "none", ++ "apply", ++ "unapply", ++ "query"); ++ ++static bool ++cmdHotpatch(vshControl *ctl, ++ const vshCmd *cmd) ++{ ++ g_autoptr(virshDomain) dom = NULL; ++ const char *patch = NULL; ++ const char *id = NULL; ++ const char *actionstr = NULL; ++ int action = -1; ++ g_autofree char *ret = NULL; ++ ++ if (!(dom = virshCommandOptDomain(ctl, cmd, NULL))) ++ return false; ++ ++ if (vshCommandOptStringReq(ctl, cmd, "action", &actionstr) < 0) ++ return false; ++ ++ if (actionstr) ++ action = virDomainHotpatchActionTypeFromString(actionstr); ++ ++ if (vshCommandOptStringReq(ctl, cmd, "patch", &patch) < 0) ++ return false; ++ ++ if (vshCommandOptStringReq(ctl, cmd, "id", &id) < 0) ++ return false; ++ ++ if (!(ret = virDomainHotpatchManage(dom, action, patch, id, 0))) ++ return false; ++ ++ vshPrint(ctl, _("%s"), ret); ++ return true; ++} ++ + const vshCmdDef domManagementCmds[] = { + {.name = "attach-device", + .handler = cmdAttachDevice, +@@ -14953,5 +15025,11 @@ const vshCmdDef domManagementCmds[] = { + .info = info_guestinfo, + .flags = 0 + }, ++ {.name = "hotpatch", ++ .handler = cmdHotpatch, ++ .opts = opts_hotpatch, ++ .info = info_hotpatch, ++ .flags = 0 ++ }, + {.name = NULL} + }; +-- +2.27.0 + diff --git a/hotpatch-introduce-hotpatch-async-job-flag.patch b/hotpatch-introduce-hotpatch-async-job-flag.patch new file mode 100644 index 0000000000000000000000000000000000000000..24f1611410ace86ce95e81c3629b6bc9ec3d4f05 --- /dev/null +++ b/hotpatch-introduce-hotpatch-async-job-flag.patch @@ -0,0 +1,155 @@ +From a83bb0dc19d7c92c200b9a234e120d16878eac19 Mon Sep 17 00:00:00 2001 +From: AlexChen +Date: Tue, 19 Oct 2021 22:41:24 +0800 +Subject: [PATCH] hotpatch: introduce hotpatch async job flag + +Signed-off-by: Hao Wang +Signed-off-by: Bihong Yu +Signed-off-by: AlexChen +--- + include/libvirt/libvirt-domain.h | 1 + + src/qemu/qemu_domain.c | 3 +++ + src/qemu/qemu_domain.h | 1 + + src/qemu/qemu_driver.c | 13 +++++++++++++ + src/qemu/qemu_migration.c | 2 ++ + src/qemu/qemu_process.c | 1 + + tools/virsh-domain.c | 1 + + 7 files changed, 22 insertions(+) + +diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h +index f91061724b..2d6432cab2 100644 +--- a/include/libvirt/libvirt-domain.h ++++ b/include/libvirt/libvirt-domain.h +@@ -3295,6 +3295,7 @@ typedef enum { + VIR_DOMAIN_JOB_OPERATION_SNAPSHOT_REVERT = 7, + VIR_DOMAIN_JOB_OPERATION_DUMP = 8, + VIR_DOMAIN_JOB_OPERATION_BACKUP = 9, ++ VIR_DOMAIN_JOB_OPERATION_HOTPATCH = 10, + + # ifdef VIR_ENUM_SENTINELS + VIR_DOMAIN_JOB_OPERATION_LAST +diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c +index 5d35d49638..2351cac120 100644 +--- a/src/qemu/qemu_domain.c ++++ b/src/qemu/qemu_domain.c +@@ -111,6 +111,7 @@ VIR_ENUM_IMPL(qemuDomainAsyncJob, + "snapshot", + "start", + "backup", ++ "hotpatch", + ); + + VIR_ENUM_IMPL(qemuDomainNamespace, +@@ -217,6 +218,7 @@ qemuDomainAsyncJobPhaseToString(qemuDomainAsyncJob job, + case QEMU_ASYNC_JOB_START: + case QEMU_ASYNC_JOB_NONE: + case QEMU_ASYNC_JOB_BACKUP: ++ case QEMU_ASYNC_JOB_HOTPATCH: + G_GNUC_FALLTHROUGH; + case QEMU_ASYNC_JOB_LAST: + break; +@@ -243,6 +245,7 @@ qemuDomainAsyncJobPhaseFromString(qemuDomainAsyncJob job, + case QEMU_ASYNC_JOB_START: + case QEMU_ASYNC_JOB_NONE: + case QEMU_ASYNC_JOB_BACKUP: ++ case QEMU_ASYNC_JOB_HOTPATCH: + G_GNUC_FALLTHROUGH; + case QEMU_ASYNC_JOB_LAST: + break; +diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h +index cf19f4d101..678ddab624 100644 +--- a/src/qemu/qemu_domain.h ++++ b/src/qemu/qemu_domain.h +@@ -107,6 +107,7 @@ typedef enum { + QEMU_ASYNC_JOB_SNAPSHOT, + QEMU_ASYNC_JOB_START, + QEMU_ASYNC_JOB_BACKUP, ++ QEMU_ASYNC_JOB_HOTPATCH, + + QEMU_ASYNC_JOB_LAST + } qemuDomainAsyncJob; +diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c +index f6d99957a5..d4c5f073bb 100644 +--- a/src/qemu/qemu_driver.c ++++ b/src/qemu/qemu_driver.c +@@ -13866,6 +13866,9 @@ static int qemuDomainAbortJob(virDomainPtr dom) + ret = 0; + break; + ++ case QEMU_ASYNC_JOB_HOTPATCH: ++ break; ++ + case QEMU_ASYNC_JOB_LAST: + default: + virReportEnumRangeError(qemuDomainAsyncJob, priv->job.asyncJob); +@@ -23180,6 +23183,7 @@ qemuDomainHotpatchManage(virDomainPtr domain, + unsigned int flags) + { + virDomainObjPtr vm; ++ virQEMUDriverPtr driver = domain->conn->privateData; + char *ret = NULL; + size_t len; + +@@ -23188,6 +23192,12 @@ qemuDomainHotpatchManage(virDomainPtr domain, + if (!(vm = qemuDomainObjFromDomain(domain))) + goto cleanup; + ++ if (qemuDomainObjBeginAsyncJob(driver, vm, QEMU_ASYNC_JOB_HOTPATCH, ++ VIR_DOMAIN_JOB_OPERATION_HOTPATCH, 0) < 0) ++ goto cleanup; ++ ++ qemuDomainObjSetAsyncJobMask(vm, QEMU_JOB_DEFAULT_MASK); ++ + switch (action) { + case VIR_DOMAIN_HOTPATCH_APPLY: + ret = qemuDomainHotpatchApply(vm, patch); +@@ -23214,6 +23224,9 @@ qemuDomainHotpatchManage(virDomainPtr domain, + if (len > 0) + ret[len - 1] = '\0'; + ++ endjob: ++ qemuDomainObjEndAsyncJob(driver, vm); ++ + cleanup: + virDomainObjEndAPI(&vm); + return ret; +diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c +index 3f4627bd39..1665071eb3 100644 +--- a/src/qemu/qemu_migration.c ++++ b/src/qemu/qemu_migration.c +@@ -1532,6 +1532,8 @@ qemuMigrationJobName(virDomainObjPtr vm) + return _("start job"); + case QEMU_ASYNC_JOB_BACKUP: + return _("backup job"); ++ case QEMU_ASYNC_JOB_HOTPATCH: ++ return _("hotpatch job"); + case QEMU_ASYNC_JOB_LAST: + default: + return _("job"); +diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c +index 9cf7242f31..818a72d8f9 100644 +--- a/src/qemu/qemu_process.c ++++ b/src/qemu/qemu_process.c +@@ -3646,6 +3646,7 @@ qemuProcessRecoverJob(virQEMUDriverPtr driver, + priv->job.current->started = now; + break; + ++ case QEMU_ASYNC_JOB_HOTPATCH: + case QEMU_ASYNC_JOB_NONE: + case QEMU_ASYNC_JOB_LAST: + break; +diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c +index 65d5c831ec..f643bd403e 100644 +--- a/tools/virsh-domain.c ++++ b/tools/virsh-domain.c +@@ -6167,6 +6167,7 @@ VIR_ENUM_IMPL(virshDomainJobOperation, + N_("Snapshot revert"), + N_("Dump"), + N_("Backup"), ++ N_("Hotpatch"), + ); + + static const char * +-- +2.27.0 + diff --git a/libvirt.spec b/libvirt.spec index 72b971ce8f114c4ff7b06ab7d7ab890af8778b18..9f9b3cbb26d546b6401ff5ad1ba66eda46efa830 100644 --- a/libvirt.spec +++ b/libvirt.spec @@ -105,7 +105,7 @@ Summary: Library providing a simple virtualization API Name: libvirt Version: 6.2.0 -Release: 26 +Release: 27 License: LGPLv2+ URL: https://libvirt.org/ @@ -190,6 +190,12 @@ Patch0073: virDevMapperGetTargets-Don-t-ignore-EBADF.patch Patch0074: conf-domain_conf-pin-the-retry_interval-and-retry_ti.patch Patch0075: storage_driver-Unlock-object-on-ACL-fail-in-storageP.patch Patch0076: security-fix-SELinux-label-generation-logic.patch +Patch0077: Hotpatch-introduce-DomainHotpatchManage-API.patch +Patch0078: hotpatch-Implement-qemuDomainHotpatchManage.patch +Patch0079: hotpatch-introduce-hotpatch-async-job-flag.patch +Patch0080: hotpatch-implement-hotpatch-virsh-api.patch +Patch0081: hotpatch-check-vm-id-and-pid-before-using-hotpatch-a.patch +Patch0082: domain-add-logs-for-virDomainHotpatchManage.patch Requires: libvirt-daemon = %{version}-%{release} Requires: libvirt-daemon-config-network = %{version}-%{release} @@ -1923,6 +1929,16 @@ exit 0 %changelog +* Mon Dec 06 2021 Euler Robot +- hotpatch: implement hotpatch virsh api +- hotpatch: check vm id and pid before using hotpatch api +- domain: add logs for virDomainHotpatchManage + +* Mon Dec 06 2021 Euler Robot +- Hotpatch: introduce DomainHotpatchManage API +- hotpatch: Implement qemuDomainHotpatchManage +- hotpatch: introduce hotpatch async job flag + * Sun Sep 26 2021 imxcc - fix cve-2021-3667 cve-2021-3631