[PATCH safe for 10.10.0] qemu: re-use existing ActualNetDef for more interface types during update-device
by Laine Stump
For the full history behind this patch, look at the following:
https://issues.redhat.com/browse/RHEL-7036
commit v10.7.0-101-ga37bd2a15b
commit v10.8.0-rc2-8-gbcd5ae4e73
Summary: original problem was unexpected failure of update-device when
the user hadn't changed anything other than online status of the guest
NIC (which should always be allowed).
The first commit "fixed" this by avoiding the allocation of a new
ActualNetDef (i.e. creating a new networkport) for *all* network
device updates (because that was inappropriately changing which
ethernet physdev should be used for a macvtap connection, which by
design can't be handled in an update-device).
But this commit caused a regression for update-device of bridge-based
network devices (because some the updates of certain attributes *do*
require the ActualNetDef be re-allocated), so...
The 2nd commit narrowed the list of network types that get the "don't
allocate new ActualNetDef" treatment (so that only interfaces
connected to a network that uses a pool of ethernet VFs *being used in
passthrough mode* qualify).
But then it was pointed out that this re-broke simple updates of
devices that used a direct/macvtap network in "bridge" mode (because
it's possible to list multiple physdevs to use for bridge mode, in
which case the network driver attempts to "load balance" (and so a new
allocation might have a different ethernet physdev which, again, can't
be supported in a device-update).
So this (single line of code) patch *widens* the list of network types
that don't allocate a new ActualNetDef to also include the other
direct (macvtap) modes, e.g. bridge, private, etc.
Signed-off-by: Laine Stump <laine(a)redhat.com>
---
There is a more comprehensive fix that also, e.g., makes updating the
bandwidth or vlan info of a direct interface work correctly, but that
is much more invasive (and also isn't done yet). This patch fixes the
case of updating a direct interface's online status (for example)
without breaking anything else.
src/qemu/qemu_hotplug.c | 38 +++++++++++++++++++++-----------------
1 file changed, 21 insertions(+), 17 deletions(-)
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 3c18af6b0c..ff8c1263c6 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -3935,25 +3935,29 @@ qemuDomainChangeNet(virQEMUDriver *driver,
if (newdev->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
if (olddev->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
oldType == VIR_DOMAIN_NET_TYPE_DIRECT &&
- virDomainNetGetActualDirectMode(olddev) == VIR_NETDEV_MACVLAN_MODE_PASSTHRU &&
STREQ(olddev->data.network.name, newdev->data.network.name)) {
/* old and new are type='network', and the network name
- * hasn't changed *and* this is a network where each
- * connection is allocated exclusive use of a VF
- * device. In this case we *don't* want to get a new port
- * ("actual device") from the network because attempting
- * to allocate a new device would also allocate a
- * new/different VF, causing the update to fail. And
- * anyway we can use olddev's actualNetDef (since it
- * hasn't changed).
- *
- * So instead we just duplicate *the pointer to* the
- * actualNetDef from olddev to newdev so that comparisons
- * of actualNetDef will show no change. If the update is
- * successful, we will clear the actualNetDef pointer from
- * olddev before destroying it (or if the update fails,
- * then we need to clear the pointer from newdev before
- * destroying it)
+ * hasn't changed *and* this is a "direct" network (a pool
+ * of 1 or more host ethernet devices where each guest
+ * interface is allocated one device that it connects to
+ * via macvtap. In this case we *don't* want to get a new
+ * port ("actual device") from the network because
+ * attempting to allocate a new device would also allocate
+ * a new/different ethernet, causing the update to fail
+ * (because the physical device of a macvtap-based
+ * interface can't be changed without completely
+ * unplugging and re-plugging the guest NIC).
+
+
+ * We can work around this issue by just re-using olddev's
+ * actualNetDef (since it hasn't changed) rather than
+ * allocating a new one. We just duplicate *the pointer
+ * to* the actualNetDef from olddev to newdev so that
+ * comparisons of actualNetDef will show no change. If the
+ * update is successful, we will clear the actualNetDef
+ * pointer from olddev before destroying it (or if the
+ * update fails, then we need to clear the pointer from
+ * newdev before destroying it)
*/
newdev->data.network.actual = olddev->data.network.actual;
memcpy(newdev->data.network.portid, olddev->data.network.portid,
--
2.47.0
4 months, 2 weeks
[PATCH] Change return type of functions that use VIR_EXPAND_N and never fail to void
by Alexander Kuznetsov
These functions return value is invariant since VIR_EXPAND_N check
removal in 7d2fd6e, so change its type and remove all dependent checks.
Found by Linux Verification Center (linuxtesting.org) with Svace.
Reported-by: Pavel Nekrasov <p.nekrasov(a)fobos-nt.ru>
Signed-off-by: Alexander Kuznetsov <kuznetsovam(a)altlinux.org>
---
src/access/viraccessdriverstack.c | 4 +---
src/access/viraccessdriverstack.h | 2 +-
src/access/viraccessmanager.c | 5 +----
src/admin/admin_remote.c | 3 +--
src/hyperv/hyperv_wmi.c | 13 ++++-------
src/locking/lock_daemon.c | 10 ++-------
src/locking/lock_driver_lockd.c | 3 +--
src/logging/log_daemon.c | 10 ++-------
src/logging/log_manager.c | 3 +--
src/lxc/lxc_monitor.c | 4 +---
src/remote/remote_daemon.c | 20 ++++-------------
src/remote/remote_driver.c | 17 +++++---------
src/rpc/gendispatch.pl | 5 +----
src/rpc/virnetclient.c | 6 ++---
src/rpc/virnetclient.h | 4 ++--
src/rpc/virnetserver.c | 3 +--
src/rpc/virnetserver.h | 2 +-
src/util/virsysinfo.c | 37 ++++++++++---------------------
18 files changed, 43 insertions(+), 108 deletions(-)
diff --git a/src/access/viraccessdriverstack.c b/src/access/viraccessdriverstack.c
index fb9ea71665..9d6a0d4d1b 100644
--- a/src/access/viraccessdriverstack.c
+++ b/src/access/viraccessdriverstack.c
@@ -32,7 +32,7 @@ struct _virAccessDriverStackPrivate {
};
-int virAccessDriverStackAppend(virAccessManager *manager,
+void virAccessDriverStackAppend(virAccessManager *manager,
virAccessManager *child)
{
virAccessDriverStackPrivate *priv = virAccessManagerGetPrivateData(manager);
@@ -40,8 +40,6 @@ int virAccessDriverStackAppend(virAccessManager *manager,
VIR_EXPAND_N(priv->managers, priv->managersLen, 1);
priv->managers[priv->managersLen-1] = child;
-
- return 0;
}
diff --git a/src/access/viraccessdriverstack.h b/src/access/viraccessdriverstack.h
index abcfc30ec3..f878ef1989 100644
--- a/src/access/viraccessdriverstack.h
+++ b/src/access/viraccessdriverstack.h
@@ -23,7 +23,7 @@
#include "access/viraccessdriver.h"
-int virAccessDriverStackAppend(virAccessManager *manager,
+void virAccessDriverStackAppend(virAccessManager *manager,
virAccessManager *child);
extern virAccessDriver accessDriverStack;
diff --git a/src/access/viraccessmanager.c b/src/access/viraccessmanager.c
index 481528c3b9..6d9fdee5f1 100644
--- a/src/access/viraccessmanager.c
+++ b/src/access/viraccessmanager.c
@@ -164,10 +164,7 @@ virAccessManager *virAccessManagerNewStack(const char **names)
if (!child)
goto error;
- if (virAccessDriverStackAppend(manager, child) < 0) {
- virObjectUnref(child);
- goto error;
- }
+ virAccessDriverStackAppend(manager, child);
}
return manager;
diff --git a/src/admin/admin_remote.c b/src/admin/admin_remote.c
index 3291a1e965..5c4913a76e 100644
--- a/src/admin/admin_remote.c
+++ b/src/admin/admin_remote.c
@@ -214,8 +214,7 @@ remoteAdminPrivNew(const char *sock_path)
NULL, 0, NULL)))
goto error;
- if (virNetClientAddProgram(priv->client, priv->program) < 0)
- goto error;
+ virNetClientAddProgram(priv->client, priv->program);
return priv;
error:
diff --git a/src/hyperv/hyperv_wmi.c b/src/hyperv/hyperv_wmi.c
index 8bc376e22f..0b82f1f131 100644
--- a/src/hyperv/hyperv_wmi.c
+++ b/src/hyperv/hyperv_wmi.c
@@ -184,14 +184,12 @@ hypervFreeInvokeParams(hypervInvokeParamsList *params)
}
-static inline int
+static inline void
hypervCheckParams(hypervInvokeParamsList *params)
{
if (params->nbParams + 1 > params->nbAvailParams) {
VIR_EXPAND_N(params->params, params->nbAvailParams, 5);
}
-
- return 0;
}
@@ -212,8 +210,7 @@ hypervAddSimpleParam(hypervInvokeParamsList *params, const char *name,
{
hypervParam *p = NULL;
- if (hypervCheckParams(params) < 0)
- return -1;
+ hypervCheckParams(params);
p = ¶ms->params[params->nbParams];
p->type = HYPERV_SIMPLE_PARAM;
@@ -245,8 +242,7 @@ hypervAddEprParam(hypervInvokeParamsList *params,
{
hypervParam *p = NULL;
- if (hypervCheckParams(params) < 0)
- return -1;
+ hypervCheckParams(params);
p = ¶ms->params[params->nbParams];
p->type = HYPERV_EPR_PARAM;
@@ -333,8 +329,7 @@ hypervAddEmbeddedParam(hypervInvokeParamsList *params,
{
hypervParam *p = NULL;
- if (hypervCheckParams(params) < 0)
- return -1;
+ hypervCheckParams(params);
p = ¶ms->params[params->nbParams];
p->type = HYPERV_EMBEDDED_PARAM;
diff --git a/src/locking/lock_daemon.c b/src/locking/lock_daemon.c
index ba52ce7d77..0b86300b43 100644
--- a/src/locking/lock_daemon.c
+++ b/src/locking/lock_daemon.c
@@ -1066,10 +1066,7 @@ int main(int argc, char **argv) {
goto cleanup;
}
- if (virNetServerAddProgram(lockSrv, lockProgram) < 0) {
- ret = VIR_DAEMON_ERR_INIT;
- goto cleanup;
- }
+ virNetServerAddProgram(lockSrv, lockProgram);
if (adminSrv != NULL) {
if (!(adminProgram = virNetServerProgramNew(ADMIN_PROGRAM,
@@ -1079,10 +1076,7 @@ int main(int argc, char **argv) {
ret = VIR_DAEMON_ERR_INIT;
goto cleanup;
}
- if (virNetServerAddProgram(adminSrv, adminProgram) < 0) {
- ret = VIR_DAEMON_ERR_INIT;
- goto cleanup;
- }
+ virNetServerAddProgram(adminSrv, adminProgram);
}
/* Disable error func, now logging is setup */
diff --git a/src/locking/lock_driver_lockd.c b/src/locking/lock_driver_lockd.c
index d75302dd0a..0b6c720477 100644
--- a/src/locking/lock_driver_lockd.c
+++ b/src/locking/lock_driver_lockd.c
@@ -213,8 +213,7 @@ static virNetClient *virLockManagerLockDaemonConnectionNew(bool privileged,
NULL)))
goto error;
- if (virNetClientAddProgram(client, *prog) < 0)
- goto error;
+ virNetClientAddProgram(client, *prog);
return client;
diff --git a/src/logging/log_daemon.c b/src/logging/log_daemon.c
index 5a9be4a44e..16a5dcea9a 100644
--- a/src/logging/log_daemon.c
+++ b/src/logging/log_daemon.c
@@ -864,10 +864,7 @@ int main(int argc, char **argv) {
ret = VIR_DAEMON_ERR_INIT;
goto cleanup;
}
- if (virNetServerAddProgram(logSrv, logProgram) < 0) {
- ret = VIR_DAEMON_ERR_INIT;
- goto cleanup;
- }
+ virNetServerAddProgram(logSrv, logProgram);
if (adminSrv != NULL) {
if (!(adminProgram = virNetServerProgramNew(ADMIN_PROGRAM,
@@ -877,10 +874,7 @@ int main(int argc, char **argv) {
ret = VIR_DAEMON_ERR_INIT;
goto cleanup;
}
- if (virNetServerAddProgram(adminSrv, adminProgram) < 0) {
- ret = VIR_DAEMON_ERR_INIT;
- goto cleanup;
- }
+ virNetServerAddProgram(adminSrv, adminProgram);
}
/* Disable error func, now logging is setup */
diff --git a/src/logging/log_manager.c b/src/logging/log_manager.c
index d8490f4e5a..19e23d65c5 100644
--- a/src/logging/log_manager.c
+++ b/src/logging/log_manager.c
@@ -88,8 +88,7 @@ virLogManagerConnect(bool privileged,
NULL)))
goto error;
- if (virNetClientAddProgram(client, *prog) < 0)
- goto error;
+ virNetClientAddProgram(client, *prog);
VIR_FREE(daemonPath);
VIR_FREE(logdpath);
diff --git a/src/lxc/lxc_monitor.c b/src/lxc/lxc_monitor.c
index 811d6685e5..cf2fd1897f 100644
--- a/src/lxc/lxc_monitor.c
+++ b/src/lxc/lxc_monitor.c
@@ -169,9 +169,7 @@ virLXCMonitor *virLXCMonitorNew(virDomainObj *vm,
mon)))
goto error;
- if (virNetClientAddProgram(mon->client,
- mon->program) < 0)
- goto error;
+ virNetClientAddProgram(mon->client, mon->program);
mon->vm = virObjectRef(vm);
memcpy(&mon->cb, cb, sizeof(mon->cb));
diff --git a/src/remote/remote_daemon.c b/src/remote/remote_daemon.c
index 9e82132654..1d079c7e4b 100644
--- a/src/remote/remote_daemon.c
+++ b/src/remote/remote_daemon.c
@@ -1063,10 +1063,7 @@ int main(int argc, char **argv) {
ret = VIR_DAEMON_ERR_INIT;
goto cleanup;
}
- if (virNetServerAddProgram(srv, remoteProgram) < 0) {
- ret = VIR_DAEMON_ERR_INIT;
- goto cleanup;
- }
+ virNetServerAddProgram(srv, remoteProgram);
if (!(lxcProgram = virNetServerProgramNew(LXC_PROGRAM,
LXC_PROTOCOL_VERSION,
@@ -1075,10 +1072,7 @@ int main(int argc, char **argv) {
ret = VIR_DAEMON_ERR_INIT;
goto cleanup;
}
- if (virNetServerAddProgram(srv, lxcProgram) < 0) {
- ret = VIR_DAEMON_ERR_INIT;
- goto cleanup;
- }
+ virNetServerAddProgram(srv, lxcProgram);
if (!(qemuProgram = virNetServerProgramNew(QEMU_PROGRAM,
QEMU_PROTOCOL_VERSION,
@@ -1087,10 +1081,7 @@ int main(int argc, char **argv) {
ret = VIR_DAEMON_ERR_INIT;
goto cleanup;
}
- if (virNetServerAddProgram(srv, qemuProgram) < 0) {
- ret = VIR_DAEMON_ERR_INIT;
- goto cleanup;
- }
+ virNetServerAddProgram(srv, qemuProgram);
if (!(srvAdm = virNetServerNew("admin", 1,
config->admin_min_workers,
@@ -1120,10 +1111,7 @@ int main(int argc, char **argv) {
ret = VIR_DAEMON_ERR_INIT;
goto cleanup;
}
- if (virNetServerAddProgram(srvAdm, adminProgram) < 0) {
- ret = VIR_DAEMON_ERR_INIT;
- goto cleanup;
- }
+ virNetServerAddProgram(srvAdm, adminProgram);
if (timeout > 0) {
if (virNetDaemonAutoShutdown(dmn, timeout) < 0)
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index e76d9e9ba4..307f9ca945 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -1160,10 +1160,9 @@ doRemoteOpen(virConnectPtr conn,
conn)))
goto error;
- if (virNetClientAddProgram(priv->client, priv->remoteProgram) < 0 ||
- virNetClientAddProgram(priv->client, priv->lxcProgram) < 0 ||
- virNetClientAddProgram(priv->client, priv->qemuProgram) < 0)
- goto error;
+ virNetClientAddProgram(priv->client, priv->remoteProgram);
+ virNetClientAddProgram(priv->client, priv->lxcProgram);
+ virNetClientAddProgram(priv->client, priv->qemuProgram);
/* Try and authenticate with server */
VIR_DEBUG("Trying authentication");
@@ -5664,10 +5663,7 @@ remoteDomainMigratePrepareTunnel3(virConnectPtr dconn,
false)))
return -1;
- if (virNetClientAddStream(priv->client, netst) < 0) {
- virObjectUnref(netst);
- return -1;
- }
+ virNetClientAddStream(priv->client, netst);
st->driver = &remoteStreamDrv;
st->privateData = netst;
@@ -6433,10 +6429,7 @@ remoteDomainMigratePrepareTunnel3Params(virConnectPtr dconn,
false)))
goto cleanup;
- if (virNetClientAddStream(priv->client, netst) < 0) {
- virObjectUnref(netst);
- goto cleanup;
- }
+ virNetClientAddStream(priv->client, netst);
st->driver = &remoteStreamDrv;
st->privateData = netst;
diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl
index c5842dc796..724a6aed6e 100755
--- a/src/rpc/gendispatch.pl
+++ b/src/rpc/gendispatch.pl
@@ -1822,10 +1822,7 @@ elsif ($mode eq "client") {
print " if (!(netst = virNetClientStreamNew(priv->remoteProgram, $call->{constname}, priv->counter, sparse)))\n";
print " goto cleanup;\n";
print "\n";
- print " if (virNetClientAddStream(priv->client, netst) < 0) {\n";
- print " virObjectUnref(netst);\n";
- print " goto cleanup;\n";
- print " }";
+ print " virNetClientAddStream(priv->client, netst);\n";
print "\n";
print " st->driver = &remoteStreamDrv;\n";
print " st->privateData = netst;\n";
diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c
index 6d424eb599..39ccbd739c 100644
--- a/src/rpc/virnetclient.c
+++ b/src/rpc/virnetclient.c
@@ -1053,7 +1053,7 @@ bool virNetClientIsOpen(virNetClient *client)
}
-int virNetClientAddProgram(virNetClient *client,
+void virNetClientAddProgram(virNetClient *client,
virNetClientProgram *prog)
{
virObjectLock(client);
@@ -1062,11 +1062,10 @@ int virNetClientAddProgram(virNetClient *client,
client->programs[client->nprograms-1] = virObjectRef(prog);
virObjectUnlock(client);
- return 0;
}
-int virNetClientAddStream(virNetClient *client,
+void virNetClientAddStream(virNetClient *client,
virNetClientStream *st)
{
virObjectLock(client);
@@ -1075,7 +1074,6 @@ int virNetClientAddStream(virNetClient *client,
client->streams[client->nstreams-1] = virObjectRef(st);
virObjectUnlock(client);
- return 0;
}
diff --git a/src/rpc/virnetclient.h b/src/rpc/virnetclient.h
index 1647a6cc71..29099791a0 100644
--- a/src/rpc/virnetclient.h
+++ b/src/rpc/virnetclient.h
@@ -117,10 +117,10 @@ int virNetClientDupFD(virNetClient *client, bool cloexec);
bool virNetClientHasPassFD(virNetClient *client);
-int virNetClientAddProgram(virNetClient *client,
+void virNetClientAddProgram(virNetClient *client,
virNetClientProgram *prog);
-int virNetClientAddStream(virNetClient *client,
+void virNetClientAddStream(virNetClient *client,
virNetClientStream *st);
void virNetClientRemoveStream(virNetClient *client,
diff --git a/src/rpc/virnetserver.c b/src/rpc/virnetserver.c
index a6c6443c55..91219c3eed 100644
--- a/src/rpc/virnetserver.c
+++ b/src/rpc/virnetserver.c
@@ -768,7 +768,7 @@ virNetServerAddServiceUNIX(virNetServer *srv,
}
-int
+void
virNetServerAddProgram(virNetServer *srv,
virNetServerProgram *prog)
{
@@ -776,7 +776,6 @@ virNetServerAddProgram(virNetServer *srv,
VIR_EXPAND_N(srv->programs, srv->nprograms, 1);
srv->programs[srv->nprograms-1] = virObjectRef(prog);
- return 0;
}
diff --git a/src/rpc/virnetserver.h b/src/rpc/virnetserver.h
index 7756a1dd6c..c14d8bd10f 100644
--- a/src/rpc/virnetserver.h
+++ b/src/rpc/virnetserver.h
@@ -84,7 +84,7 @@ int virNetServerAddServiceUNIX(virNetServer *srv,
size_t max_queued_clients,
size_t nrequests_client_max);
-int virNetServerAddProgram(virNetServer *srv,
+void virNetServerAddProgram(virNetServer *srv,
virNetServerProgram *prog);
int virNetServerSetTLSContext(virNetServer *srv,
diff --git a/src/util/virsysinfo.c b/src/util/virsysinfo.c
index dbcbca62ed..3575669ac3 100644
--- a/src/util/virsysinfo.c
+++ b/src/util/virsysinfo.c
@@ -263,7 +263,7 @@ virSysinfoParsePPCSystem(const char *base, virSysinfoSystemDef **sysdef)
return ret;
}
-static int
+static void
virSysinfoParsePPCProcessor(const char *base, virSysinfoDef *ret)
{
const char *cur;
@@ -303,8 +303,6 @@ virSysinfoParsePPCProcessor(const char *base, virSysinfoDef *ret)
}
}
-
- return 0;
}
/* virSysinfoRead for PowerPC
@@ -325,8 +323,7 @@ virSysinfoReadPPC(void)
ret->nprocessor = 0;
ret->processor = NULL;
- if (virSysinfoParsePPCProcessor(outbuf, ret) < 0)
- return NULL;
+ virSysinfoParsePPCProcessor(outbuf, ret);
if (virSysinfoParsePPCSystem(outbuf, &ret->system) < 0)
return NULL;
@@ -383,7 +380,7 @@ virSysinfoParseARMSystem(const char *base, virSysinfoSystemDef **sysdef)
return ret;
}
-static int
+static void
virSysinfoParseARMProcessor(const char *base, virSysinfoDef *ret)
{
const char *cur;
@@ -393,7 +390,7 @@ virSysinfoParseARMProcessor(const char *base, virSysinfoDef *ret)
if (!(tmp_base = strstr(base, "model name")) &&
!(tmp_base = strstr(base, "Processor")))
- return 0;
+ return;
eol = strchr(tmp_base, '\n');
cur = strchr(tmp_base, ':') + 1;
@@ -420,7 +417,7 @@ virSysinfoParseARMProcessor(const char *base, virSysinfoDef *ret)
}
VIR_FREE(processor_type);
- return 0;
+ return;
}
/* virSysinfoRead for ARMv7
@@ -451,8 +448,7 @@ virSysinfoReadARM(void)
ret->nprocessor = 0;
ret->processor = NULL;
- if (virSysinfoParseARMProcessor(outbuf, ret) < 0)
- return NULL;
+ virSysinfoParseARMProcessor(outbuf, ret);
if (virSysinfoParseARMSystem(outbuf, &ret->system) < 0)
return NULL;
@@ -753,7 +749,7 @@ virSysinfoParseX86System(const char *base, virSysinfoSystemDef **sysdef)
return ret;
}
-static int
+static void
virSysinfoParseX86BaseBoard(const char *base,
virSysinfoBaseBoardDef **baseBoard,
size_t *nbaseBoard)
@@ -827,7 +823,6 @@ virSysinfoParseX86BaseBoard(const char *base,
*nbaseBoard = nboards;
*baseBoard = g_steal_pointer(&boards);
- return 0;
}
@@ -1006,7 +1001,7 @@ virSysinfoParseOEMStrings(const char *base,
}
-static int
+static void
virSysinfoParseX86Processor(const char *base, virSysinfoDef *ret)
{
const char *cur, *tmp_base;
@@ -1102,11 +1097,9 @@ virSysinfoParseX86Processor(const char *base, virSysinfoDef *ret)
base += strlen("Processor Information");
}
-
- return 0;
}
-static int
+static void
virSysinfoParseX86Memory(const char *base, virSysinfoDef *ret)
{
const char *cur, *tmp_base;
@@ -1197,8 +1190,6 @@ virSysinfoParseX86Memory(const char *base, virSysinfoDef *ret)
next:
base += strlen("Memory Device");
}
-
- return 0;
}
virSysinfoDef *
@@ -1223,8 +1214,7 @@ virSysinfoReadDMI(void)
if (virSysinfoParseX86System(outbuf, &ret->system) < 0)
return NULL;
- if (virSysinfoParseX86BaseBoard(outbuf, &ret->baseBoard, &ret->nbaseBoard) < 0)
- return NULL;
+ virSysinfoParseX86BaseBoard(outbuf, &ret->baseBoard, &ret->nbaseBoard);
if (virSysinfoParseX86Chassis(outbuf, &ret->chassis) < 0)
return NULL;
@@ -1234,13 +1224,10 @@ virSysinfoReadDMI(void)
ret->nprocessor = 0;
ret->processor = NULL;
- if (virSysinfoParseX86Processor(outbuf, ret) < 0)
- return NULL;
-
+ virSysinfoParseX86Processor(outbuf, ret);
ret->nmemory = 0;
ret->memory = NULL;
- if (virSysinfoParseX86Memory(outbuf, ret) < 0)
- return NULL;
+ virSysinfoParseX86Memory(outbuf, ret);
return g_steal_pointer(&ret);
}
--
2.42.2
4 months, 2 weeks
Exception in thread "main" java.lang.UnsatisfiedLinkError: Unable to
load library 'virt': The specified module could not be found.
by sujith.a_S1@dell.com
trying to write a simple java program to connect to KVM, but getting the error
CODE
----------------------------------------------------------------------------------------------------
package com.poc.kvm_connection;
import org.libvirt.Connect;
import org.libvirt.ConnectAuth;
import org.libvirt.ConnectAuthDefault;
import org.libvirt.LibvirtException;
public class KvmConnectionApplication {
public static void main(String[] args) throws Exception {
KvmConnectionApplication application = new KvmConnectionApplication();
application.testConnection();
}
public void testConnection() throws LibvirtException {
ConnectAuth defaultAuth = new ConnectAuthDefault();
Connect conn = new Connect("qemu+tcp://10.230.211.237/system", defaultAuth, 0);
}
}
ERROR
--------------------------------------------------------------------------------------------------------------------
Exception in thread "main" java.lang.UnsatisfiedLinkError: Unable to load library 'virt': The specified module could not be found.
at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:169)
at com.sun.jna.NativeLibrary.getInstance(NativeLibrary.java:242)
at com.sun.jna.Library$Handler.<init>(Library.java:140)
at com.sun.jna.Native.loadLibrary(Native.java:368)
at com.sun.jna.Native.loadLibrary(Native.java:353)
at org.libvirt.jna.Libvirt.<clinit>(Unknown Source)
at org.libvirt.Connect.<clinit>(Unknown Source)
4 months, 2 weeks
[PATCH 0/8] Enabling logging for ch guests
by Praveen K Paladugu
LogContext management is now moved from Qemu driver to hypervisor. After migrating Qemu to use domain_logcontext, I extended ch driver to use also use logcontext to capture early boot failures in domain specific log file.
I broke up the migration of logcontext from qemu to hypevisor into multiple patches. Due to this breakup, patches 1,2,3 fail to build. Only after applying patch4 does this patchset successfully build.
Praveen K Paladugu (8):
domain: move logcontext mgmt from qemu to hypervisor
hypervisor: drop hypervisor specific args in domainLogContextNew
qemu: Fix domainLogContextNew invocations in qemu driver
libvirt_private: export symbols from domain_logcontext
po: Update POTFILES
ch: Enable logging for ch domains
ch: move curl_data and curl_callback definitions
ch: Enable logging curl responses from ch
po/POTFILES | 2 +-
src/ch/ch_conf.h | 2 +
src/ch/ch_monitor.c | 84 ++++++++++++-------
src/ch/ch_monitor.h | 6 +-
src/ch/ch_process.c | 36 ++++++--
.../domain_logcontext.c} | 78 +++++++++--------
src/hypervisor/domain_logcontext.h | 45 ++++++++++
src/hypervisor/meson.build | 1 +
src/libvirt_private.syms | 6 ++
src/qemu/meson.build | 1 -
src/qemu/qemu_domain.c | 28 +++----
src/qemu/qemu_domain.h | 12 +--
src/qemu/qemu_logcontext.h | 41 ---------
src/qemu/qemu_nbdkit.c | 12 ++-
src/qemu/qemu_process.c | 45 +++++-----
15 files changed, 235 insertions(+), 164 deletions(-)
rename src/{qemu/qemu_logcontext.c => hypervisor/domain_logcontext.c} (79%)
create mode 100644 src/hypervisor/domain_logcontext.h
delete mode 100644 src/qemu/qemu_logcontext.h
--
2.47.0
4 months, 2 weeks
[PATCH] qemu: Grab a QUERY job when formatting domain XML
by Michal Privoznik
It may happen that, for instance after daemon restart, that one
thread is still in qemuProcessReconnect(), i.e. filling in
runtime information by talking to QEMU on monitor. If another
thread then tries to format domain XML (which is currently
guarded by plain mutex on virDomainObj) it'll produce incomplete
and misleading information (e.g. current size of virtio-mem).
This happens because the reconnecting thread talks to QEMU on
monitor and thus unlocks the domain object frequently allowing
the XML formatting thread to acquire the mutex meanwhile.
Resolves: https://issues.redhat.com/browse/RHEL-71042
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
src/qemu/qemu_driver.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 09f7edda7d..f1a633fdd3 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -6163,6 +6163,9 @@ static char
if (virDomainGetXMLDescEnsureACL(dom->conn, vm->def, flags) < 0)
goto cleanup;
+ if (virDomainObjBeginJob(vm, VIR_JOB_QUERY) < 0)
+ goto cleanup;
+
qemuDomainUpdateCurrentMemorySize(vm);
if ((flags & VIR_DOMAIN_XML_MIGRATABLE))
@@ -6177,6 +6180,8 @@ static char
ret = qemuDomainFormatXML(driver, vm, flags);
+ virDomainObjEndJob(vm);
+
cleanup:
virDomainObjEndAPI(&vm);
return ret;
--
2.45.2
4 months, 2 weeks
[PATCH v2 00/25] cpu_map: Add missing -v1 models
by Jiri Denemark
CPU models that do not have a list of versions attached are still
advertised as aliases to corresponding -v1 variants. We should add the
missing variants to the CPU map.
Available on gitlab:
git fetch https://gitlab.com/jirkade/libvirt.git cpu-versions
Version 2:
- Add -v1 for all models including ancient ones
Jiri Denemark (25):
cpu_map: Sort data files in meson.build
sync_qemu_models_i386: Update meson.build
sync_qemu_models_i386: Generate missing -v1 variants
cpu_map: Add 486-v1 CPU model
cpu_map: Add pentium-v1 CPU model
cpu_map: Add pentium2-v1 CPU model
cpu_map: Add pentium3-v1 CPU model
cpu_map: Add coreduo-v1 CPU model
cpu_map: Add n270-v1 CPU model
cpu_map: Add core2duo-v1 CPU model
cpu_map: Add qemu32-v1 CPU model
cpu_map: Add kvm32-v1 CPU model
cpu_map: Add qemu64-v1 CPU model
cpu_map: Add kvm64-v1 CPU model
cpu_map: Add Conroe-v1 CPU model
cpu_map: Add Penryn-v1 CPU model
cpu_map: Add KnightsMill-v1 CPU model
cpu_map: Add athlon-v1 CPU model
cpu_map: Add phenom-v1 CPU model
cpu_map: Add Opteron_G1-v1 CPU model
cpu_map: Add Opteron_G2-v1 CPU model
cpu_map: Add Opteron_G3-v1 CPU model
cpu_map: Add Opteron_G4-v1 CPU model
cpu_map: Add Opteron_G5-v1 CPU model
cpu_map: Add EPYC-Genoa-v1 CPU model
src/cpu_map/index.xml | 22 +++
src/cpu_map/meson.build | 38 +++--
src/cpu_map/sync_qemu_models_i386.py | 30 ++++
src/cpu_map/x86_486-v1.xml | 6 +
src/cpu_map/x86_Conroe-v1.xml | 6 +
src/cpu_map/x86_EPYC-Genoa-v1.xml | 6 +
src/cpu_map/x86_KnightsMill-v1.xml | 6 +
src/cpu_map/x86_Opteron_G1-v1.xml | 6 +
src/cpu_map/x86_Opteron_G2-v1.xml | 6 +
src/cpu_map/x86_Opteron_G3-v1.xml | 6 +
src/cpu_map/x86_Opteron_G4-v1.xml | 6 +
src/cpu_map/x86_Opteron_G5-v1.xml | 6 +
src/cpu_map/x86_Penryn-v1.xml | 6 +
src/cpu_map/x86_athlon-v1.xml | 6 +
src/cpu_map/x86_core2duo-v1.xml | 6 +
src/cpu_map/x86_coreduo-v1.xml | 6 +
src/cpu_map/x86_kvm32-v1.xml | 6 +
src/cpu_map/x86_kvm64-v1.xml | 6 +
src/cpu_map/x86_n270-v1.xml | 6 +
src/cpu_map/x86_pentium-v1.xml | 6 +
src/cpu_map/x86_pentium2-v1.xml | 6 +
src/cpu_map/x86_pentium3-v1.xml | 6 +
src/cpu_map/x86_phenom-v1.xml | 6 +
src/cpu_map/x86_qemu32-v1.xml | 6 +
src/cpu_map/x86_qemu64-v1.xml | 6 +
.../x86_64-cpuid-A10-5800K-host.xml | 2 +-
.../x86_64-cpuid-Atom-D510-host.xml | 2 +-
.../x86_64-cpuid-Atom-N450-host.xml | 2 +-
.../x86_64-cpuid-Core2-E6850-host.xml | 2 +-
.../x86_64-cpuid-Core2-Q9500-host.xml | 2 +-
.../cputestdata/x86_64-cpuid-FX-8150-host.xml | 2 +-
.../x86_64-cpuid-Opteron-1352-host.xml | 2 +-
.../x86_64-cpuid-Opteron-2350-host.xml | 2 +-
.../x86_64-cpuid-Opteron-6234-host.xml | 2 +-
.../x86_64-cpuid-Opteron-6282-host.xml | 2 +-
.../x86_64-cpuid-Pentium-P6100-host.xml | 2 +-
.../x86_64-cpuid-Phenom-B95-host.xml | 2 +-
.../x86_64-cpuid-Xeon-5110-host.xml | 2 +-
.../x86_64-cpuid-Xeon-X5460-host.xml | 2 +-
.../domaincapsdata/qemu_5.2.0-q35.x86_64.xml | 100 ++++++++++---
.../domaincapsdata/qemu_5.2.0-tcg.x86_64.xml | 105 +++++++++++---
tests/domaincapsdata/qemu_5.2.0.x86_64.xml | 100 ++++++++++---
.../domaincapsdata/qemu_6.0.0-q35.x86_64.xml | 100 ++++++++++---
.../domaincapsdata/qemu_6.0.0-tcg.x86_64.xml | 105 +++++++++++---
tests/domaincapsdata/qemu_6.0.0.x86_64.xml | 100 ++++++++++---
.../domaincapsdata/qemu_6.1.0-q35.x86_64.xml | 100 ++++++++++---
.../domaincapsdata/qemu_6.1.0-tcg.x86_64.xml | 105 +++++++++++---
tests/domaincapsdata/qemu_6.1.0.x86_64.xml | 100 ++++++++++---
.../domaincapsdata/qemu_6.2.0-q35.x86_64.xml | 100 ++++++++++---
.../domaincapsdata/qemu_6.2.0-tcg.x86_64.xml | 105 +++++++++++---
tests/domaincapsdata/qemu_6.2.0.x86_64.xml | 100 ++++++++++---
.../domaincapsdata/qemu_7.0.0-q35.x86_64.xml | 100 ++++++++++---
.../domaincapsdata/qemu_7.0.0-tcg.x86_64.xml | 105 +++++++++++---
tests/domaincapsdata/qemu_7.0.0.x86_64.xml | 100 ++++++++++---
.../domaincapsdata/qemu_7.1.0-q35.x86_64.xml | 100 ++++++++++---
.../domaincapsdata/qemu_7.1.0-tcg.x86_64.xml | 105 +++++++++++---
tests/domaincapsdata/qemu_7.1.0.x86_64.xml | 100 ++++++++++---
.../domaincapsdata/qemu_7.2.0-q35.x86_64.xml | 100 ++++++++++---
.../qemu_7.2.0-tcg.x86_64+hvf.xml | 97 ++++++++++---
.../domaincapsdata/qemu_7.2.0-tcg.x86_64.xml | 97 ++++++++++---
tests/domaincapsdata/qemu_7.2.0.x86_64.xml | 100 ++++++++++---
.../domaincapsdata/qemu_8.0.0-q35.x86_64.xml | 100 ++++++++++---
.../domaincapsdata/qemu_8.0.0-tcg.x86_64.xml | 97 ++++++++++---
tests/domaincapsdata/qemu_8.0.0.x86_64.xml | 100 ++++++++++---
.../domaincapsdata/qemu_8.1.0-q35.x86_64.xml | 132 ++++++++++++++---
.../domaincapsdata/qemu_8.1.0-tcg.x86_64.xml | 135 +++++++++++++++---
tests/domaincapsdata/qemu_8.1.0.x86_64.xml | 132 ++++++++++++++---
.../domaincapsdata/qemu_8.2.0-q35.x86_64.xml | 132 ++++++++++++++---
.../domaincapsdata/qemu_8.2.0-tcg.x86_64.xml | 134 ++++++++++++++---
tests/domaincapsdata/qemu_8.2.0.x86_64.xml | 132 ++++++++++++++---
.../domaincapsdata/qemu_9.0.0-q35.x86_64.xml | 132 ++++++++++++++---
.../domaincapsdata/qemu_9.0.0-tcg.x86_64.xml | 133 ++++++++++++++---
tests/domaincapsdata/qemu_9.0.0.x86_64.xml | 132 ++++++++++++++---
.../domaincapsdata/qemu_9.1.0-q35.x86_64.xml | 132 ++++++++++++++---
.../domaincapsdata/qemu_9.1.0-tcg.x86_64.xml | 133 ++++++++++++++---
tests/domaincapsdata/qemu_9.1.0.x86_64.xml | 132 ++++++++++++++---
.../domaincapsdata/qemu_9.2.0-q35.x86_64.xml | 132 ++++++++++++++---
.../domaincapsdata/qemu_9.2.0-tcg.x86_64.xml | 133 ++++++++++++++---
tests/domaincapsdata/qemu_9.2.0.x86_64.xml | 132 ++++++++++++++---
79 files changed, 3882 insertions(+), 877 deletions(-)
create mode 100644 src/cpu_map/x86_486-v1.xml
create mode 100644 src/cpu_map/x86_Conroe-v1.xml
create mode 100644 src/cpu_map/x86_EPYC-Genoa-v1.xml
create mode 100644 src/cpu_map/x86_KnightsMill-v1.xml
create mode 100644 src/cpu_map/x86_Opteron_G1-v1.xml
create mode 100644 src/cpu_map/x86_Opteron_G2-v1.xml
create mode 100644 src/cpu_map/x86_Opteron_G3-v1.xml
create mode 100644 src/cpu_map/x86_Opteron_G4-v1.xml
create mode 100644 src/cpu_map/x86_Opteron_G5-v1.xml
create mode 100644 src/cpu_map/x86_Penryn-v1.xml
create mode 100644 src/cpu_map/x86_athlon-v1.xml
create mode 100644 src/cpu_map/x86_core2duo-v1.xml
create mode 100644 src/cpu_map/x86_coreduo-v1.xml
create mode 100644 src/cpu_map/x86_kvm32-v1.xml
create mode 100644 src/cpu_map/x86_kvm64-v1.xml
create mode 100644 src/cpu_map/x86_n270-v1.xml
create mode 100644 src/cpu_map/x86_pentium-v1.xml
create mode 100644 src/cpu_map/x86_pentium2-v1.xml
create mode 100644 src/cpu_map/x86_pentium3-v1.xml
create mode 100644 src/cpu_map/x86_phenom-v1.xml
create mode 100644 src/cpu_map/x86_qemu32-v1.xml
create mode 100644 src/cpu_map/x86_qemu64-v1.xml
--
2.47.0
4 months, 2 weeks
[PATCH] virsh: Fix --timeout option of migrate command
by Jiri Denemark
When starting a migration with --timeout, we create a thread to call the
migration API and in parallel setup a timer for the timeout. The
description of --timeout says: "run action specified by --timeout-*
option (suspend by default) if live migration exceeds timeout", which is
not really the way this feature was implemented. Before live migration
starts we first need to contact the source to get the domain definition
and send it to the destination where a new QEMU process has to be
started. This can take some (unpredictably long) time while the timeout
timer is already running. If a very short timeout is set (which doesn't
really make sense, but it's allowed), we may even end up taking the
timeout action before the actual migration had a chance to start.
With this patch the timeout is started only after we get non-zero
dataTotal from virDomainGetJobInfo, which means the migration (of either
storage or memory) really started.
https://issues.redhat.com/browse/RHEL-41264
Signed-off-by: Jiri Denemark <jdenemar(a)redhat.com>
---
tools/virsh-domain.c | 55 ++++++++++++++++++++++++++++----------------
1 file changed, 35 insertions(+), 20 deletions(-)
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index e4923284af..546db955a9 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -4237,7 +4237,10 @@ typedef void (*jobWatchTimeoutFunc)(vshControl *ctl, virDomainPtr dom,
struct virshWatchData {
vshControl *ctl;
virDomainPtr dom;
+ GMainContext *context;
jobWatchTimeoutFunc timeout_func;
+ int timeout_secs;
+ GSource *timeout_src;
void *opaque;
const char *label;
GIOChannel *stdin_ioc;
@@ -4259,6 +4262,20 @@ virshWatchTimeout(gpointer opaque)
}
+static void
+virshWatchSetTimeout(struct virshWatchData *data)
+{
+ vshDebug(data->ctl, VSH_ERR_DEBUG,
+ "watchJob: setting timeout of %d secs\n", data->timeout_secs);
+
+ data->timeout_src = g_timeout_source_new_seconds(data->timeout_secs);
+ g_source_set_callback(data->timeout_src,
+ virshWatchTimeout,
+ data, NULL);
+ g_source_attach(data->timeout_src, data->context);
+}
+
+
static gboolean
virshWatchProgress(gpointer opaque)
{
@@ -4290,10 +4307,17 @@ virshWatchProgress(gpointer opaque)
jobinfo.type == VIR_DOMAIN_JOB_UNBOUNDED)) {
vshTTYDisableInterrupt(data->ctl);
data->jobStarted = true;
+ vshDebug(data->ctl, VSH_ERR_DEBUG,
+ "watchJob: job started\n");
+ }
- if (!data->verbose) {
+ if (data->jobStarted) {
+ if (data->timeout_secs > 0 && !data->timeout_src) {
+ if (jobinfo.dataTotal > 0)
+ virshWatchSetTimeout(data);
+ } else if (!data->verbose) {
vshDebug(data->ctl, VSH_ERR_DEBUG,
- "watchJob: job started, disabling callback\n");
+ "watchJob: disabling callback\n");
return G_SOURCE_REMOVE;
}
}
@@ -4356,13 +4380,15 @@ virshWatchJob(vshControl *ctl,
struct sigaction sig_action;
struct sigaction old_sig_action;
#endif /* !WIN32 */
- g_autoptr(GSource) timeout_src = NULL;
g_autoptr(GSource) progress_src = NULL;
g_autoptr(GSource) stdin_src = NULL;
struct virshWatchData data = {
.ctl = ctl,
.dom = dom,
+ .context = g_main_loop_get_context(eventLoop),
.timeout_func = timeout_func,
+ .timeout_secs = timeout_secs,
+ .timeout_src = NULL,
.opaque = opaque,
.label = label,
.stdin_ioc = NULL,
@@ -4391,27 +4417,14 @@ virshWatchJob(vshControl *ctl,
g_source_set_callback(stdin_src,
(GSourceFunc)virshWatchInterrupt,
&data, NULL);
- g_source_attach(stdin_src,
- g_main_loop_get_context(eventLoop));
- }
-
- if (timeout_secs) {
- vshDebug(ctl, VSH_ERR_DEBUG,
- "watchJob: setting timeout of %d secs\n", timeout_secs);
- timeout_src = g_timeout_source_new_seconds(timeout_secs);
- g_source_set_callback(timeout_src,
- virshWatchTimeout,
- &data, NULL);
- g_source_attach(timeout_src,
- g_main_loop_get_context(eventLoop));
+ g_source_attach(stdin_src, data.context);
}
progress_src = g_timeout_source_new(500);
g_source_set_callback(progress_src,
virshWatchProgress,
&data, NULL);
- g_source_attach(progress_src,
- g_main_loop_get_context(eventLoop));
+ g_source_attach(progress_src, data.context);
g_main_loop_run(eventLoop);
@@ -4420,8 +4433,10 @@ virshWatchJob(vshControl *ctl,
if (*job_err == 0 && verbose) /* print [100 %] */
virshPrintJobProgress(label, 0, 1);
- if (timeout_src)
- g_source_destroy(timeout_src);
+ if (data.timeout_src) {
+ g_source_destroy(data.timeout_src);
+ g_source_unref(data.timeout_src);
+ }
g_source_destroy(progress_src);
if (stdin_src)
g_source_destroy(stdin_src);
--
2.47.0
4 months, 2 weeks
[PATCH] ch: Enable user aliases
by Praveen K Paladugu
Enable parsing user aliases in ch driver.
Signed-off-by: Praveen K Paladugu <praveenkpaladugu(a)gmail.com>
---
src/ch/ch_domain.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/ch/ch_domain.c b/src/ch/ch_domain.c
index bfccabed49..4f5966adce 100644
--- a/src/ch/ch_domain.c
+++ b/src/ch/ch_domain.c
@@ -284,7 +284,8 @@ virDomainDefParserConfig virCHDriverDomainDefParserConfig = {
.domainPostParseBasicCallback = virCHDomainDefPostParseBasic,
.domainPostParseCallback = virCHDomainDefPostParse,
.deviceValidateCallback = chValidateDomainDeviceDef,
- .features = VIR_DOMAIN_DEF_FEATURE_NO_STUB_CONSOLE,
+ .features = VIR_DOMAIN_DEF_FEATURE_NO_STUB_CONSOLE |
+ VIR_DOMAIN_DEF_FEATURE_USER_ALIAS,
};
virCHMonitor *
--
2.47.0
4 months, 2 weeks
[PATCH v4 0/5] ch: handle events from cloud-hypervisor
by Purna Pavan Chandra Aekkaladevi
changes from v3->v4:
* Don't abort; instead kill the VM and exit
* use g_clear_pointer along with g_free
* Fix possible memory leak
* Rebase on latest master
changes from v2->v3:
* Remove patch 'utils: Implement virFileIsNamedPipe' as it is no more needed.
* Remove the eventmonitorpath only if it exists
* Added domain name as a prefix to logs from ch_events.c. This will make
debugging easier.
* Simplified event parsing logic by reserving a byte for null char.
changes from v1->v2:
* Rebase on latest master
* Use /* */ for comments
* Remove fifo file if already exists
* Address other comments from Praveen Paladugu
cloud-hypervisor raises various events, including VM lifecylce operations
such as boot, shutdown, pause, resume, etc. Libvirt will now read these
events and take the necessary actions, such as correctly updating the
domain state. A FIFO file is passed to `--event-monitor` option of
cloud-hypervisor. Libvirt creates a new thread that acts as the reader
of the fifo file and continuously monitors for new events. Currently,
shutdown events are handled by updating the domain state appropriately.
Purna Pavan Chandra Aekkaladevi (5):
ch: pass --event-monitor option to cloud-hypervisor
ch: start a new thread for handling ch events
ch: events: Read and parse cloud-hypervisor events
ch: events: facilitate lifecycle events handling
NEWS: Mention event handling support in ch driver
NEWS.rst | 7 +
po/POTFILES | 1 +
src/ch/ch_events.c | 331 ++++++++++++++++++++++++++++++++++++++++++++
src/ch/ch_events.h | 54 ++++++++
src/ch/ch_monitor.c | 52 ++++++-
src/ch/ch_monitor.h | 11 ++
src/ch/meson.build | 2 +
7 files changed, 451 insertions(+), 7 deletions(-)
create mode 100644 src/ch/ch_events.c
create mode 100644 src/ch/ch_events.h
--
2.34.1
4 months, 2 weeks