b03b5ee4创建于 2024年4月12日历史提交
From 2721c0ce65045c90e54fcab383d4af83415bd3f3 Mon Sep 17 00:00:00 2001
From: AlexChen <alex.chen@huawei.com>
Date: Tue, 19 Oct 2021 14:50:32 +0800
Subject: [PATCH] hotpatch: Implement qemuDomainHotpatchManage

Signed-off-by: Hao Wang <wanghao232@huawei.com>
Signed-off-by: Bihong Yu <yubihong@huawei.com>
Signed-off-by: AlexChen <alex.chen@huawei.com>
---
 include/libvirt/libvirt-domain.h |  10 +-
 src/libvirt-domain.c             |   2 +-
 src/libvirt_public.syms          |   2 +-
 src/qemu/meson.build             |   1 +
 src/qemu/qemu_driver.c           |  48 ++++++++
 src/qemu/qemu_hotpatch.c         | 182 +++++++++++++++++++++++++++++++
 src/qemu/qemu_hotpatch.h         |  36 ++++++
 7 files changed, 274 insertions(+), 7 deletions(-)
 create mode 100644 src/qemu/qemu_hotpatch.c
 create mode 100644 src/qemu/qemu_hotpatch.h

diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index f8def59032..e786ecfab2 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -6422,13 +6422,13 @@ int virDomainAuthorizedSSHKeysGet(virDomainPtr domain,
  * Since: 6.2.0
  */
 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 */
+    VIR_DOMAIN_HOTPATCH_NONE = 0, /* No action (Since: 6.2.0) */
+    VIR_DOMAIN_HOTPATCH_APPLY,    /* Apply hotpatch (Since: 6.2.0) */
+    VIR_DOMAIN_HOTPATCH_UNAPPLY,  /* Unapply hotpatch (Since: 6.2.0) */
+    VIR_DOMAIN_HOTPATCH_QUERY,    /* Query hotpatch (Since: 6.2.0) */
 
 # ifdef VIR_ENUM_SENTINELS
-    VIR_DOMAIN_HOTPATCH_LAST
+    VIR_DOMAIN_HOTPATCH_LAST      /* Last index (Since: 6.2.0) */
 # endif
 } virDomainHotpatchAction;
 
diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
index 26833efd0e..21b01110fe 100644
--- a/src/libvirt-domain.c
+++ b/src/libvirt-domain.c
@@ -13805,7 +13805,7 @@ virDomainBackupGetXMLDesc(virDomainPtr domain,
  *
  * Returns success messages in case of success, NULL otherwise.
  *
- * Since: 6.10.0
+ * Since: 6.2.0
  */
 char *
 virDomainHotpatchManage(virDomainPtr domain,
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 52a5d03240..8b38fe9a5f 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -882,7 +882,7 @@ LIBVIRT_6.10.0 {
     global:
         virDomainAuthorizedSSHKeysGet;
         virDomainAuthorizedSSHKeysSet;
-} LIBVIRT_6.0.0;
+} LIBVIRT_6.2.0;
 
 LIBVIRT_7.1.0 {
     global:
diff --git a/src/qemu/meson.build b/src/qemu/meson.build
index 2279fef2ca..9d5b4da35d 100644
--- a/src/qemu/meson.build
+++ b/src/qemu/meson.build
@@ -42,6 +42,7 @@ qemu_driver_sources = [
   'qemu_vhost_user.c',
   'qemu_vhost_user_gpu.c',
   'qemu_virtiofs.c',
+  'qemu_hotpatch.c',
 ]
 
 driver_source_files += files(qemu_driver_sources)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index d00d2a27c6..3dd82d6f12 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -105,6 +105,7 @@
 #include "virdomaincheckpointobjlist.h"
 #include "virutil.h"
 #include "backup_conf.h"
+#include "qemu_hotpatch.h"
 
 #define VIR_FROM_THIS VIR_FROM_QEMU
 
@@ -19934,6 +19935,52 @@ qemuDomainFDAssociate(virDomainPtr domain,
     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,
@@ -20178,6 +20225,7 @@ static virHypervisorDriver qemuHypervisorDriver = {
     .domainAgentSetResponseTimeout = qemuDomainAgentSetResponseTimeout, /* 5.10.0 */
     .domainBackupBegin = qemuDomainBackupBegin, /* 6.0.0 */
     .domainBackupGetXMLDesc = qemuDomainBackupGetXMLDesc, /* 6.0.0 */
+    .domainHotpatchManage = qemuDomainHotpatchManage, /* 6.2.0 */
     .domainAuthorizedSSHKeysGet = qemuDomainAuthorizedSSHKeysGet, /* 6.10.0 */
     .domainAuthorizedSSHKeysSet = qemuDomainAuthorizedSSHKeysSet, /* 6.10.0 */
     .domainGetMessages = qemuDomainGetMessages, /* 7.1.0 */
diff --git a/src/qemu/qemu_hotpatch.c b/src/qemu/qemu_hotpatch.c
new file mode 100644
index 0000000000..c1a4ab7aca
--- /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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#include <unistd.h>
+#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(virDomainObj *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(virDomainObj *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(virDomainObj *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..3cf22f7fc4
--- /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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include <unistd.h>
+#include "qemu/qemu_conf.h"
+
+char *
+qemuDomainHotpatchQuery(virDomainObj *vm);
+
+char *
+qemuDomainHotpatchApply(virDomainObj *vm,
+                        const char *patch);
+
+char *
+qemuDomainHotpatchUnapply(virDomainObj *vm,
+                          const char *id);
-- 
2.27.0