[libvirt] [PATCH] Make virDomainGetXMLDesc output cache settings even if no special driverName is set
by Soren Hansen
If a special cache strategy for a disk has been specified in a domain
definition, but no driverName has been set, virDomainGetXMLDesc will not
include the <driver> tag at all.
This patch makes sure that the <driver> tag is included if any of the
settings it can contain has been set.
Signed-off-by: Soren Hansen <soren(a)linux2go.dk>
---
src/conf/domain_conf.c | 6 ++++--
1 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 96ba0b0..56c5239 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -4718,8 +4718,10 @@ virDomainDiskDefFormat(virBufferPtr buf,
" <disk type='%s' device='%s'>\n",
type, device);
- if (def->driverName) {
- virBufferVSprintf(buf, " <driver name='%s'", def->driverName);
+ if (def->driverName || def->driverType || def->cachemode) {
+ virBufferVSprintf(buf, " <driver");
+ if (def->driverName)
+ virBufferVSprintf(buf, " name='%s'", def->driverName);
if (def->driverType)
virBufferVSprintf(buf, " type='%s'", def->driverType);
if (def->cachemode)
--
1.7.0
14 years, 9 months
[libvirt] Domains callbacks under mingwin
by Dev.Atom
Hi there,
I trying to enable domain events callbacks under a cross compiled (mingwin under fedora12 env) libvirt 0.7.4 (I haven't been able to compile more recent versions under mingwin) dll. Here a little sample of code I'm trying to write :
#include "stdafx.h"
#include "windows.h"
#include "libvirt.h"
#include "virterror.h"
static int domain_event(virConnectPtr conn,
virDomainPtr dom,
int evt,
int detail,
void *opaque)
{
bool test = true;
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
virConnectPtr conn = virConnectOpen("qemu+tcp://192.168.220.198/session");
// Set Callback
int cbresult = virConnectDomainEventRegister(conn, domain_event, NULL, NULL);
// Lookup Domain
virDomainPtr dom = virDomainLookupByName(conn, "Test1");
// Start Domain
int startDom = virDomainCreate(dom);
if (startDom != 0)
{
virErrorPtr e = virGetLastError();
bool test = true;
}
// Wait
Sleep(60000);
// Stop Domain
int StopDom = virDomainDestroy(dom);
if (StopDom != 0)
{
virErrorPtr e = virGetLastError();
bool test = true;
}
return 0;
}
I'm able to connect to the host and I'm able to start the domain, but when I enable callback with "virConnectDomainEventRegister", it fails, I have a message "unmarshalling msg" coming from the "remoteDomainReadEvent" method of remote_driver.c in libvirt.
I think about a problem near __stdcall or __cdecl calls or this kind of thing, but I'm not sure.
Any clues ?
Best regards,
Arnaud Champion
14 years, 9 months
[libvirt] [RFC][PATCH v2 1/2] Separate backend setup from NIC device add/remove
by Ed Swierk
This patch moves backend setup code from qemudDomainAttachNetDevice and
qemudDomainDetachNetDevice into separate functions. While the intent is
to allow the new functions to be called separately without affecting VM
NIC devices, this is arguably a worthwhile refactoring on its own.
Signed-off-by: Ed Swierk <eswierk(a)aristanetworks.com>
---
Move the code that creates and destroys the network backend and
connects it to qemu from the code that creates the virtual NIC.
Index: libvirt-0.7.7/src/qemu/qemu_driver.c
===================================================================
--- libvirt-0.7.7.orig/src/qemu/qemu_driver.c
+++ libvirt-0.7.7/src/qemu/qemu_driver.c
@@ -141,6 +141,16 @@ static int qemuDetectVcpuPIDs(struct qem
static int qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
virDomainDefPtr def);
+static int qemudDomainConnectNetBackend(virConnectPtr conn,
+ struct qemud_driver *driver,
+ virDomainObjPtr vm,
+ virDomainNetDefPtr net,
+ unsigned long long qemuCmdFlags);
+
+static int qemudDomainDisconnectNetBackend(struct qemud_driver *driver,
+ virDomainObjPtr vm,
+ virDomainNetDefPtr net);
+
static struct qemud_driver *qemu_driver = NULL;
@@ -6231,20 +6241,17 @@ error:
}
-/* XXX conn required for network -> bridge resolution */
-static int qemudDomainAttachNetDevice(virConnectPtr conn,
- struct qemud_driver *driver,
- virDomainObjPtr vm,
- virDomainNetDefPtr net,
- unsigned long long qemuCmdFlags)
+static int qemudDomainConnectNetBackend(virConnectPtr conn,
+ struct qemud_driver *driver,
+ virDomainObjPtr vm,
+ virDomainNetDefPtr net,
+ unsigned long long qemuCmdFlags)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
char *tapfd_name = NULL;
int tapfd = -1;
- char *nicstr = NULL;
char *netstr = NULL;
int ret = -1;
- virDomainDevicePCIAddress guestAddr;
int vlan;
if (!(qemuCmdFlags & QEMUD_CMD_FLAG_HOST_NET_ADD)) {
@@ -6253,36 +6260,84 @@ static int qemudDomainAttachNetDevice(vi
return -1;
}
+ if (priv->monConfig->type != VIR_DOMAIN_CHR_TYPE_UNIX) {
+ qemuReportError(VIR_ERR_NO_SUPPORT,
+ _("network device type '%s' cannot be attached: "
+ "qemu is not using a unix socket monitor"),
+ virDomainNetTypeToString(net->type));
+ return -1;
+ }
+
+ if ((vlan = qemuDomainNetVLAN(net)) < 0) {
+ qemuReportError(VIR_ERR_NO_SUPPORT, "%s",
+ _("Unable to connect network backend without vlan"));
+ goto out;
+ }
+
if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE ||
net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
- if (priv->monConfig->type != VIR_DOMAIN_CHR_TYPE_UNIX) {
- qemuReportError(VIR_ERR_NO_SUPPORT,
- _("network device type '%s' cannot be attached: "
- "qemu is not using a unix socket monitor"),
- virDomainNetTypeToString(net->type));
- return -1;
- }
-
- if ((tapfd = qemudNetworkIfaceConnect(conn, driver, net, qemuCmdFlags)) < 0)
- return -1;
+ tapfd = qemudNetworkIfaceConnect(conn, driver, net, qemuCmdFlags);
} else if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
- if (priv->monConfig->type != VIR_DOMAIN_CHR_TYPE_UNIX) {
- qemuReportError(VIR_ERR_NO_SUPPORT,
- _("network device type '%s' cannot be attached: "
- "qemu is not using a unix socket monitor"),
- virDomainNetTypeToString(net->type));
- return -1;
- }
+ tapfd = qemudPhysIfaceConnect(conn, driver, net,
+ net->data.direct.linkdev,
+ net->data.direct.mode,
+ qemuCmdFlags);
+ }
+ if (tapfd < 0)
+ return -1;
- if ((tapfd = qemudPhysIfaceConnect(conn, driver, net,
- net->data.direct.linkdev,
- net->data.direct.mode,
- qemuCmdFlags)) < 0)
- return -1;
+ if (virAsprintf(&tapfd_name, "fd-%s", net->info.alias) < 0) {
+ virReportOOMError();
+ close(tapfd);
+ return -1;
+ }
+
+ if (!(netstr = qemuBuildHostNetStr(net, ' ',
+ vlan, tapfd_name))) {
+ VIR_FREE(tapfd_name);
+ close(tapfd);
+ return -1;
+ }
+
+ qemuDomainObjEnterMonitorWithDriver(driver, vm);
+
+ if (qemuMonitorSendFileHandle(priv->mon, tapfd_name, tapfd) < 0)
+ goto out;
+
+ if (qemuMonitorAddHostNetwork(priv->mon, netstr) < 0) {
+ if (qemuMonitorCloseFileHandle(priv->mon, tapfd_name) < 0)
+ VIR_WARN(_("Failed to close tapfd with '%s'"), tapfd_name);
+ goto out;
}
- if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets+1) < 0)
- goto no_memory;
+ ret = 0;
+
+out:
+ qemuDomainObjExitMonitorWithDriver(driver, vm);
+ VIR_FREE(netstr);
+ VIR_FREE(tapfd_name);
+ close(tapfd);
+ return ret;
+}
+
+
+/* XXX conn required for network -> bridge resolution */
+static int qemudDomainAttachNetDevice(virConnectPtr conn,
+ struct qemud_driver *driver,
+ virDomainObjPtr vm,
+ virDomainNetDefPtr net,
+ unsigned long long qemuCmdFlags)
+{
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ char *nicstr = NULL;
+ int ret = -1;
+ virDomainDevicePCIAddress guestAddr;
+ int vlan;
+
+ if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets+1) < 0) {
+ virReportOOMError();
+ return -1;
+ }
if ((qemuCmdFlags & QEMUD_CMD_FLAG_NET_NAME) ||
(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
@@ -6294,40 +6349,16 @@ static int qemudDomainAttachNetDevice(vi
qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &net->info) < 0)
goto cleanup;
- vlan = qemuDomainNetVLAN(net);
-
- if (vlan < 0) {
+ if ((vlan = qemuDomainNetVLAN(net)) < 0) {
qemuReportError(VIR_ERR_NO_SUPPORT, "%s",
_("Unable to attach network devices without vlan"));
goto cleanup;
}
- if (tapfd != -1) {
- if (virAsprintf(&tapfd_name, "fd-%s", net->info.alias) < 0)
- goto no_memory;
-
- qemuDomainObjEnterMonitorWithDriver(driver, vm);
- if (qemuMonitorSendFileHandle(priv->mon, tapfd_name, tapfd) < 0) {
- qemuDomainObjExitMonitorWithDriver(driver, vm);
- goto cleanup;
- }
- qemuDomainObjExitMonitorWithDriver(driver, vm);
- }
-
- if (!(netstr = qemuBuildHostNetStr(net, ' ',
- vlan, tapfd_name)))
- goto try_tapfd_close;
-
- qemuDomainObjEnterMonitorWithDriver(driver, vm);
- if (qemuMonitorAddHostNetwork(priv->mon, netstr) < 0) {
- qemuDomainObjExitMonitorWithDriver(driver, vm);
- goto try_tapfd_close;
+ if (qemudDomainConnectNetBackend(conn, driver, vm, net, qemuCmdFlags) < 0) {
+ VIR_WARN0(_("Failed to connect network backend"));
+ goto cleanup;
}
- qemuDomainObjExitMonitorWithDriver(driver, vm);
-
- if (tapfd != -1)
- close(tapfd);
- tapfd = -1;
if (!(nicstr = qemuBuildNicStr(net, NULL, vlan)))
goto try_remove;
@@ -6342,9 +6373,13 @@ static int qemudDomainAttachNetDevice(vi
memcpy(&net->info.addr.pci, &guestAddr, sizeof(guestAddr));
qemuDomainObjExitMonitorWithDriver(driver, vm);
+ vm->def->nets[vm->def->nnets++] = net;
ret = 0;
+ goto cleanup;
- vm->def->nets[vm->def->nnets++] = net;
+try_remove:
+ if (qemudDomainDisconnectNetBackend(driver, vm, net) < 0)
+ VIR_WARN0("Unable to disconnect network backend");
cleanup:
if ((ret != 0) &&
@@ -6352,44 +6387,8 @@ cleanup:
(net->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) &&
qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &net->info) < 0)
VIR_WARN0("Unable to release PCI address on NIC");
-
VIR_FREE(nicstr);
- VIR_FREE(netstr);
- VIR_FREE(tapfd_name);
- if (tapfd != -1)
- close(tapfd);
-
return ret;
-
-try_remove:
- if (vlan < 0) {
- VIR_WARN0(_("Unable to remove network backend"));
- } else {
- char *hostnet_name;
- if (virAsprintf(&hostnet_name, "host%s", net->info.alias) < 0)
- goto no_memory;
- qemuDomainObjEnterMonitorWithDriver(driver, vm);
- if (qemuMonitorRemoveHostNetwork(priv->mon, vlan, hostnet_name) < 0)
- VIR_WARN(_("Failed to remove network backend for vlan %d, net %s"),
- vlan, hostnet_name);
- qemuDomainObjExitMonitorWithDriver(driver, vm);
- VIR_FREE(hostnet_name);
- }
- goto cleanup;
-
-try_tapfd_close:
- if (tapfd_name) {
- qemuDomainObjEnterMonitorWithDriver(driver, vm);
- if (qemuMonitorCloseFileHandle(priv->mon, tapfd_name) < 0)
- VIR_WARN(_("Failed to close tapfd with '%s'"), tapfd_name);
- qemuDomainObjExitMonitorWithDriver(driver, vm);
- }
-
- goto cleanup;
-
-no_memory:
- virReportOOMError();
- goto cleanup;
}
@@ -6887,18 +6886,50 @@ cleanup:
return ret;
}
-static int
-qemudDomainDetachNetDevice(struct qemud_driver *driver,
- virDomainObjPtr vm,
- virDomainDeviceDefPtr dev,
- unsigned long long qemuCmdFlags)
+static int qemudDomainDisconnectNetBackend(struct qemud_driver *driver,
+ virDomainObjPtr vm,
+ virDomainNetDefPtr detach)
{
- int i, ret = -1;
- virDomainNetDefPtr detach = NULL;
qemuDomainObjPrivatePtr priv = vm->privateData;
int vlan;
char *hostnet_name = NULL;
+ if ((vlan = qemuDomainNetVLAN(detach)) < 0) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED,
+ "%s", _("unable to determine original VLAN"));
+ return -1;
+ }
+
+ if (virAsprintf(&hostnet_name, "host%s", detach->info.alias) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+
+ qemuDomainObjEnterMonitorWithDriver(driver, vm);
+ if (qemuMonitorRemoveHostNetwork(priv->mon, vlan, hostnet_name) < 0)
+ VIR_WARN0("Failed to remove host network");
+ qemuDomainObjExitMonitorWithDriver(driver, vm);
+
+#if WITH_MACVTAP
+ if (detach->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
+ if (detach->ifname)
+ delMacvtap(detach->ifname);
+ }
+#endif
+
+ VIR_FREE(hostnet_name);
+ return 0;
+}
+
+static int qemudDomainDetachNetDevice(struct qemud_driver *driver,
+ virDomainObjPtr vm,
+ virDomainDeviceDefPtr dev,
+ unsigned long long qemuCmdFlags)
+{
+ int i;
+ virDomainNetDefPtr detach = NULL;
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+
for (i = 0 ; i < vm->def->nnets ; i++) {
virDomainNetDefPtr net = vm->def->nets[i];
@@ -6914,53 +6945,33 @@ qemudDomainDetachNetDevice(struct qemud_
dev->data.net->mac[0], dev->data.net->mac[1],
dev->data.net->mac[2], dev->data.net->mac[3],
dev->data.net->mac[4], dev->data.net->mac[5]);
- goto cleanup;
+ return -1;
}
if (!virDomainDeviceAddressIsValid(&detach->info,
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
qemuReportError(VIR_ERR_OPERATION_FAILED,
"%s", _("device cannot be detached without a PCI address"));
- goto cleanup;
- }
-
- if ((vlan = qemuDomainNetVLAN(detach)) < 0) {
- qemuReportError(VIR_ERR_OPERATION_FAILED,
- "%s", _("unable to determine original VLAN"));
- goto cleanup;
- }
-
- if (virAsprintf(&hostnet_name, "host%s", detach->info.alias) < 0) {
- virReportOOMError();
- goto cleanup;
+ return -1;
}
qemuDomainObjEnterMonitorWithDriver(driver, vm);
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
- qemuDomainObjExitMonitor(vm);
- goto cleanup;
+ qemuDomainObjExitMonitorWithDriver(driver, vm);
+ return -1;
}
} else {
if (qemuMonitorRemovePCIDevice(priv->mon,
&detach->info.addr.pci) < 0) {
qemuDomainObjExitMonitorWithDriver(driver, vm);
- goto cleanup;
+ return -1;
}
}
-
- if (qemuMonitorRemoveHostNetwork(priv->mon, vlan, hostnet_name) < 0) {
- qemuDomainObjExitMonitorWithDriver(driver, vm);
- goto cleanup;
- }
qemuDomainObjExitMonitorWithDriver(driver, vm);
-#if WITH_MACVTAP
- if (detach->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
- if (detach->ifname)
- delMacvtap(detach->ifname);
- }
-#endif
+ if (qemudDomainDisconnectNetBackend(driver, vm, detach) < 0)
+ VIR_WARN0("Failed to disconnect network backend");
if ((driver->macFilter) && (detach->ifname != NULL)) {
if ((errno = networkDisallowMacOnPort(driver,
@@ -6987,11 +6998,7 @@ qemudDomainDetachNetDevice(struct qemud_
}
virDomainNetDefFree(detach);
- ret = 0;
-
-cleanup:
- VIR_FREE(hostnet_name);
- return ret;
+ return 0;
}
static int qemudDomainDetachHostPciDevice(struct qemud_driver *driver,
14 years, 9 months
[libvirt] Fix locking in qemudDomainMemoryStats
by Adam Litke
When adding domainMemoryStats API support for the qemu driver, I didn't
follow the locking rules exactly. The job condition must be held when
executing monitor commands. This corrects the segfaults I was seeing
when calling domainMemoryStats in a multi-threaded environment.
If this patch is accepted, I would also consider it a candidate for the
0.7.6 stable patch stream (if such a thing exists). Thanks.
Signed-off-by: Adam Litke <agl(a)us.ibm.com>
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index b8b7916..a9023da 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -7526,6 +7526,9 @@ qemudDomainMemoryStats (virDomainPtr dom,
goto cleanup;
}
+ if (qemuDomainObjBeginJob(vm) < 0)
+ goto cleanup;
+
if (virDomainObjIsActive(vm)) {
qemuDomainObjPrivatePtr priv = vm->privateData;
qemuDomainObjEnterMonitor(vm);
@@ -7536,6 +7539,9 @@ qemudDomainMemoryStats (virDomainPtr dom,
"%s", _("domain is not running"));
}
+ if (qemuDomainObjEndJob(vm) == 0)
+ vm = NULL;
+
cleanup:
if (vm)
virDomainObjUnlock(vm);
--
Thanks,
Adam
14 years, 9 months
[libvirt] Unable to start a VM with USB device
by Laurent Léonard
Hi,
I just packaged libvirt 0.7.7 for Debian.
But I can't start a VM with an USB device attached:
# virsh start test-vm
error: Failed to start domain test-vm
error: unable to set security context '107:113' on '/dev/bus/usb/000/000': No
such file or directory
I know there were changes about USB passthrough so I suppose it's a bug.
Thank you,
--
Laurent Léonard
14 years, 9 months
[libvirt] [PATCHv2] Eliminate large stack buffer in doTunnelSendAll
by Laine Stump
doTunnelSendAll function (used by QEMU migration) uses a 64k buffer on
the stack, which could be problematic. This patch replaces that with a
buffer from the heap.
While in the neighborhood, this patch also improves error reporting in
the case that saferead fails - previously, virStreamAbort() was called
(resetting errno) before reporting the error. It's been changed to
report the error first.
---
Eric noticed that I was inconsistent in the ordering of cleanup
vs. error reporting, so I fixed that in this version.
src/qemu/qemu_driver.c | 18 +++++++++++++++---
1 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index bb3edde..5a18938 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -8399,19 +8399,28 @@ cleanup:
}
+#define TUNNEL_SEND_BUF_SIZE 65536
+
static int doTunnelSendAll(virStreamPtr st,
int sock)
{
- char buffer[65536];
- int nbytes = sizeof(buffer);
+ char *buffer;
+ int nbytes = TUNNEL_SEND_BUF_SIZE;
+
+ if (VIR_ALLOC_N(buffer, TUNNEL_SEND_BUF_SIZE) < 0) {
+ virReportOOMError();
+ virStreamAbort(st);
+ return -1;
+ }
/* XXX should honour the 'resource' parameter here */
for (;;) {
nbytes = saferead(sock, buffer, nbytes);
if (nbytes < 0) {
- virStreamAbort(st);
virReportSystemError(errno, "%s",
_("tunnelled migration failed to read from qemu"));
+ virStreamAbort(st);
+ VIR_FREE(buffer);
return -1;
}
else if (nbytes == 0)
@@ -8421,10 +8430,13 @@ static int doTunnelSendAll(virStreamPtr st,
if (virStreamSend(st, buffer, nbytes) < 0) {
qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
_("Failed to write migration data to remote libvirtd"));
+ VIR_FREE(buffer);
return -1;
}
}
+ VIR_FREE(buffer);
+
if (virStreamFinish(st) < 0)
/* virStreamFinish set the error for us */
return -1;
--
1.6.6.1
14 years, 9 months
[libvirt] [PATCH 0/5] build: use C99 varargs
by Eric Blake
Here's the full cleanup, based on my earlier RFC. I've tested
that everything still builds and passes 'make syntax-check'.
This is broken out in chunks, although whoever ends up pushing
may want to squash it all into one.
src/conf/cpu_conf.c | 4 ++--
src/conf/domain_conf.c | 4 ++--
src/conf/domain_event.c | 5 +++--
src/conf/interface_conf.c | 4 ++--
src/conf/network_conf.c | 6 +++---
src/conf/node_device_conf.h | 5 +++--
src/conf/secret_conf.h | 6 +++---
src/conf/storage_conf.h | 6 +++---
src/cpu/cpu.h | 6 +++---
src/datatypes.c | 6 +++---
src/esx/esx_device_monitor.c | 5 +++--
src/esx/esx_driver.c | 5 +++--
src/esx/esx_interface_driver.c | 5 +++--
src/esx/esx_network_driver.c | 5 +++--
src/esx/esx_secret_driver.c | 5 +++--
src/esx/esx_storage_driver.c | 5 +++--
src/esx/esx_util.c | 5 +++--
src/esx/esx_vi.c | 5 +++--
src/esx/esx_vi_methods.c | 5 +++--
src/esx/esx_vi_types.c | 5 +++--
src/esx/esx_vmx.c | 5 +++--
src/interface/netcf_driver.c | 6 +++---
src/libvirt.c | 6 +++---
src/lxc/lxc_conf.h | 5 +++--
src/network/bridge_driver.c | 4 ++--
src/nodeinfo.c | 6 +++---
src/opennebula/one_conf.h | 8 +++++---
src/openvz/openvz_conf.h | 5 +++--
src/phyp/phyp_driver.c | 5 +++--
src/qemu/qemu_conf.h | 4 ++--
src/remote/remote_driver.c | 4 ++--
src/security/security_driver.h | 6 +++---
src/test/test_driver.c | 4 ++--
src/uml/uml_conf.h | 6 +++---
src/util/hostusb.c | 4 ++--
src/util/json.c | 6 +++---
src/util/macvtap.c | 5 +++--
src/util/pci.c | 4 ++--
src/util/stats_linux.c | 6 +++---
src/util/util.c | 4 ++--
src/util/xml.c | 6 +++---
src/vbox/vbox_driver.c | 5 +++--
src/vbox/vbox_tmpl.c | 5 +++--
src/xen/proxy_internal.c | 4 ++--
src/xen/sexpr.c | 9 ++++-----
src/xen/xen_driver.c | 4 ++--
src/xen/xen_hypervisor.c | 6 +++---
src/xen/xen_inotify.c | 5 +++--
src/xen/xend_internal.c | 9 ++++-----
src/xen/xm_internal.c | 6 +++---
src/xen/xs_internal.c | 4 ++--
51 files changed, 144 insertions(+), 124 deletions(-)
14 years, 9 months
[libvirt] [PATCH] Get thread and socket information in virsh nodeinfo.
by Chris Lalancette
The current code for "nodeinfo" is pretty naive
about socket and thread information. To determine the
sockets, it just takes the number of cpus and divides
by the number of cores. For the thread count, it always
sets it to 1. With more recent Intel machines, however,
hyperthreading is again an option, meaning that these
heuristics no longer work and give bogus numbers. This
patch goes through /sys to get the additional
information so we properly report it.
Note that I had to edit the tests not to report on
socket and thread counts, since these are determined
dynamically now.
Signed-off-by: Chris Lalancette <clalance(a)redhat.com>
---
src/nodeinfo.c | 140 +++++++++++++++++++++++++++++--
tests/nodeinfodata/linux-nodeinfo-1.txt | 2 +-
tests/nodeinfodata/linux-nodeinfo-2.txt | 2 +-
tests/nodeinfodata/linux-nodeinfo-3.txt | 2 +-
tests/nodeinfodata/linux-nodeinfo-4.txt | 2 +-
tests/nodeinfodata/linux-nodeinfo-5.txt | 2 +-
tests/nodeinfodata/linux-nodeinfo-6.txt | 2 +-
tests/nodeinfotest.c | 5 +-
8 files changed, 139 insertions(+), 18 deletions(-)
diff --git a/src/nodeinfo.c b/src/nodeinfo.c
index 2d44609..18efd28 100644
--- a/src/nodeinfo.c
+++ b/src/nodeinfo.c
@@ -28,6 +28,7 @@
#include <stdlib.h>
#include <stdint.h>
#include <errno.h>
+#include <dirent.h>
#if HAVE_NUMACTL
# define NUMA_VERSION1_COMPATIBILITY 1
@@ -55,22 +56,117 @@
#ifdef __linux__
#define CPUINFO_PATH "/proc/cpuinfo"
+#define CPU_SYS_PATH "/sys/devices/system/cpu"
-/* NB, these are not static as we need to call them from testsuite */
+/* NB, this is not static as we need to call it from the testsuite */
int linuxNodeInfoCPUPopulate(virConnectPtr conn, FILE *cpuinfo,
virNodeInfoPtr nodeinfo);
-int linuxNodeInfoCPUPopulate(virConnectPtr conn, FILE *cpuinfo, virNodeInfoPtr nodeinfo) {
+static int popcnt(char x)
+{
+ char count;
+ for (count = 0; x; count++)
+ x &= x-1;
+ return count;
+}
+
+static unsigned long count_thread_siblings(int cpu)
+{
+ unsigned long ret = 0;
+ char *path = NULL;
+ FILE *pathfp = NULL;
+ char str[1024];
+ int i;
+
+ if (virAsprintf(&path, "%s/cpu%d/topology/thread_siblings", CPU_SYS_PATH,
+ cpu) < 0) {
+ virReportOOMError();
+ return 0;
+ }
+
+ pathfp = fopen(path, "r");
+ if (pathfp == NULL) {
+ virReportSystemError(errno, _("cannot open %s"), path);
+ VIR_FREE(path);
+ return 0;
+ }
+
+ if (fgets(str, sizeof(str), pathfp) == NULL) {
+ virReportSystemError(errno, _("cannot read from %s"), path);
+ goto cleanup;
+ }
+
+ i = 0;
+ while (str[i] != '\0') {
+ if (str[i] != '\n' && str[i] != ',')
+ ret += popcnt(str[i] - '0');
+ i++;
+ }
+
+cleanup:
+ fclose(pathfp);
+ VIR_FREE(path);
+
+ return ret;
+}
+
+static int parse_socket(int cpu)
+{
+ char *path = NULL;
+ FILE *pathfp;
+ char socket_str[1024];
+ char *tmp;
+ int socket;
+
+ if (virAsprintf(&path, "%s/cpu%d/topology/physical_package_id",
+ CPU_SYS_PATH, cpu) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+
+ pathfp = fopen(path, "r");
+ if (pathfp == NULL) {
+ virReportSystemError(errno, _("cannot open %s"), path);
+ goto cleanup;
+ }
+
+ if (fgets(socket_str, sizeof(socket_str), pathfp) == NULL) {
+ virReportSystemError(errno, _("cannot read from %s"), path);
+ goto cleanup;
+ }
+ if (virStrToLong_i(socket_str, &tmp, 10, &socket) < 0) {
+ nodeReportError(NULL, VIR_ERR_INTERNAL_ERROR,
+ _("could not convert '%s' to an integer"),
+ socket_str);
+ goto cleanup;
+ }
+
+cleanup:
+ fclose(pathfp);
+ VIR_FREE(path);
+
+ return socket;
+}
+
+int linuxNodeInfoCPUPopulate(virConnectPtr conn, FILE *cpuinfo,
+ virNodeInfoPtr nodeinfo)
+{
char line[1024];
+ DIR *cpudir = NULL;
+ struct dirent *cpudirent = NULL;
+ int cpu;
+ unsigned long cur_threads;
+ int socket;
+ unsigned long long socket_mask = 0;
nodeinfo->cpus = 0;
nodeinfo->mhz = 0;
- nodeinfo->nodes = nodeinfo->sockets = nodeinfo->cores = nodeinfo->threads = 1;
+ nodeinfo->nodes = nodeinfo->cores = 1;
/* NB: It is impossible to fill our nodes, since cpuinfo
* has not knowledge of NUMA nodes */
- /* XXX hyperthreads */
+ /* NOTE: hyperthreads are ignored here; they are parsed out of /sys */
while (fgets(line, sizeof(line), cpuinfo) != NULL) {
char *buf = line;
if (STRPREFIX(buf, "processor")) { /* aka a single logical CPU */
@@ -122,12 +218,38 @@ int linuxNodeInfoCPUPopulate(virConnectPtr conn, FILE *cpuinfo, virNodeInfoPtr n
return -1;
}
- /*
- * Can't reliably count sockets from proc metadata, so
- * infer it based on total CPUs vs cores.
- * XXX hyperthreads
+ /* OK, we've parsed what we can out of /proc/cpuinfo. Get the socket
+ * and thread information from /sys
*/
- nodeinfo->sockets = nodeinfo->cpus / nodeinfo->cores;
+ cpudir = opendir(CPU_SYS_PATH);
+ if (cpudir == NULL) {
+ virReportSystemError(errno, _("cannot opendir %s"), CPU_SYS_PATH);
+ return -1;
+ }
+ while ((cpudirent = readdir(cpudir))) {
+ if (sscanf(cpudirent->d_name, "cpu%d", &cpu) != 1)
+ continue;
+
+ socket = parse_socket(cpu);
+ if (socket < 0) {
+ closedir(cpudir);
+ return -1;
+ }
+ if (!(socket_mask & (1 << socket))) {
+ socket_mask |= (1 << socket);
+ nodeinfo->sockets++;
+ }
+
+ cur_threads = count_thread_siblings(cpu);
+ if (cur_threads == 0) {
+ closedir(cpudir);
+ return -1;
+ }
+ if (cur_threads > nodeinfo->threads)
+ nodeinfo->threads = cur_threads;
+ }
+
+ closedir(cpudir);
return 0;
}
diff --git a/tests/nodeinfodata/linux-nodeinfo-1.txt b/tests/nodeinfodata/linux-nodeinfo-1.txt
index e52e20a..09e2946 100644
--- a/tests/nodeinfodata/linux-nodeinfo-1.txt
+++ b/tests/nodeinfodata/linux-nodeinfo-1.txt
@@ -1 +1 @@
-CPUs: 2, MHz: 2800, Nodes: 1, Sockets: 1, Cores: 2, Threads: 1
+CPUs: 2, MHz: 2800, Nodes: 1, Cores: 2
diff --git a/tests/nodeinfodata/linux-nodeinfo-2.txt b/tests/nodeinfodata/linux-nodeinfo-2.txt
index 12e819b..e4eea94 100644
--- a/tests/nodeinfodata/linux-nodeinfo-2.txt
+++ b/tests/nodeinfodata/linux-nodeinfo-2.txt
@@ -1 +1 @@
-CPUs: 2, MHz: 2211, Nodes: 1, Sockets: 1, Cores: 2, Threads: 1
+CPUs: 2, MHz: 2211, Nodes: 1, Cores: 2
diff --git a/tests/nodeinfodata/linux-nodeinfo-3.txt b/tests/nodeinfodata/linux-nodeinfo-3.txt
index d285781..17d4d8e 100644
--- a/tests/nodeinfodata/linux-nodeinfo-3.txt
+++ b/tests/nodeinfodata/linux-nodeinfo-3.txt
@@ -1 +1 @@
-CPUs: 4, MHz: 1595, Nodes: 1, Sockets: 2, Cores: 2, Threads: 1
+CPUs: 4, MHz: 1595, Nodes: 1, Cores: 2
diff --git a/tests/nodeinfodata/linux-nodeinfo-4.txt b/tests/nodeinfodata/linux-nodeinfo-4.txt
index 991d4f9..5a5c919 100644
--- a/tests/nodeinfodata/linux-nodeinfo-4.txt
+++ b/tests/nodeinfodata/linux-nodeinfo-4.txt
@@ -1 +1 @@
-CPUs: 4, MHz: 1000, Nodes: 1, Sockets: 1, Cores: 4, Threads: 1
+CPUs: 4, MHz: 1000, Nodes: 1, Cores: 4
diff --git a/tests/nodeinfodata/linux-nodeinfo-5.txt b/tests/nodeinfodata/linux-nodeinfo-5.txt
index dce7ada..54abb5d 100644
--- a/tests/nodeinfodata/linux-nodeinfo-5.txt
+++ b/tests/nodeinfodata/linux-nodeinfo-5.txt
@@ -1 +1 @@
-CPUs: 4, MHz: 2814, Nodes: 1, Sockets: 2, Cores: 2, Threads: 1
+CPUs: 4, MHz: 2814, Nodes: 1, Cores: 2
diff --git a/tests/nodeinfodata/linux-nodeinfo-6.txt b/tests/nodeinfodata/linux-nodeinfo-6.txt
index 75cdaa9..f89e35e 100644
--- a/tests/nodeinfodata/linux-nodeinfo-6.txt
+++ b/tests/nodeinfodata/linux-nodeinfo-6.txt
@@ -1 +1 @@
-CPUs: 4, MHz: 1000, Nodes: 1, Sockets: 2, Cores: 2, Threads: 1
+CPUs: 4, MHz: 1000, Nodes: 1, Cores: 2
diff --git a/tests/nodeinfotest.c b/tests/nodeinfotest.c
index 4cb248a..b3b91ad 100644
--- a/tests/nodeinfotest.c
+++ b/tests/nodeinfotest.c
@@ -47,9 +47,8 @@ static int linuxTestCompareFiles(const char *cpuinfofile, const char *outputfile
fclose(cpuinfo);
snprintf(actualData, MAX_FILE,
- "CPUs: %u, MHz: %u, Nodes: %u, Sockets: %u, Cores: %u, Threads: %u\n",
- nodeinfo.cpus, nodeinfo.mhz, nodeinfo.nodes, nodeinfo.sockets,
- nodeinfo.cores, nodeinfo.threads);
+ "CPUs: %u, MHz: %u, Nodes: %u, Cores: %u\n",
+ nodeinfo.cpus, nodeinfo.mhz, nodeinfo.nodes, nodeinfo.cores);
if (STRNEQ(actualData, expectData)) {
if (getenv("DEBUG_TESTS")) {
--
1.6.6.1
14 years, 9 months