[libvirt] [PATCH] qemu: Warn when using vhost-user without shared memory
by Martin Kletzander
When user configures vhost-user interface and forgets to also configure
any shared memory, the search for the root cause of non-operational
interface might take unpleasantly long time. Let's enhance user
experience by emitting a warning in the logs.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1266982
Signed-off-by: Martin Kletzander <mkletzan(a)redhat.com>
---
src/qemu/qemu_process.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 420196264685..fb471342e790 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -4542,6 +4542,7 @@ qemuProcessLaunch(virConnectPtr conn,
unsigned int hostdev_flags = 0;
size_t nnicindexes = 0;
int *nicindexes = NULL;
+ bool check_shmem = false;
VIR_DEBUG("vm=%p name=%s id=%d asyncJob=%d "
"incoming.launchURI=%s incoming.deferredURI=%s "
@@ -4749,6 +4750,49 @@ qemuProcessLaunch(virConnectPtr conn,
goto cleanup;
}
+ VIR_DEBUG("Checking for any possible (non-fatal) issues");
+
+ /*
+ * For vhost-user to work, the domain has to have some type of
+ * shared memory configured. We're not the proper once to judge
+ * whether shared hugepages or shm are enough and will be in the
+ * future, so we'll just warn in case there is none of that
+ * configured. Moreover failing would give the false illusion
+ * that libvirt is really checking that everything works before
+ * running the domain and not only we are unable to do that, but
+ * it's also not our aim to do so.
+ */
+ for (i = 0; i < vm->def->nnets; i++) {
+ if (virDomainNetGetActualType(vm->def->nets[i]) ==
+ VIR_DOMAIN_NET_TYPE_VHOSTUSER) {
+ check_shmem = true;
+ break;
+ }
+ }
+
+ if (check_shmem) {
+ bool shmem = vm->def->nshmems;
+
+ /*
+ * This check is by no means complete. We merely check
+ * whetere there are *some* hugepages enabled and *some* NUMA
+ * nodes with shared memory access.
+ */
+ if (!shmem && vm->def->mem.nhugepages) {
+ for (i = 0; i < virDomainNumaGetNodeCount(vm->def->numa); i++) {
+ if (virDomainNumaGetNodeMemoryAccessMode(vm->def->numa, i) ==
+ VIR_NUMA_MEM_ACCESS_SHARED)
+ shmem = true;
+ break;
+ }
+ }
+
+ if (!shmem) {
+ VIR_WARN("Detected vhost-user interface without any shared memory. "
+ "The interface might not be operational");
+ }
+ }
+
VIR_DEBUG("Building emulator command line");
if (!(cmd = qemuBuildCommandLine(conn, driver, vm->def, priv->monConfig,
priv->monJSON, priv->qemuCaps,
--
2.6.3
8 years, 11 months
[libvirt] [PATCH] qemuMonitorJSONEjectMedia: don't stringify the replay at all
by Pavel Hrdina
Commit 256496e1 introduced a detection if "is locked" in error replay
from qemu monitor. Commit c4073657 fixed a memory leak, but it was
pointed out by Peter, that this could be done cleaner without
stringifing the replay.
Signed-off-by: Pavel Hrdina <phrdina(a)redhat.com>
---
src/qemu/qemu_monitor_json.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 4ae63cf..d4b6514 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -2223,11 +2223,12 @@ int qemuMonitorJSONEjectMedia(qemuMonitorPtr mon,
ret = qemuMonitorJSONCheckError(cmd, reply);
if (ret < 0) {
- char *replyStr = virJSONValueToString(reply, false);
-
- if (c_strcasestr(replyStr, "is locked"))
- ret = -2;
- VIR_FREE(replyStr);
+ virJSONValuePtr error = virJSONValueObjectGet(reply, "error");
+ if (error) {
+ const char *errorStr = virJSONValueObjectGetString(error, "desc");
+ if (errorStr && c_strcasestr(errorStr, "is locked"))
+ ret = -2;
+ }
}
virJSONValueFree(cmd);
--
2.6.4
8 years, 11 months
[libvirt] qemu logging/tracing option in domain xml
by Dmitry Andreev
Hi all,
QEMU has the '-d' command line option to configure logs/traces.
As I can see, <qemu:commandline> is the only way to set it in domain xml.
<qemu:commandline> makes a configuration tainted and doesn't allow to
update tracing/logging configuration in runtime. The ability to update
configuration in runtime will be very useful for us in Virtuozzo for
QEMU problem investigation and development.
So I want to ask you will you mind if I prepare a patch-set that
introduces a new section for domain xml with next scheme:
<element name="debug">
<zeroOrMore>
<element name="log">
<attribute name="name">
<ref name="filter-param-value"/>
</attribute>
</element>
</zeroOrMore>
</element>
Is this acceptable?
8 years, 11 months
[libvirt] [PATCH] pci: Use 'addr' instead of 'dev' for virPCIDeviceAddressPtr
by Andrea Bolognani
The name 'dev' is more appropriate for virPCIDevicePtr.
---
src/util/virpci.c | 7 ++++---
src/util/virpci.h | 4 ++--
2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/src/util/virpci.c b/src/util/virpci.c
index bb874ac..9cc4613 100644
--- a/src/util/virpci.c
+++ b/src/util/virpci.c
@@ -2655,12 +2655,13 @@ virPCIGetSysfsFile(char *virPCIDeviceName, char **pci_sysfs_device_link)
}
int
-virPCIDeviceAddressGetSysfsFile(virPCIDeviceAddressPtr dev,
+virPCIDeviceAddressGetSysfsFile(virPCIDeviceAddressPtr addr,
char **pci_sysfs_device_link)
{
if (virAsprintf(pci_sysfs_device_link,
- PCI_SYSFS "devices/%04x:%02x:%02x.%x", dev->domain,
- dev->bus, dev->slot, dev->function) < 0)
+ PCI_SYSFS "devices/%04x:%02x:%02x.%x",
+ addr->domain, addr->bus,
+ addr->slot, addr->function) < 0)
return -1;
return 0;
}
diff --git a/src/util/virpci.h b/src/util/virpci.h
index 6516f05..f3d5676 100644
--- a/src/util/virpci.h
+++ b/src/util/virpci.h
@@ -159,7 +159,7 @@ virPCIDeviceListPtr virPCIDeviceGetIOMMUGroupList(virPCIDevicePtr dev);
int virPCIDeviceAddressGetIOMMUGroupAddresses(virPCIDeviceAddressPtr devAddr,
virPCIDeviceAddressPtr **iommuGroupDevices,
size_t *nIommuGroupDevices);
-int virPCIDeviceAddressGetIOMMUGroupNum(virPCIDeviceAddressPtr dev);
+int virPCIDeviceAddressGetIOMMUGroupNum(virPCIDeviceAddressPtr addr);
char *virPCIDeviceGetIOMMUGroupDev(virPCIDevicePtr dev);
int virPCIDeviceIsAssignable(virPCIDevicePtr dev,
@@ -180,7 +180,7 @@ int virPCIGetVirtualFunctionIndex(const char *pf_sysfs_device_link,
const char *vf_sysfs_device_link,
int *vf_index);
-int virPCIDeviceAddressGetSysfsFile(virPCIDeviceAddressPtr dev,
+int virPCIDeviceAddressGetSysfsFile(virPCIDeviceAddressPtr addr,
char **pci_sysfs_device_link);
int virPCIGetNetName(char *device_link_sysfs_path, char **netname);
--
2.5.0
8 years, 11 months
[libvirt] [PATCH] qemuMonitorJSONEjectMedia: Don't leak stringified reply
by Michal Privoznik
The return value of virJSONValueToString() should be freed when
no longer needed. This is not the case after 256496e1.
==26902== 138 bytes in 2 blocks are definitely lost in loss record 1,051 of 1,239
==26902== at 0x4C29F80: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==26902== by 0xAA5F599: strdup (in /lib64/libc-2.21.so)
==26902== by 0x552BAD9: virStrdup (virstring.c:726)
==26902== by 0x54F60A7: virJSONValueToString (virjson.c:1790)
==26902== by 0x1DF6EBB9: qemuMonitorJSONEjectMedia (qemu_monitor_json.c:2225)
==26902== by 0x1DF57A4C: qemuMonitorEjectMedia (qemu_monitor.c:1985)
==26902== by 0x1DF1EF2D: qemuDomainChangeEjectableMedia (qemu_hotplug.c:199)
==26902== by 0x1DF90314: qemuDomainChangeDiskLive (qemu_driver.c:7985)
==26902== by 0x1DF90476: qemuDomainUpdateDeviceLive (qemu_driver.c:8030)
==26902== by 0x1DF91ED7: qemuDomainUpdateDeviceFlags (qemu_driver.c:8677)
==26902== by 0x561785F: virDomainUpdateDeviceFlags (libvirt-domain.c:8559)
==26902== by 0x134210: remoteDispatchDomainUpdateDeviceFlags (remote_dispatch.h:10966)
==26902== 106 bytes in 1 blocks are definitely lost in loss record 1,033 of 1,239
==26902== at 0x4C29F80: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==26902== by 0xAA5F599: strdup (in /lib64/libc-2.21.so)
==26902== by 0x552BAD9: virStrdup (virstring.c:726)
==26902== by 0x54F60A7: virJSONValueToString (virjson.c:1790)
==26902== by 0x1DF6EC0C: qemuMonitorJSONEjectMedia (qemu_monitor_json.c:2227)
==26902== by 0x1DF57A4C: qemuMonitorEjectMedia (qemu_monitor.c:1985)
==26902== by 0x1DF1EF2D: qemuDomainChangeEjectableMedia (qemu_hotplug.c:199)
==26902== by 0x1DF90314: qemuDomainChangeDiskLive (qemu_driver.c:7985)
==26902== by 0x1DF90476: qemuDomainUpdateDeviceLive (qemu_driver.c:8030)
==26902== by 0x1DF91ED7: qemuDomainUpdateDeviceFlags (qemu_driver.c:8677)
==26902== by 0x561785F: virDomainUpdateDeviceFlags (libvirt-domain.c:8559)
==26902== by 0x134210: remoteDispatchDomainUpdateDeviceFlags (remote_dispatch.h:10966)
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
src/qemu/qemu_monitor_json.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 84c0be2..4ae63cf 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -2222,10 +2222,13 @@ int qemuMonitorJSONEjectMedia(qemuMonitorPtr mon,
if (ret == 0)
ret = qemuMonitorJSONCheckError(cmd, reply);
- VIR_DEBUG("%s", virJSONValueToString(reply, false));
+ if (ret < 0) {
+ char *replyStr = virJSONValueToString(reply, false);
- if (ret < 0 && c_strcasestr(virJSONValueToString(reply, false), "is locked"))
- ret = -2;
+ if (c_strcasestr(replyStr, "is locked"))
+ ret = -2;
+ VIR_FREE(replyStr);
+ }
virJSONValueFree(cmd);
virJSONValueFree(reply);
--
2.4.10
8 years, 11 months
[libvirt] [PATCH] pci: Use virPCIDeviceAddress in virPCIDevice
by Andrea Bolognani
Instead of replicating the information (domain, bus, slot, function)
inside the virPCIDevice structure, use the already-existing
virPCIDeviceAddress structure.
Outside of the module, the only visible change is that the return value
of virPCIDeviceGetAddress() must no longer be freed by the caller.
---
Suggested by Laine[1] in the context of a patch series; since the idea
is not really tied to the series, sending as a stand-alone cleanup.
[1] https://www.redhat.com/archives/libvir-list/2015-December/msg00125.html
src/util/virhostdev.c | 4 --
src/util/virpci.c | 182 ++++++++++++++++++++++++++++++++++----------------
src/util/virpci.h | 7 ++
3 files changed, 133 insertions(+), 60 deletions(-)
diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c
index de029a0..173ac58 100644
--- a/src/util/virhostdev.c
+++ b/src/util/virhostdev.c
@@ -585,7 +585,6 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
goto cleanup;
}
- VIR_FREE(devAddr);
if (!(devAddr = virPCIDeviceGetAddress(dev)))
goto cleanup;
@@ -728,7 +727,6 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
virObjectUnlock(hostdev_mgr->activePCIHostdevs);
virObjectUnlock(hostdev_mgr->inactivePCIHostdevs);
virObjectUnref(pcidevs);
- VIR_FREE(devAddr);
return ret;
}
@@ -1581,7 +1579,6 @@ virHostdevPCINodeDeviceDetach(virHostdevManagerPtr hostdev_mgr,
out:
virObjectUnlock(hostdev_mgr->inactivePCIHostdevs);
virObjectUnlock(hostdev_mgr->activePCIHostdevs);
- VIR_FREE(devAddr);
return ret;
}
@@ -1613,7 +1610,6 @@ virHostdevPCINodeDeviceReAttach(virHostdevManagerPtr hostdev_mgr,
out:
virObjectUnlock(hostdev_mgr->inactivePCIHostdevs);
virObjectUnlock(hostdev_mgr->activePCIHostdevs);
- VIR_FREE(devAddr);
return ret;
}
diff --git a/src/util/virpci.c b/src/util/virpci.c
index bececb5..2818bf7 100644
--- a/src/util/virpci.c
+++ b/src/util/virpci.c
@@ -56,10 +56,7 @@ VIR_ENUM_IMPL(virPCIELinkSpeed, VIR_PCIE_LINK_SPEED_LAST,
"", "2.5", "5", "8")
struct _virPCIDevice {
- unsigned int domain;
- unsigned int bus;
- unsigned int slot;
- unsigned int function;
+ virPCIDeviceAddressPtr address;
char name[PCI_ADDR_LEN]; /* domain:bus:slot.function */
char id[PCI_ID_LEN]; /* product vendor */
@@ -653,12 +650,14 @@ static int
virPCIDeviceSharesBusWithActive(virPCIDevicePtr dev, virPCIDevicePtr check, void *data)
{
virPCIDeviceList *inactiveDevs = data;
+ virPCIDeviceAddressPtr devAddr = dev->address;
+ virPCIDeviceAddressPtr checkAddr = check->address;
/* Different domain, different bus, or simply identical device */
- if (dev->domain != check->domain ||
- dev->bus != check->bus ||
- (dev->slot == check->slot &&
- dev->function == check->function))
+ if (devAddr->domain != checkAddr->domain ||
+ devAddr->bus != checkAddr->bus ||
+ (devAddr->slot == checkAddr->slot &&
+ devAddr->function == checkAddr->function))
return 0;
/* same bus, but inactive, i.e. about to be assigned to guest */
@@ -686,10 +685,12 @@ virPCIDeviceIsParent(virPCIDevicePtr dev, virPCIDevicePtr check, void *data)
uint16_t device_class;
uint8_t header_type, secondary, subordinate;
virPCIDevicePtr *best = data;
+ virPCIDeviceAddressPtr devAddr = dev->address;
+ virPCIDeviceAddressPtr checkAddr = check->address;
int ret = 0;
int fd;
- if (dev->domain != check->domain)
+ if (devAddr->domain != checkAddr->domain)
return 0;
if ((fd = virPCIDeviceConfigOpen(check, false)) < 0)
@@ -713,7 +714,7 @@ virPCIDeviceIsParent(virPCIDevicePtr dev, virPCIDevicePtr check, void *data)
/* if the secondary bus exactly equals the device's bus, then we found
* the direct parent. No further work is necessary
*/
- if (dev->bus == secondary) {
+ if (devAddr->bus == secondary) {
ret = 1;
goto cleanup;
}
@@ -722,10 +723,10 @@ virPCIDeviceIsParent(virPCIDevicePtr dev, virPCIDevicePtr check, void *data)
* In this case, what we need to do is look for the "best" match; i.e.
* the most restrictive match that still satisfies all of the conditions.
*/
- if (dev->bus > secondary && dev->bus <= subordinate) {
+ if (devAddr->bus > secondary && devAddr->bus <= subordinate) {
if (*best == NULL) {
- *best = virPCIDeviceNew(check->domain, check->bus, check->slot,
- check->function);
+ *best = virPCIDeviceNew(checkAddr->domain, checkAddr->bus,
+ checkAddr->slot, checkAddr->function);
if (*best == NULL) {
ret = -1;
goto cleanup;
@@ -745,8 +746,8 @@ virPCIDeviceIsParent(virPCIDevicePtr dev, virPCIDevicePtr check, void *data)
if (secondary > best_secondary) {
virPCIDeviceFree(*best);
- *best = virPCIDeviceNew(check->domain, check->bus, check->slot,
- check->function);
+ *best = virPCIDeviceNew(checkAddr->domain, checkAddr->bus,
+ checkAddr->slot, checkAddr->function);
if (*best == NULL) {
ret = -1;
goto cleanup;
@@ -925,6 +926,7 @@ virPCIDeviceReset(virPCIDevicePtr dev,
char *drvName = NULL;
int ret = -1;
int fd = -1;
+ virPCIDeviceAddressPtr devAddr = dev->address;
if (activeDevs && virPCIDeviceListFind(activeDevs, dev)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -970,7 +972,7 @@ virPCIDeviceReset(virPCIDevicePtr dev,
ret = virPCIDeviceTryPowerManagementReset(dev, fd);
/* Bus reset is not an option with the root bus */
- if (ret < 0 && dev->bus != 0)
+ if (ret < 0 && devAddr->bus != 0)
ret = virPCIDeviceTrySecondaryBusReset(dev, fd, inactiveDevs);
if (ret < 0) {
@@ -1428,6 +1430,7 @@ virPCIDeviceWaitForCleanup(virPCIDevicePtr dev, const char *matcher)
bool in_matching_device;
int ret;
size_t match_depth;
+ virPCIDeviceAddressPtr devAddr = dev->address;
fp = fopen("/proc/iomem", "r");
if (!fp) {
@@ -1483,8 +1486,8 @@ virPCIDeviceWaitForCleanup(virPCIDevicePtr dev, const char *matcher)
virStrToLong_ui(tmp + 1, &tmp, 16, &function) < 0 || *tmp != '\n')
continue;
- if (domain != dev->domain || bus != dev->bus || slot != dev->slot ||
- function != dev->function)
+ if (domain != devAddr->domain || bus != devAddr->bus ||
+ slot != devAddr->slot || function != devAddr->function)
continue;
in_matching_device = true;
match_depth = strspn(line, " ");
@@ -1547,6 +1550,72 @@ virPCIGetAddrString(unsigned int domain,
return ret;
}
+/**
+ * virPCIDeviceAddressNew:
+ * @domain: PCI domain
+ * @bus: PCI bus
+ * @slot: PCI slot
+ * @function: PCI function
+ *
+ * Create a new virPCIDeviceAddress object.
+ *
+ * Returns: a new address, or NULL on failure.
+ */
+virPCIDeviceAddressPtr
+virPCIDeviceAddressNew(unsigned int domain,
+ unsigned int bus,
+ unsigned int slot,
+ unsigned int function)
+{
+ virPCIDeviceAddressPtr addr;
+
+ if (VIR_ALLOC(addr) < 0)
+ return NULL;
+
+ addr->domain = domain;
+ addr->bus = bus;
+ addr->slot = slot;
+ addr->function = function;
+
+ return addr;
+}
+
+/**
+ * virPCIDeviceAddressCopy:
+ * @addr: PCI address
+ *
+ * Create a copy of a PCI address.
+ *
+ * Returns: a copy of @addr, or NULL on failure.
+ */
+virPCIDeviceAddressPtr
+virPCIDeviceAddressCopy(virPCIDeviceAddressPtr addr)
+{
+ virPCIDeviceAddressPtr copy;
+
+ if (!addr)
+ return NULL;
+
+ if (VIR_ALLOC(copy) < 0)
+ return NULL;
+
+ *copy = *addr;
+
+ return copy;
+}
+
+/**
+ * virPCIDeviceAddressFree:
+ * @addr: PCI address
+ *
+ * Release all resources associated with a PCI address.
+ */
+void
+virPCIDeviceAddressFree(virPCIDeviceAddressPtr addr)
+{
+ VIR_FREE(addr);
+}
+
virPCIDevicePtr
virPCIDeviceNew(unsigned int domain,
unsigned int bus,
@@ -1560,17 +1629,14 @@ virPCIDeviceNew(unsigned int domain,
if (VIR_ALLOC(dev) < 0)
return NULL;
- dev->domain = domain;
- dev->bus = bus;
- dev->slot = slot;
- dev->function = function;
+ if (!(dev->address = virPCIDeviceAddressNew(domain, bus, slot, function)))
+ goto error;
if (snprintf(dev->name, sizeof(dev->name), "%.4x:%.2x:%.2x.%.1x",
- dev->domain, dev->bus, dev->slot,
- dev->function) >= sizeof(dev->name)) {
+ domain, bus, slot, function) >= sizeof(dev->name)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("dev->name buffer overflow: %.4x:%.2x:%.2x.%.1x"),
- dev->domain, dev->bus, dev->slot, dev->function);
+ domain, bus, slot, function);
goto error;
}
if (virAsprintf(&dev->path, PCI_SYSFS "devices/%s/config",
@@ -1627,9 +1693,13 @@ virPCIDeviceCopy(virPCIDevicePtr dev)
/* shallow copy to take care of most attributes */
*copy = *dev;
+
+ /* deep copy for the rest */
+ copy->address = NULL;
copy->path = copy->stubDriver = NULL;
copy->used_by_drvname = copy->used_by_domname = NULL;
- if (VIR_STRDUP(copy->path, dev->path) < 0 ||
+ if (!(copy->address = virPCIDeviceAddressCopy(dev->address)) ||
+ VIR_STRDUP(copy->path, dev->path) < 0 ||
VIR_STRDUP(copy->stubDriver, dev->stubDriver) < 0 ||
VIR_STRDUP(copy->used_by_drvname, dev->used_by_drvname) < 0 ||
VIR_STRDUP(copy->used_by_domname, dev->used_by_domname) < 0) {
@@ -1649,6 +1719,7 @@ virPCIDeviceFree(virPCIDevicePtr dev)
if (!dev)
return;
VIR_DEBUG("%s %s: freeing", dev->id, dev->name);
+ virPCIDeviceAddressFree(dev->address);
VIR_FREE(dev->path);
VIR_FREE(dev->stubDriver);
VIR_FREE(dev->used_by_drvname);
@@ -1661,25 +1732,14 @@ virPCIDeviceFree(virPCIDevicePtr dev)
* @dev: device to get address from
*
* Take a PCI device on input and return its PCI address. The
- * caller must free the returned value when no longer needed.
+ * returned object is owned by the device and must not be freed.
*
* Returns NULL on failure, the device address on success.
*/
virPCIDeviceAddressPtr
virPCIDeviceGetAddress(virPCIDevicePtr dev)
{
-
- virPCIDeviceAddressPtr pciAddrPtr;
-
- if (!dev || (VIR_ALLOC(pciAddrPtr) < 0))
- return NULL;
-
- pciAddrPtr->domain = dev->domain;
- pciAddrPtr->bus = dev->bus;
- pciAddrPtr->slot = dev->slot;
- pciAddrPtr->function = dev->function;
-
- return pciAddrPtr;
+ return dev->address;
}
const char *
@@ -1888,14 +1948,18 @@ virPCIDeviceListDel(virPCIDeviceListPtr list,
int
virPCIDeviceListFindIndex(virPCIDeviceListPtr list, virPCIDevicePtr dev)
{
+ virPCIDeviceAddressPtr devAddr = dev->address;
+ virPCIDeviceAddressPtr tmpAddr;
size_t i;
- for (i = 0; i < list->count; i++)
- if (list->devs[i]->domain == dev->domain &&
- list->devs[i]->bus == dev->bus &&
- list->devs[i]->slot == dev->slot &&
- list->devs[i]->function == dev->function)
+ for (i = 0; i < list->count; i++) {
+ tmpAddr = list->devs[i]->address;
+ if (tmpAddr->domain == devAddr->domain &&
+ tmpAddr->bus == devAddr->bus &&
+ tmpAddr->slot == devAddr->slot &&
+ tmpAddr->function == devAddr->function)
return i;
+ }
return -1;
}
@@ -1907,13 +1971,16 @@ virPCIDeviceListFindByIDs(virPCIDeviceListPtr list,
unsigned int slot,
unsigned int function)
{
+ virPCIDeviceAddressPtr tmpAddr;
size_t i;
for (i = 0; i < list->count; i++) {
- if (list->devs[i]->domain == domain &&
- list->devs[i]->bus == bus &&
- list->devs[i]->slot == slot &&
- list->devs[i]->function == function)
+ tmpAddr = list->devs[i]->address;
+ if (tmpAddr &&
+ tmpAddr->domain == domain &&
+ tmpAddr->bus == bus &&
+ tmpAddr->slot == slot &&
+ tmpAddr->function == function)
return list->devs[i];
}
return NULL;
@@ -1942,9 +2009,11 @@ int virPCIDeviceFileIterate(virPCIDevicePtr dev,
int ret = -1;
struct dirent *ent;
int direrr;
+ virPCIDeviceAddressPtr devAddr = dev->address;
if (virAsprintf(&pcidir, "/sys/bus/pci/devices/%04x:%02x:%02x.%x",
- dev->domain, dev->bus, dev->slot, dev->function) < 0)
+ devAddr->domain, devAddr->bus,
+ devAddr->slot, devAddr->function) < 0)
goto cleanup;
if (!(dir = opendir(pcidir))) {
@@ -2074,13 +2143,12 @@ virPCIDeviceListPtr
virPCIDeviceGetIOMMUGroupList(virPCIDevicePtr dev)
{
virPCIDeviceListPtr groupList = virPCIDeviceListNew();
- virPCIDeviceAddress devAddr = { dev->domain, dev->bus,
- dev->slot, dev->function };
+ virPCIDeviceAddressPtr devAddr = dev->address;
if (!groupList)
goto error;
- if (virPCIDeviceAddressIOMMUGroupIterate(&devAddr,
+ if (virPCIDeviceAddressIOMMUGroupIterate(devAddr,
virPCIDeviceGetIOMMUGroupAddOne,
groupList) < 0)
goto error;
@@ -2286,6 +2354,7 @@ static int
virPCIDeviceIsBehindSwitchLackingACS(virPCIDevicePtr dev)
{
virPCIDevicePtr parent;
+ virPCIDeviceAddressPtr devAddr = dev->address;
if (virPCIDeviceGetParent(dev, &parent) < 0)
return -1;
@@ -2294,7 +2363,7 @@ virPCIDeviceIsBehindSwitchLackingACS(virPCIDevicePtr dev)
* into play since devices on the root bus can't P2P without going
* through the root IOMMU.
*/
- if (dev->bus == 0) {
+ if (devAddr->bus == 0) {
return 0;
} else {
virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -2664,12 +2733,13 @@ virPCIGetSysfsFile(char *virPCIDeviceName, char **pci_sysfs_device_link)
}
int
-virPCIDeviceAddressGetSysfsFile(virPCIDeviceAddressPtr dev,
+virPCIDeviceAddressGetSysfsFile(virPCIDeviceAddressPtr addr,
char **pci_sysfs_device_link)
{
if (virAsprintf(pci_sysfs_device_link,
- PCI_SYSFS "devices/%04x:%02x:%02x.%x", dev->domain,
- dev->bus, dev->slot, dev->function) < 0)
+ PCI_SYSFS "devices/%04x:%02x:%02x.%x",
+ addr->domain, addr->bus,
+ addr->slot, addr->function) < 0)
return -1;
return 0;
}
diff --git a/src/util/virpci.h b/src/util/virpci.h
index 6516f05..a137a9a 100644
--- a/src/util/virpci.h
+++ b/src/util/virpci.h
@@ -69,6 +69,13 @@ struct _virPCIEDeviceInfo {
virPCIELink *link_sta; /* Actually negotiated capabilities */
};
+virPCIDeviceAddressPtr virPCIDeviceAddressNew(unsigned int domain,
+ unsigned int bus,
+ unsigned int slot,
+ unsigned int function);
+virPCIDeviceAddressPtr virPCIDeviceAddressCopy(virPCIDeviceAddressPtr addr);
+void virPCIDeviceAddressFree(virPCIDeviceAddressPtr addr);
+
virPCIDevicePtr virPCIDeviceNew(unsigned int domain,
unsigned int bus,
unsigned int slot,
--
2.5.0
8 years, 11 months
[libvirt] [PATCHv3] hypervisor driver for Jailhouse
by Christian Loehle
>From 818447bdc0c7fb5048367276a5eb64108ad95e2a Mon Sep 17 00:00:00 2001
From: Christian Loehle <cloehle(a)linutronix.de>
Date: Mon, 14 Dec 2015 20:13:07 +0100
Subject: [PATCH] Add Jailhouse Driver v3
---
configure.ac | 7 +
include/libvirt/virterror.h | 1 +
m4/virt-driver-jailhouse.m4 | 35 +++
po/POTFILES.in | 1 +
src/Makefile.am | 15 ++
src/conf/domain_conf.c | 3 +-
src/conf/domain_conf.h | 1 +
src/jailhouse/README | 14 ++
src/jailhouse/jailhouse_driver.c | 511 +++++++++++++++++++++++++++++++++++++++
src/jailhouse/jailhouse_driver.h | 28 +++
src/libvirt.c | 10 +
src/util/virerror.c | 1 +
12 files changed, 626 insertions(+), 1 deletion(-)
create mode 100644 m4/virt-driver-jailhouse.m4
create mode 100644 src/jailhouse/README
create mode 100644 src/jailhouse/jailhouse_driver.c
create mode 100644 src/jailhouse/jailhouse_driver.h
diff --git a/configure.ac b/configure.ac
index 98cf210..445b2ca 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1087,6 +1087,12 @@ dnl
LIBVIRT_DRIVER_CHECK_BHYVE
dnl
+dnl Checks for Jailhouse driver
+dnl
+
+LIBVIRT_DRIVER_CHECK_JAILHOUSE
+
+dnl
dnl check for shell that understands <> redirection without truncation,
dnl needed by src/qemu/qemu_monitor_{text,json}.c.
dnl
@@ -2830,6 +2836,7 @@ AC_MSG_NOTICE([ ESX: $with_esx])
AC_MSG_NOTICE([ Hyper-V: $with_hyperv])
LIBVIRT_DRIVER_RESULT_VZ
LIBVIRT_DRIVER_RESULT_BHYVE
+LIBVIRT_DRIVER_RESULT_JAILHOUSE
AC_MSG_NOTICE([ Test: $with_test])
AC_MSG_NOTICE([ Remote: $with_remote])
AC_MSG_NOTICE([ Network: $with_network])
diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
index 0539e48..bbc7e2e 100644
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -128,6 +128,7 @@ typedef enum {
VIR_FROM_THREAD = 61, /* Error from thread utils */
VIR_FROM_ADMIN = 62, /* Error from admin backend */
VIR_FROM_LOGGING = 63, /* Error from log manager */
+ VIR_FROM_JAILHOUSE = 64, /* Error from Jailhouse driver */
# ifdef VIR_ENUM_SENTINELS
VIR_ERR_DOMAIN_LAST
diff --git a/m4/virt-driver-jailhouse.m4 b/m4/virt-driver-jailhouse.m4
new file mode 100644
index 0000000..6c72043
--- /dev/null
+++ b/m4/virt-driver-jailhouse.m4
@@ -0,0 +1,35 @@
+dnl The Jailhouse driver
+dnl
+dnl Copyright (C) 2005-2015 Red Hat, Inc.
+dnl
+dnl This library is free software; you can redistribute it and/or
+dnl modify it under the terms of the GNU Lesser General Public
+dnl License as published by the Free Software Foundation; either
+dnl version 2.1 of the License, or (at your option) any later version.
+dnl
+dnl This library is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+dnl Lesser General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU Lesser General Public
+dnl License along with this library. If not, see
+dnl <http://www.gnu.org/licenses/>.
+dnl
+
+AC_DEFUN([LIBVIRT_DRIVER_CHECK_JAILHOUSE],[
+ AC_ARG_WITH([jailhouse],
+ [AS_HELP_STRING([--with-jailhouse],
+ [add Jailhouse support @<:@default=yes@:>@])])
+ m4_divert_text([DEFAULTS], [with_jailhouse=yes])
+
+ if test "$with_jailhouse" = "yes"; then
+ AC_DEFINE_UNQUOTED([WITH_JAILHOUSE], 1, [whether jailhouse driver is enabled])
+ fi
+
+ AM_CONDITIONAL([WITH_JAILHOUSE], [test "$with_jailhouse" = "yes"])
+])
+
+AC_DEFUN([LIBVIRT_DRIVER_RESULT_JAILHOUSE],[
+ AC_MSG_NOTICE([Jailhouse: $with_jailhouse])
+])
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 82e8d3e..29259f4 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -61,6 +61,7 @@ src/hyperv/hyperv_wmi.c
src/interface/interface_backend_netcf.c
src/interface/interface_backend_udev.c
src/internal.h
+src/jailhouse/jailhouse_driver.c
src/libvirt.c
src/libvirt-admin.c
src/libvirt-domain.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 7219f7c..af46766 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -622,6 +622,7 @@ DRIVER_SOURCE_FILES = \
$(VMWARE_DRIVER_SOURCES) \
$(XEN_DRIVER_SOURCES) \
$(XENAPI_DRIVER_SOURCES) \
+ $(JAILHOUSE_DRIVER_SOURCES) \
$(NULL)
STATEFUL_DRIVER_SOURCE_FILES = \
@@ -904,6 +905,11 @@ BHYVE_DRIVER_SOURCES = \
bhyve/bhyve_utils.h \
$(NULL)
+JAILHOUSE_DRIVER_SOURCES = \
+ jailhouse/jailhouse_driver.c \
+ jailhouse/jailhouse_driver.h \
+ $(NULL)
+
NETWORK_DRIVER_SOURCES = \
network/bridge_driver.h network/bridge_driver.c \
network/bridge_driver_platform.h \
@@ -1480,6 +1486,14 @@ libvirt_driver_vz_la_LIBADD = $(PARALLELS_SDK_LIBS) $(LIBNL_LIBS)
libvirt_driver_vz_la_SOURCES = $(VZ_DRIVER_SOURCES)
endif WITH_VZ
+if WITH_JAILHOUSE
+noinst_LTLIBRARIES += libvirt_driver_jailhouse.la
+libvirt_la_BUILT_LIBADD += libvirt_driver_jailhouse.la
+libvirt_driver_jailhouse_la_CFLAGS = \
+ -I$(srcdir)/conf $(AM_CFLAGS)
+libvirt_driver_jailhouse_la_SOURCES = $(JAILHOUSE_DRIVER_SOURCES)
+endif WITH_JAILHOUSE
+
if WITH_BHYVE
noinst_LTLIBRARIES += libvirt_driver_bhyve_impl.la
libvirt_driver_bhyve_la_SOURCES =
@@ -1845,6 +1859,7 @@ EXTRA_DIST += \
$(HYPERV_DRIVER_EXTRA_DIST) \
$(VZ_DRIVER_SOURCES) \
$(BHYVE_DRIVER_SOURCES) \
+ $(JAILHOUSE_DRIVER_SOURCES) \
$(NETWORK_DRIVER_SOURCES) \
$(INTERFACE_DRIVER_SOURCES) \
$(STORAGE_DRIVER_SOURCES) \
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 5200c27..926c1a0 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -107,7 +107,8 @@ VIR_ENUM_IMPL(virDomainVirt, VIR_DOMAIN_VIRT_LAST,
"phyp",
"parallels",
"bhyve",
- "vz")
+ "vz",
+ "jailhouse")
VIR_ENUM_IMPL(virDomainOS, VIR_DOMAIN_OSTYPE_LAST,
"hvm",
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index cec681a..271811f 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -225,6 +225,7 @@ typedef enum {
VIR_DOMAIN_VIRT_PARALLELS,
VIR_DOMAIN_VIRT_BHYVE,
VIR_DOMAIN_VIRT_VZ,
+ VIR_DOMAIN_VIRT_JAILHOUSE,
VIR_DOMAIN_VIRT_LAST
} virDomainVirtType;
diff --git a/src/jailhouse/README b/src/jailhouse/README
new file mode 100644
index 0000000..02ba87d
--- /dev/null
+++ b/src/jailhouse/README
@@ -0,0 +1,14 @@
+The jailhouse hypervisor driver for the libvirt project aims to provide
+rudimentary support for managing jailhouse with the libvirt library.
+The main advantage of this is the possibility to use virt-manager as a GUI to
+manage Jailhouse cells. Thus the driver is mainly built around the API calls
+that virt-manager uses and needs.
+Due to the concept of Jailhouse a lot of libvirt functions can't be realized,
+so this driver isn't as full-featured as upstream drivers of the
+libvirt project.
+Currently the driver relies on the Jailhouse binary, which has to be in $PATH
+or passed when connecting a libvirt client to it
+(e.g. virt-manager -c jailhouse:///path/to/jailhouse/tools/jailhouse).
+Be aware though that the driver doesn't store any information about cells,
+so most API calls use "jailhouse cell list" every time they're called to get
+the current state.
diff --git a/src/jailhouse/jailhouse_driver.c b/src/jailhouse/jailhouse_driver.c
new file mode 100644
index 0000000..79e97f0
--- /dev/null
+++ b/src/jailhouse/jailhouse_driver.c
@@ -0,0 +1,511 @@
+/*
+ * virJailhouseDriver.c: hypervisor driver for managing Jailhouse cells
+ *
+ * Copyright (C) 2015 Linutronix GmbH
+ *
+ * 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/>.
+ *
+ * Author: Christian Loehle
+ */
+
+#include <config.h>
+#include <string.h>
+#include "jailhouse_driver.h"
+#include "datatypes.h"
+#include "virerror.h"
+#include "viralloc.h"
+#include "virlog.h"
+#include "vircommand.h"
+#include "virxml.h"
+#include "configmake.h"
+#include "virfile.h"
+#include "virtypedparam.h"
+#include "virstring.h"
+#include "nodeinfo.h"
+#include "capabilities.h"
+#include "domain_conf.h"
+
+#define VIR_FROM_THIS VIR_FROM_JAILHOUSE
+
+#define IDLENGTH 8
+#define NAMELENGTH 24
+#define STATELENGTH 16
+#define CPULENGTH 24
+#define STATERUNNING 0
+#define STATERUNNINGSTRING "running "
+#define STATERUNNINGLOCKED 1
+#define STATERUNNINGLOCKEDSTRING "running/locked "
+#define STATESHUTDOWN 2
+#define STATESHUTDOWNSTRING "shut down "
+#define STATEFAILED 3
+#define STATEFAILEDSTRING "failed "
+#define JAILHOUSEBINARY "jailhouse"
+
+struct virJailhouseCell {
+ int id;
+ char name[NAMELENGTH+1];
+ int state;
+ virBitmapPtr assignedCPUs;
+ virBitmapPtr failedCPUs; /* currently unused */
+ unsigned char uuid[VIR_UUID_BUFLEN];
+};
+typedef struct virJailhouseCell virJailhouseCell;
+typedef virJailhouseCell *virJailhouseCellPtr;
+
+/*
+ * Because virCommandRunRegex Callback gets called every line
+ */
+struct virJailhouseCellCallbackData {
+ size_t ncells;
+ virJailhouseCellPtr cells;
+};
+typedef struct virJailhouseCellCallbackData virJailhouseCellCallbackData;
+typedef virJailhouseCellCallbackData *virJailhouseCellCallbackDataPtr;
+
+/*
+ * The driver requeries the cells on most calls, it stores the result of the
+ * last query, so it can copy the UUIDs in the new query if the cell is the
+ * same(otherwise it just generates a new one).
+ * not preserving the UUID results in a lot of bugs in libvirts clients.
+ */
+struct virJailhouseDriver {
+ size_t lastQueryCellsCount;
+ virJailhouseCellPtr lastQueryCells;
+};
+typedef struct virJailhouseDriver virJailhouseDriver;
+typedef virJailhouseDriver *virJailhouseDriverPtr;
+
+static int virJailhouseParseListOutputCallback(char **const groups, void *data)
+{
+ virJailhouseCellCallbackDataPtr celldata = (virJailhouseCellCallbackDataPtr) data;
+ virJailhouseCellPtr cells = celldata->cells;
+ size_t count = celldata->ncells;
+ char* endptr = groups[0] + strlen(groups[0]) - 1;
+ char* state = groups[2];
+ if (VIR_EXPAND_N(cells, count, 1))
+ return -1;
+ celldata->ncells++;
+
+ if (virStrToLong_i(groups[0], &endptr, 0, &cells[count-1].id))
+ return -1;
+ if (!virStrcpy(cells[count-1].name, groups[1], NAMELENGTH+1))
+ return -1;
+ if (STREQLEN(state, STATERUNNINGSTRING, STATELENGTH))
+ cells[count-1].state = STATERUNNING;
+ else if (STREQLEN(state, STATESHUTDOWNSTRING, STATELENGTH))
+ cells[count-1].state = STATESHUTDOWN;
+ else if (STREQLEN(state, STATERUNNINGLOCKEDSTRING, STATELENGTH))
+ cells[count-1].state = STATERUNNINGLOCKED;
+ else
+ cells[count-1].state = STATEFAILED;
+ virBitmapParse(groups[3], 0, &cells[count-1].assignedCPUs, VIR_DOMAIN_CPUMASK_LEN);
+ virBitmapParse(groups[4], 0, &cells[count-1].failedCPUs, VIR_DOMAIN_CPUMASK_LEN);
+ celldata->cells = cells;
+ return 0;
+}
+
+/*
+ * calls "jailhouse cell list" and parses the output in an array of virJailhouseCell
+ * example output:
+ * ID Name State Assigned CPUs Failed CPUs
+ * 0 QEMU-VM running 0-3
+ */
+static ssize_t
+virJailhouseParseListOutput(virJailhouseCellPtr *parsedCells)
+{
+ int nvars[] = { 5 };
+ virJailhouseCellCallbackData callbackData;
+ const char *regex[] = { "([0-9]{1,8})\\s*([-0-9a-zA-Z]{1,24})\\s*([a-z/ ]{1,16})\\s*([0-9,-]{1,24})?\\s*([0-9,-]{1,24})?\\s*" };
+ virCommandPtr cmd = virCommandNew(JAILHOUSEBINARY);
+ virCommandAddArg(cmd, "cell");
+ virCommandAddArg(cmd, "list");
+ virCommandAddEnvPassCommon(cmd);
+ callbackData.cells = NULL;
+ callbackData.ncells = 0;
+ if (virCommandRunRegex(cmd, 1, regex, nvars, &virJailhouseParseListOutputCallback, &callbackData, NULL) < 0) {
+ virCommandFree(cmd);
+ return -1;
+ }
+ virCommandFree(cmd);
+ *parsedCells = callbackData.cells;
+ return callbackData.ncells;
+}
+
+/*
+ * Returns the libvirts equivalent of the cell state passed to it
+ */
+static virDomainState
+virJailhouseCellToState(virJailhouseCellPtr cell)
+{
+ switch (cell->state) {
+ case STATERUNNING: return VIR_DOMAIN_RUNNING;
+ case STATERUNNINGLOCKED: return VIR_DOMAIN_RUNNING;
+ case STATESHUTDOWN: return VIR_DOMAIN_SHUTOFF;
+ case STATEFAILED: return VIR_DOMAIN_CRASHED;
+ default: return VIR_DOMAIN_NOSTATE;
+ }
+}
+
+/*
+ * Returns a new virDomainPtr filled with the data of the virJailhouseCell
+ */
+static virDomainPtr
+virJailhouseCellToDomainPtr(virConnectPtr conn, virJailhouseCellPtr cell)
+{
+ virDomainPtr dom = virGetDomain(conn, cell->name, cell->uuid);
+ dom->id = cell->id;
+ return dom;
+}
+
+/*
+ * Check cells for cell and copies UUID if found, otherwise generates a new one, this is to preserve UUID in libvirt
+ */
+static void virJailhouseSetUUID(virJailhouseCellPtr cells, size_t count, virJailhouseCellPtr cell)
+{
+ size_t i;
+ for (i = 0; i < count; i++) {
+ if (strncmp(cells[i].name, cell->name, NAMELENGTH+1))
+ continue;
+ memcpy(cell->uuid, cells[i].uuid, VIR_UUID_BUFLEN);
+ return;
+ }
+ virUUIDGenerate(cell->uuid);
+}
+
+/*
+ * Frees the old list of cells, gets the new one and preserves UUID if cells were present in the old
+ */
+static int
+virJailhouseGetCurrentCellList(virConnectPtr conn)
+{
+ virJailhouseDriverPtr driver = (virJailhouseDriverPtr)conn->privateData;
+ ssize_t count;
+ size_t i;
+ size_t lastCount = driver->lastQueryCellsCount;
+ virJailhouseCellPtr lastCells = driver->lastQueryCells;
+ virJailhouseCellPtr cells = NULL;
+
+ count = virJailhouseParseListOutput(&cells);
+ for (i = 0; i < count; i++)
+ virJailhouseSetUUID(lastCells, lastCount, cells+i);
+ for (i = 0; i < lastCount; i++) {
+ virBitmapFree(lastCells[i].assignedCPUs);
+ virBitmapFree(lastCells[i].failedCPUs);
+ }
+ VIR_FREE(lastCells);
+ driver->lastQueryCells = cells;
+ driver->lastQueryCellsCount = count;
+ return count;
+}
+
+/*
+ * Converts libvirts virDomainPtr to the internal virJailhouseCell by parsing the "jailhouse cell list" output
+ * and looking up the name of the virDomainPtr, returns NULL if cell is no longer present
+ */
+static virJailhouseCellPtr
+virDomainPtrToCell(virDomainPtr dom)
+{
+ virJailhouseDriverPtr driver = dom->conn->privateData;
+ size_t cellsCount;
+ size_t i;
+ if (virJailhouseGetCurrentCellList(dom->conn) == -1)
+ return NULL;
+ cellsCount = driver->lastQueryCellsCount;
+ virJailhouseCellPtr cells = driver->lastQueryCells;
+ for (i = 0; i < cellsCount; i++)
+ if (dom->id == cells[i].id)
+ return cells+i;
+ return NULL;
+}
+
+static virDrvOpenStatus
+jailhouseConnectOpen(virConnectPtr conn, virConnectAuthPtr auth ATTRIBUTE_UNUSED, unsigned int flags)
+{
+ virCheckFlags(0, VIR_DRV_OPEN_ERROR);
+ virJailhouseDriverPtr driver;
+ if (conn->uri->scheme == NULL ||
+ STRNEQ(conn->uri->scheme, "jailhouse"))
+ return VIR_DRV_OPEN_DECLINED;
+ if (conn->uri->path != NULL && STRNEQ(conn->uri->path, "/")) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unexpected Jailhouse URI path '%s', try jailhouse:///"),
+ conn->uri->path);
+ return VIR_DRV_OPEN_ERROR;
+ }
+ if (VIR_ALLOC(driver) < 0)
+ return VIR_DRV_OPEN_ERROR;
+ driver->lastQueryCells = NULL;
+ driver->lastQueryCellsCount = 0;
+ conn->privateData = driver;
+ return VIR_DRV_OPEN_SUCCESS;
+}
+
+static int
+jailhouseConnectClose(virConnectPtr conn)
+{
+
+ virJailhouseDriverPtr driver = (virJailhouseDriverPtr)conn->privateData;
+ size_t i;
+ size_t cellsCount = driver->lastQueryCellsCount;
+ virJailhouseCellPtr cells = driver->lastQueryCells;
+ for (i = 0; i < cellsCount; i++) {
+ virBitmapFree(cells[i].assignedCPUs);
+ virBitmapFree(cells[i].failedCPUs);
+ }
+ VIR_FREE(cells);
+ VIR_FREE(driver);
+ conn->privateData = NULL;
+ return 0;
+}
+
+static int
+jailhouseConnectNumOfDomains(virConnectPtr conn)
+{
+ if (virJailhouseGetCurrentCellList(conn) == -1)
+ return -1;
+ return ((virJailhouseDriverPtr)conn->privateData)->lastQueryCellsCount;
+}
+
+static int
+jailhouseConnectListDomains(virConnectPtr conn, int * ids, int maxids)
+{
+ virJailhouseDriverPtr driver = (virJailhouseDriverPtr)conn->privateData;
+ virJailhouseCellPtr cells;
+ size_t cellsCount;
+ size_t i;
+ if (virJailhouseGetCurrentCellList(conn) == -1)
+ return -1;
+ cellsCount = driver->lastQueryCellsCount;
+ cells = driver->lastQueryCells;
+ for (i = 0; i < maxids && i < cellsCount; i++)
+ ids[i] = cells[i].id;
+ return i;
+}
+
+static int
+jailhouseConnectListAllDomains(virConnectPtr conn, virDomainPtr ** domains, unsigned int flags)
+{
+ virCheckFlags(VIR_CONNECT_LIST_DOMAINS_ACTIVE, 0);
+ virJailhouseDriverPtr driver = (virJailhouseDriverPtr)conn->privateData;
+ virJailhouseCellPtr cells;
+ size_t cellsCount;
+ size_t i;
+ if (virJailhouseGetCurrentCellList(conn) == -1)
+ goto error;
+
+ cellsCount = driver->lastQueryCellsCount;
+ cells = driver->lastQueryCells;
+ if (cellsCount == -1)
+ goto error;
+ if (VIR_ALLOC_N(*domains, cellsCount+1) < 0)
+ goto error;
+ for (i = 0; i < cellsCount; i++)
+ (*domains)[i] = virJailhouseCellToDomainPtr(conn, cells+i);
+ (*domains)[cellsCount] = NULL;
+ return cellsCount;
+ error:
+ *domains = NULL;
+ return -1;
+}
+
+static virDomainPtr
+jailhouseDomainLookupByID(virConnectPtr conn, int id)
+{
+ virJailhouseDriverPtr driver = (virJailhouseDriverPtr)conn->privateData;
+ size_t cellsCount;
+ size_t i;
+ if (virJailhouseGetCurrentCellList(conn) == -1)
+ return NULL;
+
+ cellsCount = driver->lastQueryCellsCount;
+ if (cellsCount == -1)
+ return NULL;
+ virJailhouseCellPtr cells = driver->lastQueryCells;
+ for (i = 0; i < cellsCount; i++)
+ if (cells[i].id == id)
+ return virJailhouseCellToDomainPtr(conn, cells+i);
+ virReportError(VIR_ERR_NO_DOMAIN, NULL);
+ return NULL;
+}
+
+static virDomainPtr
+jailhouseDomainLookupByName(virConnectPtr conn, const char *lookupName)
+{
+ virJailhouseDriverPtr driver = (virJailhouseDriverPtr)conn->privateData;
+ size_t cellsCount;
+ size_t i;
+ if (virJailhouseGetCurrentCellList(conn) == -1)
+ return NULL;
+
+ cellsCount = driver->lastQueryCellsCount;
+ if (cellsCount == -1)
+ return NULL;
+ virJailhouseCellPtr cells = driver->lastQueryCells;
+ for (i = 0; i < cellsCount; i++)
+ if (STREQ(cells[i].name, lookupName))
+ return virJailhouseCellToDomainPtr(conn, cells+i);
+ virReportError(VIR_ERR_NO_DOMAIN, NULL);
+ return NULL;
+}
+
+static virDomainPtr
+jailhouseDomainLookupByUUID(virConnectPtr conn, const unsigned char * uuid)
+{
+ virJailhouseDriverPtr driver = (virJailhouseDriverPtr)conn->privateData;
+ size_t cellsCount;
+ size_t i;
+ if (virJailhouseGetCurrentCellList(conn) == -1)
+ return NULL;
+ cellsCount = driver->lastQueryCellsCount;
+ if (cellsCount == -1)
+ return NULL;
+ virJailhouseCellPtr cells = driver->lastQueryCells;
+ for (i = 0; i < cellsCount; i++)
+ if (memcmp(cells[i].uuid, (const char*)uuid, VIR_UUID_BUFLEN) == 0)
+ return virJailhouseCellToDomainPtr(conn, cells+i);
+ virReportError(VIR_ERR_NO_DOMAIN, NULL);
+ return NULL;
+}
+
+/*
+ * There currently is no straightforward way for the driver to retrieve those,
+ * so maxMem, memory and cpuTime have dummy values
+ */
+static int
+jailhouseDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
+{
+ virJailhouseCellPtr cell = virDomainPtrToCell(domain);
+ if (cell == NULL)
+ return -1;
+ info->state = virJailhouseCellToState(cell);
+ info->maxMem = 0;
+ info->memory = 0;
+ info->nrVirtCpu = virBitmapCountBits(cell->assignedCPUs);
+ info->cpuTime = 0;
+ return 0;
+}
+
+static int
+jailhouseDomainGetState(virDomainPtr domain, int *state,
+ int *reason ATTRIBUTE_UNUSED, unsigned int flags)
+{
+ virCheckFlags(0, 0);
+ virJailhouseCellPtr cell = virDomainPtrToCell(domain);
+ if (cell == NULL)
+ return -1;
+ *state = virJailhouseCellToState(cell);
+ return 0;
+}
+
+static int
+jailhouseDomainDestroy(virDomainPtr domain)
+{
+ int resultcode;
+ virCommandPtr cmd = virCommandNew(JAILHOUSEBINARY);
+ virCommandAddArg(cmd, "cell");
+ virCommandAddArg(cmd, "shutdown");
+ virCommandAddArgFormat(cmd, "%d", domain->id);
+ virCommandAddEnvPassCommon(cmd);
+ resultcode = virCommandRun(cmd, NULL);
+ virCommandFree(cmd);
+ if (resultcode < 0)
+ return -1;
+ return 0;
+}
+
+static int
+jailhouseDomainCreate(virDomainPtr domain)
+{
+ int resultcode;
+ virCommandPtr cmd = virCommandNew(JAILHOUSEBINARY);
+ virCommandAddArg(cmd, "cell");
+ virCommandAddArg(cmd, "start");
+ virCommandAddArgFormat(cmd, "%d", domain->id);
+ virCommandAddEnvPassCommon(cmd);
+ resultcode = virCommandRun(cmd, NULL);
+ virCommandFree(cmd);
+ if (resultcode < 0)
+ return -1;
+ return 0;
+}
+
+/*
+ * There currently is no reason why it shouldn't be
+ */
+static int
+jailhouseConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+ return 1;
+}
+
+static int
+jailhouseNodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED, virNodeInfoPtr info)
+{
+ return nodeGetInfo(NULL, info);
+}
+
+/*
+ * Returns a dummy capabilities XML for virt-manager
+ */
+static char *
+jailhouseConnectGetCapabilities(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+ virCapsPtr caps = virCapabilitiesNew(VIR_ARCH_NONE, false, false);
+ char* xml = virCapabilitiesFormatXML(caps);
+ virObjectUnref(caps);
+ return xml;
+}
+
+static char *
+jailhouseDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
+{
+ virCheckFlags(0, NULL);
+ char* xml;
+ virDomainDefPtr domainDef = virDomainDefNewFull(domain->name, domain->uuid, domain->id);
+ xml = virDomainDefFormat(domainDef, 0);
+ virDomainDefFree(domainDef);
+ return xml;
+}
+
+static virHypervisorDriver jailhouseHypervisorDriver = {
+ .name = "jailhouse",
+ .connectOpen = jailhouseConnectOpen, /* 1.3.1 */
+ .connectClose = jailhouseConnectClose, /* 1.3.1 */
+ .connectGetCapabilities = jailhouseConnectGetCapabilities, /* 1.3.1 */
+ .connectNumOfDomains = jailhouseConnectNumOfDomains, /* 1.3.1 */
+ .connectListDomains = jailhouseConnectListDomains, /* 1.3.1 */
+ .connectIsAlive = jailhouseConnectIsAlive, /* 1.3.1 */
+ .connectListAllDomains = jailhouseConnectListAllDomains, /* 1.3.1 */
+ .domainLookupByID = jailhouseDomainLookupByID, /* 1.3.1 */
+ .domainLookupByName = jailhouseDomainLookupByName, /* 1.3.1 */
+ .domainLookupByUUID = jailhouseDomainLookupByUUID, /* 1.3.1 */
+ .domainGetInfo = jailhouseDomainGetInfo, /* 1.3.1 */
+ .domainGetState = jailhouseDomainGetState, /* 1.3.1 */
+ .domainGetXMLDesc = jailhouseDomainGetXMLDesc, /* 1.3.1 */
+ .domainDestroy = jailhouseDomainDestroy, /* 1.3.1 */
+ .domainCreate = jailhouseDomainCreate, /* 1.3.1 */
+ .nodeGetInfo = jailhouseNodeGetInfo /* 1.3.1 */
+};
+
+static virConnectDriver jailhouseConnectDriver = {
+ .hypervisorDriver = &jailhouseHypervisorDriver,
+};
+
+int
+jailhouseRegister(void)
+{
+ return virRegisterConnectDriver(&jailhouseConnectDriver,
+ false);
+}
diff --git a/src/jailhouse/jailhouse_driver.h b/src/jailhouse/jailhouse_driver.h
new file mode 100644
index 0000000..47c17e7
--- /dev/null
+++ b/src/jailhouse/jailhouse_driver.h
@@ -0,0 +1,28 @@
+/*
+ * jailhouse_driver.h: hypervisor driver for managing Jailhouse cells
+ *
+ * Copyright (C) 2015 Linutronix GmbH
+ *
+ * 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/>.
+ *
+ * Author: Christian Loehle
+ */
+
+#ifndef JAILHOUSE_DRIVER_H
+# define JAILHOUSE_DRIVER_H
+
+int jailhouseRegister(void);
+
+#endif
diff --git a/src/libvirt.c b/src/libvirt.c
index dd58e9c..36d5994 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -98,6 +98,9 @@
#ifdef WITH_BHYVE
# include "bhyve/bhyve_driver.h"
#endif
+#ifdef WITH_JAILHOUSE
+# include "jailhouse/jailhouse_driver.h"
+#endif
#define VIR_FROM_THIS VIR_FROM_NONE
@@ -437,6 +440,10 @@ virGlobalInit(void)
if (vzRegister() == -1)
goto error;
# endif
+#ifdef WITH_JAILHOUSE
+ if (jailhouseRegister() == -1)
+ goto error;
+#endif
#endif
#ifdef WITH_REMOTE
if (remoteRegister() == -1)
@@ -1038,6 +1045,9 @@ do_open(const char *name,
#ifndef WITH_VZ
STRCASEEQ(ret->uri->scheme, "parallels") ||
#endif
+#ifndef WITH_JAILHOUSE
+ STRCASEEQ(ret->uri->scheme, "jailhouse") ||
+#endif
false)) {
virReportErrorHelper(VIR_FROM_NONE, VIR_ERR_CONFIG_UNSUPPORTED,
__FILE__, __FUNCTION__, __LINE__,
diff --git a/src/util/virerror.c b/src/util/virerror.c
index 098211a..06741bf 100644
--- a/src/util/virerror.c
+++ b/src/util/virerror.c
@@ -135,6 +135,7 @@ VIR_ENUM_IMPL(virErrorDomain, VIR_ERR_DOMAIN_LAST,
"Thread jobs",
"Admin Interface",
"Log Manager",
+ "Jailhouse Driver",
)
--
2.1.4
8 years, 11 months
[libvirt] [PATCH 0/2] Add support for zero-write detection
by Martin Kletzander
QEMU supports detect-zeroes option since version 2.1, but we never
added support for it in libvirt. If was requested by Vasiliy Tolstov
in the list, so I just added it.
There are two discussions to be had, optionally. One is to decide
whether we should disable detect_zeros='unmap' if discard is not set
to 'unmap', but this is getting very hypervisor-specific, so I just
documented the behaviour. The other one is the naming. I described
why I made the decision for "zeros" instead of "zeroes" the decision
in the patch, but I have no problem changing it to what others like
better.
Martin Kletzander (2):
conf: Add support of zero-detection for disks
qemu: Add support for zero-detection writes
docs/formatdomain.html.in | 10 ++++++
docs/schemas/domaincommon.rng | 12 +++++++
src/conf/domain_conf.c | 23 +++++++++++++-
src/conf/domain_conf.h | 11 +++++++
src/libvirt_private.syms | 2 ++
src/qemu/qemu_capabilities.c | 2 ++
src/qemu/qemu_capabilities.h | 1 +
src/qemu/qemu_command.c | 11 +++++++
tests/qemucapabilitiesdata/caps_2.1.1-1.caps | 1 +
tests/qemucapabilitiesdata/caps_2.4.0-1.caps | 1 +
tests/qemucapabilitiesdata/caps_2.5.0-1.caps | 1 +
.../qemuxml2argv-disk-drive-detect-zeros.args | 27 ++++++++++++++++
.../qemuxml2argv-disk-drive-detect-zeros.xml | 37 ++++++++++++++++++++++
tests/qemuxml2argvtest.c | 4 +++
tests/qemuxml2xmltest.c | 1 +
15 files changed, 143 insertions(+), 1 deletion(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-drive-detect-zeros.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-drive-detect-zeros.xml
--
2.6.4
8 years, 11 months
[libvirt] [PATCH] virNetDevMacVLanTapSetup: Drop @multiqueue argument
by Michal Privoznik
Firstly, there's a bug (or typo) in the only place where we call
this function: @multiqueue is set whenever @tapfdSize is greater
than zero, while in fact the condition should have been 'greater
than one'.
Then, secondly, since the condition depends on just one
variable, that we are even passing down to the function, we can
move the condition into the function and drop useless argument.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
src/util/virnetdevmacvlan.c | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/src/util/virnetdevmacvlan.c b/src/util/virnetdevmacvlan.c
index 8fc71af..496416e 100644
--- a/src/util/virnetdevmacvlan.c
+++ b/src/util/virnetdevmacvlan.c
@@ -289,12 +289,11 @@ virNetDevMacVLanTapOpen(const char *ifname,
* @tapfd: array of file descriptors of the macvtap tap
* @tapfdSize: number of file descriptors in @tapfd
* @vnet_hdr: whether to enable or disable IFF_VNET_HDR
- * @multiqueue: whether to enable or disable IFF_MULTI_QUEUE
*
- * Turn on the IFF_VNET_HDR flag if requested and available, but make sure it's
- * off otherwise. Similarly, turn on IFF_MULTI_QUEUE if requested, but if it
- * can't be set, consider it a fatal error (rather than ignoring as with
- * @vnet_hdr).
+ * Turn on the IFF_VNET_HDR flag if requested and available, but make sure
+ * it's off otherwise. Similarly, turn on IFF_MULTI_QUEUE if @tapfdSize is
+ * greater than one, but if it can't be set, consider it a fatal error
+ * (rather than ignoring as with @vnet_hdr).
*
* A fatal error is defined as the VNET_HDR flag being set but it cannot
* be turned off for some reason. This is reported with -1. Other fatal
@@ -304,7 +303,7 @@ virNetDevMacVLanTapOpen(const char *ifname,
* Returns 0 on success, -1 in case of fatal error.
*/
static int
-virNetDevMacVLanTapSetup(int *tapfd, size_t tapfdSize, bool vnet_hdr, bool multiqueue)
+virNetDevMacVLanTapSetup(int *tapfd, size_t tapfdSize, bool vnet_hdr)
{
unsigned int features;
struct ifreq ifreq;
@@ -335,12 +334,12 @@ virNetDevMacVLanTapSetup(int *tapfd, size_t tapfdSize, bool vnet_hdr, bool multi
}
# ifdef IFF_MULTI_QUEUE
- if (multiqueue)
+ if (tapfdSize > 1)
new_flags |= IFF_MULTI_QUEUE;
else
new_flags &= ~IFF_MULTI_QUEUE;
# else
- if (multiqueue) {
+ if (tapfdSize > 1) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Multiqueue devices are not supported on this system"));
return -1;
@@ -870,7 +869,7 @@ int virNetDevMacVLanCreateWithVPortProfile(const char *tgifname,
if (virNetDevMacVLanTapOpen(cr_ifname, tapfd, tapfdSize, 10) < 0)
goto disassociate_exit;
- if (virNetDevMacVLanTapSetup(tapfd, tapfdSize, vnet_hdr, tapfdSize > 0) < 0) {
+ if (virNetDevMacVLanTapSetup(tapfd, tapfdSize, vnet_hdr) < 0) {
VIR_FORCE_CLOSE(rc); /* sets rc to -1 */
goto disassociate_exit;
}
--
2.4.10
8 years, 11 months