406 lines
13 KiB
Diff
406 lines
13 KiB
Diff
|
|
From cd0f3755bd04bb58089d756400f20c75550e54f2 Mon Sep 17 00:00:00 2001
|
||
|
|
From: tujipei <tujipei@huawei.com>
|
||
|
|
Date: Wed, 12 Jun 2024 12:02:00 +0800
|
||
|
|
Subject: [PATCH] libvirt: add get tmm memory info API and libvirtd RPC Add the
|
||
|
|
get tmm memory info API into libvirt-host. Also should add the RPC calls into
|
||
|
|
libvirtd for API calling.
|
||
|
|
|
||
|
|
Signed-off-by: tujipei <tujipei@huawei.com>
|
||
|
|
---
|
||
|
|
include/libvirt/libvirt-host.h | 2 +
|
||
|
|
scripts/apibuild.py | 1 +
|
||
|
|
scripts/check-aclrules.py | 1 +
|
||
|
|
src/driver-hypervisor.h | 5 +
|
||
|
|
src/libvirt-host.c | 35 +++++++
|
||
|
|
src/libvirt_public.syms | 1 +
|
||
|
|
src/qemu/qemu_driver.c | 139 ++++++++++++++++++++++++++++
|
||
|
|
src/remote/remote_daemon_dispatch.c | 23 +++++
|
||
|
|
src/remote/remote_driver.c | 29 ++++++
|
||
|
|
src/remote/remote_protocol.x | 16 +++-
|
||
|
|
10 files changed, 251 insertions(+), 1 deletion(-)
|
||
|
|
|
||
|
|
diff --git a/include/libvirt/libvirt-host.h b/include/libvirt/libvirt-host.h
|
||
|
|
index 6972834175..e7272ccb20 100644
|
||
|
|
--- a/include/libvirt/libvirt-host.h
|
||
|
|
+++ b/include/libvirt/libvirt-host.h
|
||
|
|
@@ -820,5 +820,7 @@ int virNodeAllocPages(virConnectPtr conn,
|
||
|
|
unsigned int cellCount,
|
||
|
|
unsigned int flags);
|
||
|
|
|
||
|
|
+char *virConnectGetTmmMemoryInfo(virConnectPtr conn,
|
||
|
|
+ unsigned int detail);
|
||
|
|
|
||
|
|
#endif /* LIBVIRT_HOST_H */
|
||
|
|
diff --git a/scripts/apibuild.py b/scripts/apibuild.py
|
||
|
|
index c98bcf6091..9b78754e5d 100755
|
||
|
|
--- a/scripts/apibuild.py
|
||
|
|
+++ b/scripts/apibuild.py
|
||
|
|
@@ -107,6 +107,7 @@ ignored_functions = {
|
||
|
|
"virDomainMigrateConfirm3Params": "private function for migration",
|
||
|
|
"virDomainMigratePrepareTunnel3Params": "private function for tunnelled migration",
|
||
|
|
"virErrorCopyNew": "private",
|
||
|
|
+ "virConnectGetTmmMemoryInfo": "private function for tmm",
|
||
|
|
}
|
||
|
|
|
||
|
|
ignored_macros = {
|
||
|
|
diff --git a/scripts/check-aclrules.py b/scripts/check-aclrules.py
|
||
|
|
index e196f81de9..aa5a589c85 100755
|
||
|
|
--- a/scripts/check-aclrules.py
|
||
|
|
+++ b/scripts/check-aclrules.py
|
||
|
|
@@ -54,6 +54,7 @@ whitelist = {
|
||
|
|
"localOnly": True,
|
||
|
|
"domainQemuAttach": True,
|
||
|
|
"domainHotpatchManage": True,
|
||
|
|
+ "connectGetTmmMemoryInfo": True,
|
||
|
|
}
|
||
|
|
|
||
|
|
# XXX this vzDomainMigrateConfirm3Params looks
|
||
|
|
diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h
|
||
|
|
index 82f808905d..e48b701365 100644
|
||
|
|
--- a/src/driver-hypervisor.h
|
||
|
|
+++ b/src/driver-hypervisor.h
|
||
|
|
@@ -1402,6 +1402,10 @@ typedef int
|
||
|
|
typedef struct _virHypervisorDriver virHypervisorDriver;
|
||
|
|
typedef virHypervisorDriver *virHypervisorDriverPtr;
|
||
|
|
|
||
|
|
+typedef char *
|
||
|
|
+(*virDrvConnectGetTmmMemoryInfo)(virConnectPtr conn,
|
||
|
|
+ bool detail);
|
||
|
|
+
|
||
|
|
/**
|
||
|
|
* _virHypervisorDriver:
|
||
|
|
*
|
||
|
|
@@ -1664,4 +1668,5 @@ struct _virHypervisorDriver {
|
||
|
|
virDrvDomainBackupGetXMLDesc domainBackupGetXMLDesc;
|
||
|
|
virDrvDomainHotpatchManage domainHotpatchManage;
|
||
|
|
virDrvDomainStartDirtyRateCalc domainStartDirtyRateCalc;
|
||
|
|
+ virDrvConnectGetTmmMemoryInfo connectGetTmmMemoryInfo;
|
||
|
|
};
|
||
|
|
diff --git a/src/libvirt-host.c b/src/libvirt-host.c
|
||
|
|
index bc3d1d2803..d0750d28cc 100644
|
||
|
|
--- a/src/libvirt-host.c
|
||
|
|
+++ b/src/libvirt-host.c
|
||
|
|
@@ -1754,3 +1754,38 @@ virNodeGetSEVInfo(virConnectPtr conn,
|
||
|
|
virDispatchError(conn);
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * virConnectGetTmmMemoryInfo:
|
||
|
|
+ * @conn: pointer to the hypervisor connection
|
||
|
|
+ * @detail: whether libvirtd return detailed tmm memory information;
|
||
|
|
+ * the default value is 0 which means don't return detailed tmm memory information.
|
||
|
|
+ *
|
||
|
|
+ * If Tmm enable, then will fill the cotents of string buffer with tmm memory information.
|
||
|
|
+ *
|
||
|
|
+ * Returns string ptr in case of success, and NULL in case of failure.
|
||
|
|
+ */
|
||
|
|
+char *
|
||
|
|
+virConnectGetTmmMemoryInfo(virConnectPtr conn,
|
||
|
|
+ unsigned int detail)
|
||
|
|
+{
|
||
|
|
+ VIR_DEBUG("conn=%p", conn);
|
||
|
|
+
|
||
|
|
+ virResetLastError();
|
||
|
|
+
|
||
|
|
+ virCheckConnectReturn(conn, NULL);
|
||
|
|
+
|
||
|
|
+ if (conn->driver->connectGetTmmMemoryInfo) {
|
||
|
|
+ char *ret;
|
||
|
|
+ ret = conn->driver->connectGetTmmMemoryInfo(conn, detail);
|
||
|
|
+ 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 f006516208..284b7f7873 100644
|
||
|
|
--- a/src/libvirt_public.syms
|
||
|
|
+++ b/src/libvirt_public.syms
|
||
|
|
@@ -877,5 +877,6 @@ LIBVIRT_6.2.0 {
|
||
|
|
global:
|
||
|
|
virDomainHotpatchManage;
|
||
|
|
virDomainStartDirtyRateCalc;
|
||
|
|
+ virConnectGetTmmMemoryInfo;
|
||
|
|
} LIBVIRT_6.0.0;
|
||
|
|
# .... define new API here using predicted next version number ....
|
||
|
|
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
|
||
|
|
index 77a139c66b..1e3f63a39a 100644
|
||
|
|
--- a/src/qemu/qemu_driver.c
|
||
|
|
+++ b/src/qemu/qemu_driver.c
|
||
|
|
@@ -23385,6 +23385,144 @@ qemuDomainStartDirtyRateCalc(virDomainPtr dom,
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
+static int
|
||
|
|
+qemuConnectTmmInfoListAppend(char ***targetInfoStrList,
|
||
|
|
+ char **infoStrList,
|
||
|
|
+ int targetNumaNum,
|
||
|
|
+ int *startIndex,
|
||
|
|
+ int maxListSize)
|
||
|
|
+{
|
||
|
|
+ char *numStart;
|
||
|
|
+ int numaNode, index, ret = 0;
|
||
|
|
+
|
||
|
|
+ for (index = *startIndex; index < maxListSize; index++) {
|
||
|
|
+ if (strlen(infoStrList[index]) == 0)
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ numStart = strstr(infoStrList[index], "node ");
|
||
|
|
+ if (!numStart)
|
||
|
|
+ return -1;
|
||
|
|
+
|
||
|
|
+ virSkipToDigit((const char **)(&numStart));
|
||
|
|
+ ret = virStrToLong_i(numStart, &numStart, 10, &numaNode);
|
||
|
|
+ if (ret < 0) {
|
||
|
|
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||
|
|
+ _("Failed to get current numa node"));
|
||
|
|
+ return ret;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (numaNode == targetNumaNum) {
|
||
|
|
+ ret = virStringListAdd(targetInfoStrList, infoStrList[index]);
|
||
|
|
+ if (ret < 0) {
|
||
|
|
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s [%d]",
|
||
|
|
+ _("Failed to get add info list member"), index);
|
||
|
|
+ return ret;
|
||
|
|
+ }
|
||
|
|
+ } else {
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ *startIndex = index;
|
||
|
|
+
|
||
|
|
+ return ret;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static char *
|
||
|
|
+qemuConnectTmmDetailInfoFormat(char *baseMeminfo,
|
||
|
|
+ char *slabInfo)
|
||
|
|
+{
|
||
|
|
+ int ret, i = 0, j = 0;
|
||
|
|
+ char *numStart, *numListStart, *format = NULL;
|
||
|
|
+ char **baseMeminfoSplits = virStringSplit(baseMeminfo, "\n", 0);
|
||
|
|
+ char **slabInfoSplits = virStringSplit(slabInfo, "\n", 0);
|
||
|
|
+ char **resultStrList = NULL;
|
||
|
|
+ int numaSize, numaIndex, headNumaNode;
|
||
|
|
+ ssize_t meminfoListSize = virStringListLength((const char * const *)baseMeminfoSplits);
|
||
|
|
+ ssize_t slabInfoSize = virStringListLength((const char * const *)slabInfoSplits);
|
||
|
|
+
|
||
|
|
+ numStart = strchr(baseMeminfoSplits[i], ':');
|
||
|
|
+ numListStart = strchr(baseMeminfoSplits[i], '(');
|
||
|
|
+ if (!numStart || !numListStart)
|
||
|
|
+ goto cleanup;
|
||
|
|
+
|
||
|
|
+ virSkipToDigit((const char **)(&numStart));
|
||
|
|
+ ret = virStrToLong_i(numStart, &numStart, 10, &numaSize);
|
||
|
|
+ if (ret < 0) {
|
||
|
|
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||
|
|
+ _("Failed to get available numa size"));
|
||
|
|
+ goto cleanup;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ ret = virStringListAdd(&resultStrList, baseMeminfoSplits[i++]);
|
||
|
|
+ if (ret < 0) {
|
||
|
|
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s [%d]",
|
||
|
|
+ _("Failed to get add base memory info list member"), (i - 1));
|
||
|
|
+ goto cleanup;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ virSkipToDigit((const char **)(&numListStart));
|
||
|
|
+ for (numaIndex = 0; *numListStart && numaIndex < numaSize; numaIndex++, numListStart++) {
|
||
|
|
+ ret = virStrToLong_i(numListStart, &numListStart, 10, &headNumaNode);
|
||
|
|
+ if (ret < 0) {
|
||
|
|
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||
|
|
+ _("Failed to get current numa node"));
|
||
|
|
+ goto cleanup;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ ret = qemuConnectTmmInfoListAppend(&resultStrList, baseMeminfoSplits, headNumaNode, &i, meminfoListSize);
|
||
|
|
+ if (ret < 0)
|
||
|
|
+ goto cleanup;
|
||
|
|
+ ret = qemuConnectTmmInfoListAppend(&resultStrList, slabInfoSplits, headNumaNode, &j, slabInfoSize);
|
||
|
|
+ if (ret < 0)
|
||
|
|
+ goto cleanup;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ format = virStringListJoin((const char **)resultStrList, "\n");
|
||
|
|
+
|
||
|
|
+ cleanup:
|
||
|
|
+ virStringListFree(baseMeminfoSplits);
|
||
|
|
+ virStringListFree(slabInfoSplits);
|
||
|
|
+ virStringListFree(resultStrList);
|
||
|
|
+ return format;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static char *
|
||
|
|
+qemuConnectGetTmmMemoryInfo(virConnectPtr conn G_GNUC_UNUSED,
|
||
|
|
+ bool detail)
|
||
|
|
+{
|
||
|
|
+ int maxLen = 10 * 1024;
|
||
|
|
+ char *meminfo = NULL;
|
||
|
|
+ g_autofree char *formatInfo = NULL;
|
||
|
|
+ g_autofree char *baseMeminfo = NULL;
|
||
|
|
+ g_autofree char *slabInfo = NULL;
|
||
|
|
+ g_autofree char *buddyInfo = NULL;
|
||
|
|
+
|
||
|
|
+ if (virFileReadAll("/sys/kernel/tmm/memory_info", maxLen, &baseMeminfo) < 0)
|
||
|
|
+ goto end;
|
||
|
|
+ if (detail && virFileReadAll("/sys/kernel/tmm/slab_info", maxLen, &slabInfo) < 0)
|
||
|
|
+ goto end;
|
||
|
|
+ if (detail && virFileReadAll("/sys/kernel/tmm/buddy_info", maxLen, &buddyInfo) < 0)
|
||
|
|
+ goto end;
|
||
|
|
+
|
||
|
|
+ if (detail) {
|
||
|
|
+ if (!virStringIsEmpty(baseMeminfo) && !virStringIsEmpty(slabInfo)) {
|
||
|
|
+ formatInfo = qemuConnectTmmDetailInfoFormat(baseMeminfo, slabInfo);
|
||
|
|
+ if (formatInfo == NULL)
|
||
|
|
+ goto end;
|
||
|
|
+ } else {
|
||
|
|
+ formatInfo = g_strdup_printf(_("%s%s"), baseMeminfo, slabInfo);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ meminfo = g_strdup_printf(_("%s\n%s"), formatInfo, buddyInfo);
|
||
|
|
+ } else {
|
||
|
|
+ meminfo = g_steal_pointer(&baseMeminfo);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+end:
|
||
|
|
+ return meminfo;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
|
||
|
|
static virHypervisorDriver qemuHypervisorDriver = {
|
||
|
|
.name = QEMU_DRIVER_NAME,
|
||
|
|
@@ -23627,6 +23765,7 @@ static virHypervisorDriver qemuHypervisorDriver = {
|
||
|
|
.domainBackupGetXMLDesc = qemuDomainBackupGetXMLDesc, /* 6.0.0 */
|
||
|
|
.domainHotpatchManage = qemuDomainHotpatchManage, /* 6.2.0 */
|
||
|
|
.domainStartDirtyRateCalc = qemuDomainStartDirtyRateCalc, /* 6.2.0 */
|
||
|
|
+ .connectGetTmmMemoryInfo = qemuConnectGetTmmMemoryInfo, /* 6.2.0 */
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
diff --git a/src/remote/remote_daemon_dispatch.c b/src/remote/remote_daemon_dispatch.c
|
||
|
|
index 0bbcc05235..a9763cee7b 100644
|
||
|
|
--- a/src/remote/remote_daemon_dispatch.c
|
||
|
|
+++ b/src/remote/remote_daemon_dispatch.c
|
||
|
|
@@ -7268,6 +7268,29 @@ remoteDispatchNetworkPortGetParameters(virNetServerPtr server G_GNUC_UNUSED,
|
||
|
|
return rv;
|
||
|
|
}
|
||
|
|
|
||
|
|
+static int
|
||
|
|
+remoteDispatchConnectGetTmmMemoryInfo(virNetServerPtr server G_GNUC_UNUSED,
|
||
|
|
+ virNetServerClientPtr client,
|
||
|
|
+ virNetMessagePtr msg G_GNUC_UNUSED,
|
||
|
|
+ virNetMessageErrorPtr rerr,
|
||
|
|
+ remote_connect_get_tmm_memory_info_args *args,
|
||
|
|
+ remote_connect_get_tmm_memory_info_ret *ret)
|
||
|
|
+{
|
||
|
|
+ int rv = -1;
|
||
|
|
+ char *meminfo = NULL;
|
||
|
|
+ virConnectPtr conn = remoteGetHypervisorConn(client);
|
||
|
|
+
|
||
|
|
+ if (conn && (meminfo = virConnectGetTmmMemoryInfo(conn, args->detail))) {
|
||
|
|
+ rv = 0;
|
||
|
|
+ ret->meminfo = meminfo;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (rv < 0)
|
||
|
|
+ virNetMessageSaveError(rerr);
|
||
|
|
+
|
||
|
|
+ return rv;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
|
||
|
|
/*----- Helpers. -----*/
|
||
|
|
|
||
|
|
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
|
||
|
|
index 9c272b4ff8..b597ae614c 100644
|
||
|
|
--- a/src/remote/remote_driver.c
|
||
|
|
+++ b/src/remote/remote_driver.c
|
||
|
|
@@ -8253,6 +8253,34 @@ remoteDomainGetGuestInfo(virDomainPtr dom,
|
||
|
|
return rv;
|
||
|
|
}
|
||
|
|
|
||
|
|
+static char *
|
||
|
|
+remoteConnectGetTmmMemoryInfo(virConnectPtr conn,
|
||
|
|
+ bool detail)
|
||
|
|
+{
|
||
|
|
+ char *rv = NULL;
|
||
|
|
+ struct private_data *priv = conn->privateData;
|
||
|
|
+ remote_connect_get_tmm_memory_info_args args;
|
||
|
|
+ remote_connect_get_tmm_memory_info_ret ret;
|
||
|
|
+
|
||
|
|
+ remoteDriverLock(priv);
|
||
|
|
+
|
||
|
|
+ args.detail = detail;
|
||
|
|
+
|
||
|
|
+ memset(&ret, 0, sizeof(ret));
|
||
|
|
+
|
||
|
|
+ if (call(conn, priv, 0, REMOTE_PROC_CONNECT_GET_TMM_MEMORY_INFO,
|
||
|
|
+ (xdrproc_t)xdr_remote_connect_get_tmm_memory_info_args, (char *)&args,
|
||
|
|
+ (xdrproc_t)xdr_remote_connect_get_tmm_memory_info_ret, (char *)&ret) < 0) {
|
||
|
|
+ goto done;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ rv = ret.meminfo;
|
||
|
|
+
|
||
|
|
+ done:
|
||
|
|
+ remoteDriverUnlock(priv);
|
||
|
|
+ return rv;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
/* get_nonnull_domain and get_nonnull_network turn an on-wire
|
||
|
|
* (name, uuid) pair into virDomainPtr or virNetworkPtr object.
|
||
|
|
* These can return NULL if underlying memory allocations fail,
|
||
|
|
@@ -8686,6 +8714,7 @@ static virHypervisorDriver hypervisor_driver = {
|
||
|
|
.domainBackupGetXMLDesc = remoteDomainBackupGetXMLDesc, /* 6.0.0 */
|
||
|
|
.domainHotpatchManage = remoteDomainHotpatchManage, /* 6.2.0 */
|
||
|
|
.domainStartDirtyRateCalc = remoteDomainStartDirtyRateCalc, /* 6.2.0 */
|
||
|
|
+ .connectGetTmmMemoryInfo = remoteConnectGetTmmMemoryInfo /* 6.2.0 */
|
||
|
|
};
|
||
|
|
|
||
|
|
static virNetworkDriver network_driver = {
|
||
|
|
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
|
||
|
|
index d89cc1a087..f37bd332a1 100644
|
||
|
|
--- a/src/remote/remote_protocol.x
|
||
|
|
+++ b/src/remote/remote_protocol.x
|
||
|
|
@@ -3789,6 +3789,14 @@ struct remote_domain_start_dirty_rate_calc_args {
|
||
|
|
unsigned int flags;
|
||
|
|
};
|
||
|
|
|
||
|
|
+struct remote_connect_get_tmm_memory_info_args {
|
||
|
|
+ unsigned int detail;
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
+struct remote_connect_get_tmm_memory_info_ret {
|
||
|
|
+ remote_nonnull_string meminfo;
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
/*----- Protocol. -----*/
|
||
|
|
|
||
|
|
/* Define the program number, protocol version and procedure numbers here. */
|
||
|
|
@@ -6698,5 +6706,11 @@ enum remote_procedure {
|
||
|
|
* @generate: both
|
||
|
|
* @acl: domain:read
|
||
|
|
*/
|
||
|
|
- REMOTE_PROC_DOMAIN_HOTPATCH_MANAGE = 800
|
||
|
|
+ REMOTE_PROC_DOMAIN_HOTPATCH_MANAGE = 800,
|
||
|
|
+
|
||
|
|
+ /**
|
||
|
|
+ * @generate: none
|
||
|
|
+ * @acl: connect:read
|
||
|
|
+ */
|
||
|
|
+ REMOTE_PROC_CONNECT_GET_TMM_MEMORY_INFO = 900
|
||
|
|
};
|
||
|
|
--
|
||
|
|
2.27.0
|
||
|
|
|