[libvirt] Libvirt synchronous hooks
by Radek Hladik
I am trying Libvirt synchronous hooks and I would like to ask a
question. I would like to use the machine start (qemu+kvm) hook to set
up the storage for the machine. I already mentioned my setup in this
mailing list but for now it is only important that VM storage is a md
raid constructed from iSCSI disks. The VM's config is using simple file
device:
<disk type='file' device='disk'>
<driver name='qemu' type=''/>
<source
file='/dev/disk/by-id/md-uuid-e464a51e:f61e98b4:bfe78010:bc810f04'/>
<target dev='vda' bus='virtio'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x05'
function='0x0'/>
</disk>
Stopping the array from stop hook works perfectly however it seems that
on the startup the storage is checked before the hook is executed. At
least I do get errors that the storage file
(/dev/disk/by-id/md-uuid-....) does not exist and my hook is not called.
I would say that I am hooking on wrong places that I should hook on
storage startup/shutdown but as far as I know there are no hooks for
storage drivers. Are there any plans in this area? Or is there any other
way how to do it that I do not see?
Radek
14 years, 3 months
[libvirt] [PATCH v4 0/8]: Add arbitrary qemu command-line and monitor commands
by Chris Lalancette
As we discussed previously, here is the patch series to add the ability
to specify arbitrary qemu command-line parameters and environment variables,
and also give arbitrary monitor commands to a guest. Because these
extra arguments have a good shot at confusing libvirt, the use of them
is not supported, but left available for advanced users and developers.
They are also in a separate library and have a separate on-the-wire
protocol.
There is one bug left that I have not yet been able to fix. Because of the
complicated way that virsh parses command-line arguments, it is not possible
to pass through spaces and quotes when using the qemu-monitor-command.
Unfortunately, the qemu monitor commands (and in particular when using QMP)
depend heavily on quoting and spacing, so using virsh to send through
command-lines is difficult. I'll have to think about how to better resolve
this issue, but it should not hold up the rest of the series.
I will point out one particular patch that could use some careful review,
namely PATCH 6/8. In there, I change the remote_message_hdr to use an
int proc instead of a enum remote_procedure proc. Now, as far as I can tell
the two sizes should be the same, so the wire protocol should be the same.
Indeed, testing seems to show that older virsh can talk just fine to a libvirtd
with these patches applied. However, the regenerated remote_protocol.c file for
parsing remote_message_header has some strange bits in it that I don't quite
understand. I'm hoping someone else can look at it and confirm that it is OK.
Thanks to Dan Berrange and Eric Blake for their reviews already, and to DV
for the Relax NG schema changes.
Changes since v3 are listed in the individual patches.
14 years, 3 months
[libvirt] [PATCH] Fix a memory leak in the qemudBuildCommandLine.
by Chris Lalancette
ADD_ARG_LIT should only be used for literal arguments,
since it duplicates the memory. Since virBufferContentAndReset
is already allocating memory, we should only use ADD_ARG.
Signed-off-by: Chris Lalancette <clalance(a)redhat.com>
---
src/qemu/qemu_conf.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 172986e..d0655fd 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -4110,7 +4110,7 @@ int qemudBuildCommandLine(virConnectPtr conn,
goto error;
}
- ADD_ARG_LIT(virBufferContentAndReset(&boot_buf));
+ ADD_ARG(virBufferContentAndReset(&boot_buf));
}
if (def->os.kernel) {
--
1.7.1.1
14 years, 3 months
[libvirt] [PATCH] qemu: Fix PCI address allocation
by Jiri Denemark
When attaching a PCI device which doesn't explicitly set its PCI
address, libvirt allocates the address automatically. The problem is
that when checking which PCI address is unused, we only check for those
with slot number higher than the highest slot number ever used.
Thus attaching/detaching such device several times in a row (31 is the
theoretical limit, less then 30 tries are enough in practise) makes any
further device attachment fail. Furthermore, attaching a device with
predefined PCI address to 0:0:31 immediately forbids attachment of any
PCI device without explicit address.
This patch changes the logic so that we always check all PCI addresses
before we say there is no PCI address available.
---
src/qemu/qemu_conf.c | 14 ++++----------
1 files changed, 4 insertions(+), 10 deletions(-)
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 57bc02f..eaebcc1 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -2055,8 +2055,6 @@ qemuAssignDeviceAliases(virDomainDefPtr def, unsigned long long qemuCmdFlags)
#define QEMU_PCI_ADDRESS_LAST_SLOT 31
struct _qemuDomainPCIAddressSet {
virHashTablePtr used;
- int nextslot;
- /* XXX add domain, bus later when QEMU allows > 1 */
};
@@ -2148,9 +2146,6 @@ int qemuDomainPCIAddressReserveAddr(qemuDomainPCIAddressSetPtr addrs,
return -1;
}
- if (dev->addr.pci.slot > addrs->nextslot)
- addrs->nextslot = dev->addr.pci.slot + 1;
-
return 0;
}
@@ -2217,7 +2212,7 @@ int qemuDomainPCIAddressSetNextAddr(qemuDomainPCIAddressSetPtr addrs,
{
int i;
- for (i = addrs->nextslot ; i <= QEMU_PCI_ADDRESS_LAST_SLOT ; i++) {
+ for (i = 0 ; i <= QEMU_PCI_ADDRESS_LAST_SLOT ; i++) {
virDomainDeviceInfo maybe;
char *addr;
@@ -2228,13 +2223,14 @@ int qemuDomainPCIAddressSetNextAddr(qemuDomainPCIAddressSetPtr addrs,
addr = qemuPCIAddressAsString(&maybe);
- VIR_DEBUG("Allocating PCI addr %s", addr);
-
if (virHashLookup(addrs->used, addr)) {
+ VIR_DEBUG("PCI addr %s already in use", addr);
VIR_FREE(addr);
continue;
}
+ VIR_DEBUG("Allocating PCI addr %s", addr);
+
if (virHashAddEntry(addrs->used, addr, addr) < 0) {
VIR_FREE(addr);
return -1;
@@ -2245,8 +2241,6 @@ int qemuDomainPCIAddressSetNextAddr(qemuDomainPCIAddressSetPtr addrs,
dev->addr.pci.bus = 0;
dev->addr.pci.slot = i;
- addrs->nextslot = i + 1;
-
return 0;
}
--
1.7.2
14 years, 3 months
[libvirt] [PATCH] OpenVZ: implement suspend/resume driver APIs
by Jean-Baptiste Rouault
---
src/openvz/openvz_driver.c | 84 ++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 82 insertions(+), 2 deletions(-)
diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c
index e5bbdd0..bdc0e92 100644
--- a/src/openvz/openvz_driver.c
+++ b/src/openvz/openvz_driver.c
@@ -503,6 +503,86 @@ static void openvzSetProgramSentinal(const char **prog, const char *key)
}
}
+static int openvzDomainSuspend(virDomainPtr dom) {
+ struct openvz_driver *driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ const char *prog[] = {VZCTL, "--quiet", "chkpnt", PROGRAM_SENTINAL, "--suspend", NULL};
+ int ret = -1;
+
+ openvzDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ openvzDriverUnlock(driver);
+
+ if (!vm) {
+ openvzError(VIR_ERR_INVALID_DOMAIN, "%s",
+ _("no domain with matching uuid"));
+ goto cleanup;
+ }
+
+ if (!virDomainObjIsActive(vm)) {
+ openvzError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("Domain is not running"));
+ goto cleanup;
+ }
+
+ if (vm->state != VIR_DOMAIN_PAUSED) {
+ openvzSetProgramSentinal(prog, vm->def->name);
+ if (virRun(prog, NULL) < 0) {
+ openvzError(VIR_ERR_OPERATION_FAILED, "%s",
+ _("Suspend operation failed"));
+ goto cleanup;
+ }
+ vm->state = VIR_DOMAIN_PAUSED;
+ }
+
+ ret = 0;
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return ret;
+}
+
+static int openvzDomainResume(virDomainPtr dom) {
+ struct openvz_driver *driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ const char *prog[] = {VZCTL, "--quiet", "chkpnt", PROGRAM_SENTINAL, "--resume", NULL};
+ int ret = -1;
+
+ openvzDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ openvzDriverUnlock(driver);
+
+ if (!vm) {
+ openvzError(VIR_ERR_INVALID_DOMAIN, "%s",
+ _("no domain with matching uuid"));
+ goto cleanup;
+ }
+
+ if (!virDomainObjIsActive(vm)) {
+ openvzError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("Domain is not running"));
+ goto cleanup;
+ }
+
+ if (vm->state == VIR_DOMAIN_PAUSED) {
+ openvzSetProgramSentinal(prog, vm->def->name);
+ if (virRun(prog, NULL) < 0) {
+ openvzError(VIR_ERR_OPERATION_FAILED, "%s",
+ _("Resume operation failed"));
+ goto cleanup;
+ }
+ vm->state = VIR_DOMAIN_RUNNING;
+ }
+
+ ret = 0;
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return ret;
+}
+
static int openvzDomainShutdown(virDomainPtr dom) {
struct openvz_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
@@ -1491,8 +1571,8 @@ static virDriver openvzDriver = {
openvzDomainLookupByID, /* domainLookupByID */
openvzDomainLookupByUUID, /* domainLookupByUUID */
openvzDomainLookupByName, /* domainLookupByName */
- NULL, /* domainSuspend */
- NULL, /* domainResume */
+ openvzDomainSuspend, /* domainSuspend */
+ openvzDomainResume, /* domainResume */
openvzDomainShutdown, /* domainShutdown */
openvzDomainReboot, /* domainReboot */
openvzDomainShutdown, /* domainDestroy */
--
1.7.0.4
14 years, 3 months
[libvirt] [PATCH] [RFC] ISCSI transport protocol support in libvirt
by Aurelien ROUGEMONT
Hi everyone,
This my first post on this list
Context : Some days ago I have decided to use infiniband for ISCSI
streams. Infiniband adds a new wonderful transport protocol : ISER. This
protocols is added to the well known the default TCP. (NB: ISER = ISCSI
+ RDMA). I could not see any ISCSI transport protocol modification
support in libivirt (the default protocol tcp is even hardcoded in the
regex)
What i have done :
- did the shell testing for the iscsiadm
- the attached patch that corrects 2 typos in the original code and
switches completely the iscsi transport protocol from tcp to iser (which
is not ideal at all)
What should be done (imho):
- add iscsi transport protocol support (using my patch as a basis)
- add a new XML property/whatever_fits_the_projects_policy to the
storagepool object that allows user to pick the iscsi transport protocol
(default is tcp)
I was thinking of having something like :
<pool type="iscsi">
<name>volumename</name>
<source>
<host name="1.2.3.4"/>
<device path="IQNOFTARGET"/>
<transport protocol="iser"/>
</source>
<target>
<path>/dev/disk/by-path</path>
</target>
</pool>
Any comment on this ? Any help on the XML part ?
Best regards,
Aurélien
NB: the current iscsi transport protocols available are : tcp(default),
iser, qla4xxx, bnx2, and icxgb3i.
PS: i'm still doing extensive testing of my patch
!DSPAM:4c46f49d90977882820711!
14 years, 3 months
[libvirt] [PATCH] Add iptables rule to fixup DHCP response checksum.
by Laine Stump
From: Laine Stump <laine(a)redhat.com>
(I don't know whether or not we want to commit this upstream yet - the
proposed iptables and kernel module backend for the changes have been
posted but not yet committed upstream. On the other hand, the new
libvirt code ends up simply printing a warning message if the
necessary iptables support isn't yet in place.)
This patch attempts to take advantage of a newly added netfilter
module to correct for a problem with some guest DHCP client
implementations when used in conjunction with a DHCP server run on the
host systems with packet checksum offloading enabled.
The problem is that, when the guest uses a RAW socket to read the DHCP
response packets, the checksum hasn't yet been fixed by the IP stack,
so it is incorrect.
The fix implemented here is to add a rule to the POSTROUTING chain of
the mangle table in iptables that fixes up the checksum for packets on
the virtual network's bridge that are destined for the bootpc port (ie
"dhcpc", ie port 68) port on the guest.
Only very new versions of iptables will have this support (it has been
submitted upstream, but not yet committed), so a failure to add this
rule only results in a warning message. The iptables patch is here:
http://patchwork.ozlabs.org/patch/58525/
A corresponding kernel module patch is also required (the backend of
the iptables patch) and has been submitted, but I don't have the
details for that (I tested using a pre-built image I received from the
developer, Michael Tsirkin).
---
src/libvirt_private.syms | 2 +
src/network/bridge_driver.c | 17 ++++++++++
src/util/iptables.c | 71 +++++++++++++++++++++++++++++++++++++++++++
src/util/iptables.h | 6 ++++
4 files changed, 96 insertions(+), 0 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 778ceb1..d81d4cf 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -328,6 +328,7 @@ iptablesAddForwardAllowRelatedIn;
iptablesAddForwardMasquerade;
iptablesAddForwardRejectIn;
iptablesAddForwardRejectOut;
+iptablesAddOutputFixUdpChecksum;
iptablesAddTcpInput;
iptablesAddUdpInput;
iptablesContextFree;
@@ -339,6 +340,7 @@ iptablesRemoveForwardAllowRelatedIn;
iptablesRemoveForwardMasquerade;
iptablesRemoveForwardRejectIn;
iptablesRemoveForwardRejectOut;
+iptablesRemoveOutputFixUdpChecksum;
iptablesRemoveTcpInput;
iptablesRemoveUdpInput;
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 72255c1..c4480ff 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -781,6 +781,19 @@ networkAddIptablesRules(struct network_driver *driver,
!networkAddRoutingIptablesRules(driver, network))
goto err8;
+ /* If we are doing local DHCP service on this network, attempt to
+ * add a rule that will fixup the checksum of DHCP response
+ * packets back to the guests (but report failure without
+ * aborting, since not all iptables implementations support it).
+ */
+
+ if ((network->def->ipAddress || network->def->nranges) &&
+ (iptablesAddOutputFixUdpChecksum(driver->iptables,
+ network->def->bridge, 68) != 0)) {
+ VIR_WARN("Could not add rule to fixup DHCP response checksums "
+ "on network '%s'", network->def->name);
+ }
+
return 1;
err8:
@@ -811,6 +824,10 @@ networkAddIptablesRules(struct network_driver *driver,
static void
networkRemoveIptablesRules(struct network_driver *driver,
virNetworkObjPtr network) {
+ if (network->def->ipAddress || network->def->nranges) {
+ iptablesRemoveOutputFixUdpChecksum(driver->iptables,
+ network->def->bridge, 68);
+ }
if (network->def->forwardType != VIR_NETWORK_FORWARD_NONE) {
if (network->def->forwardType == VIR_NETWORK_FORWARD_NAT) {
iptablesRemoveForwardMasquerade(driver->iptables,
diff --git a/src/util/iptables.c b/src/util/iptables.c
index d06b857..9b888e5 100644
--- a/src/util/iptables.c
+++ b/src/util/iptables.c
@@ -60,6 +60,7 @@ struct _iptablesContext
iptRules *input_filter;
iptRules *forward_filter;
iptRules *nat_postrouting;
+ iptRules *mangle_postrouting;
};
static void
@@ -188,6 +189,9 @@ iptablesContextNew(void)
if (!(ctx->nat_postrouting = iptRulesNew("nat", "POSTROUTING")))
goto error;
+ if (!(ctx->mangle_postrouting = iptRulesNew("mangle", "POSTROUTING")))
+ goto error;
+
return ctx;
error:
@@ -210,6 +214,8 @@ iptablesContextFree(iptablesContext *ctx)
iptRulesFree(ctx->forward_filter);
if (ctx->nat_postrouting)
iptRulesFree(ctx->nat_postrouting);
+ if (ctx->mangle_postrouting)
+ iptRulesFree(ctx->mangle_postrouting);
VIR_FREE(ctx);
}
@@ -753,3 +759,68 @@ iptablesRemoveForwardMasquerade(iptablesContext *ctx,
{
return iptablesForwardMasquerade(ctx, network, physdev, REMOVE);
}
+
+
+static int
+iptablesOutputFixUdpChecksum(iptablesContext *ctx,
+ const char *iface,
+ int port,
+ int action)
+{
+ char portstr[32];
+
+ snprintf(portstr, sizeof(portstr), "%d", port);
+ portstr[sizeof(portstr) - 1] = '\0';
+
+ return iptablesAddRemoveRule(ctx->mangle_postrouting,
+ action,
+ "--out-interface", iface,
+ "--protocol", "udp",
+ "--destination-port", portstr,
+ "--jump", "CHECKSUM", "--checksum-fill",
+ NULL);
+}
+
+/**
+ * iptablesAddOutputFixUdpChecksum:
+ * @ctx: pointer to the IP table context
+ * @iface: the interface name
+ * @port: the UDP port to match
+ *
+ * Add an rule to the mangle table's POSTROUTING chain that fixes up the
+ * checksum of packets with the given destination @port.
+ * the given @iface interface for TCP packets.
+ *
+ * Returns 0 in case of success or an error code in case of error.
+ * (NB: if the system's iptables does not support checksum mangling,
+ * this will return an error, which should be ignored.)
+ */
+
+int
+iptablesAddOutputFixUdpChecksum(iptablesContext *ctx,
+ const char *iface,
+ int port)
+{
+ return iptablesOutputFixUdpChecksum(ctx, iface, port, ADD);
+}
+
+/**
+ * iptablesRemoveOutputFixUdpChecksum:
+ * @ctx: pointer to the IP table context
+ * @iface: the interface name
+ * @port: the UDP port of the rule to remove
+ *
+ * Removes the checksum fixup rule that was previous added with
+ * iptablesAddOutputFixUdpChecksum.
+ *
+ * Returns 0 in case of success or an error code in case of error
+ * (again, if iptables doesn't support checksum fixup, this will
+ * return an error, which should be ignored)
+ */
+int
+iptablesRemoveOutputFixUdpChecksum(iptablesContext *ctx,
+ const char *iface,
+ int port)
+{
+ return iptablesOutputFixUdpChecksum(ctx, iface, port, REMOVE);
+}
diff --git a/src/util/iptables.h b/src/util/iptables.h
index 7d55a6d..5c2e553 100644
--- a/src/util/iptables.h
+++ b/src/util/iptables.h
@@ -89,5 +89,11 @@ int iptablesAddForwardMasquerade (iptablesContext *ctx,
int iptablesRemoveForwardMasquerade (iptablesContext *ctx,
const char *network,
const char *physdev);
+int iptablesAddOutputFixUdpChecksum (iptablesContext *ctx,
+ const char *iface,
+ int port);
+int iptablesRemoveOutputFixUdpChecksum (iptablesContext *ctx,
+ const char *iface,
+ int port);
#endif /* __QEMUD_IPTABLES_H__ */
--
1.7.1.1
14 years, 3 months
[libvirt] [PATCH] qemu: kill some dead stores
by Eric Blake
Spotted by clang. The qemuConnectMonitor one is an outright bug,
the other two are cosmetic.
* src/qemu/qemu_monitor.c (qemuMonitorClose): Kill dead store.
* src/qemu/qemu_driver.c (qemudDomainSaveImageStartVM): Likewise.
(qemuConnectMonitor): Don't lose error status.
---
src/qemu/qemu_driver.c | 2 --
src/qemu/qemu_monitor.c | 4 +---
2 files changed, 1 insertions(+), 5 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 098f4da..57b8271 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -1416,7 +1416,6 @@ qemuConnectMonitor(struct qemud_driver *driver, virDomainObjPtr vm)
ret = qemuMonitorSetCapabilities(priv->mon);
qemuDomainObjExitMonitorWithDriver(driver, vm);
- ret = 0;
error:
if (ret < 0)
qemuMonitorClose(priv->mon);
@@ -6535,7 +6534,6 @@ qemudDomainSaveImageStartVM(virConnectPtr conn,
wait_ret = qemudDomainSaveImageClose(fd, read_pid, &status);
fd = -1;
if (read_pid != -1) {
- read_pid = -1;
if (wait_ret == -1) {
virReportSystemError(errno,
_("failed to wait for process reading '%s'"),
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index f1494ff..2366fdb 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -685,8 +685,6 @@ cleanup:
void qemuMonitorClose(qemuMonitorPtr mon)
{
- int refs;
-
if (!mon)
return;
@@ -706,7 +704,7 @@ void qemuMonitorClose(qemuMonitorPtr mon)
mon->closed = 1;
}
- if ((refs = qemuMonitorUnref(mon)) > 0)
+ if (qemuMonitorUnref(mon) > 0)
qemuMonitorUnlock(mon);
}
--
1.7.2
14 years, 3 months
[libvirt] [PATCH] Fix the ACS checking in the PCI code.
by Chris Lalancette
When trying to assign a PCI device to a guest, we have
to check that all bridges upstream of that device support
ACS. That means that we have to find the parent bridge of
the current device, check for ACS, then find the parent bridge
of that device, check for ACS, etc. As it currently stands,
the code to do this iterates through all PCI devices on the
system, looking for a device that has a range of busses that
included the current device's bus.
That check is not restrictive enough, though. Depending on
how we iterated through the list of PCI devices, we could first
find the *topmost* bridge in the system; since it necessarily had
a range of busses including the current device's bus, we
would only ever check the topmost bridge, and not check
any of the intermediate bridges.
Note that this also caused a fairly serious bug in the
secondary bus reset code, where we could erroneously
find and reset the topmost bus instead of the inner bus.
This patch changes pciGetParentDevice() so that it first
checks if a bridge device's secondary bus exactly matches
the bus of the device we are looking for. If it does, we've
found the correct parent bridge and we are done. If it does not,
then we check to see if this bridge device's busses *include* the
bus of the device we care about. If so, we mark this bridge device
as best, and go on. If we later find another bridge device whose
busses include this device, but is more restrictive, then we
free up the previous best and mark the new one as best. This
algorithm ensures that in the normal case we find the direct
parent, but in the case that the parent bridge secondary bus
is not exactly the same as the device, we still find the
correct bridge.
This patch was tested by me on a 4-port NIC with a
bridge without ACS (where assignment failed), a 4-port
NIC with a bridge with ACS (where assignment succeeded),
and a 2-port NIC with no bridges (where assignment
succeeded).
Signed-off-by: Chris Lalancette <clalance(a)redhat.com>
---
src/util/pci.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 66 insertions(+), 12 deletions(-)
diff --git a/src/util/pci.c b/src/util/pci.c
index 26d55b8..f2890bd 100644
--- a/src/util/pci.c
+++ b/src/util/pci.c
@@ -283,6 +283,7 @@ pciIterDevices(pciIterPredicate predicate,
DIR *dir;
struct dirent *entry;
int ret = 0;
+ int rc;
*matched = NULL;
@@ -322,11 +323,20 @@ pciIterDevices(pciIterPredicate predicate,
break;
}
- if (predicate(dev, check, data)) {
+ rc = predicate(dev, check, data);
+ if (rc < 0) {
+ /* the predicate returned an error, bail */
+ pciFreeDevice(check);
+ ret = -1;
+ break;
+ }
+ else if (rc == 1) {
VIR_DEBUG("%s %s: iter matched on %s", dev->id, dev->name, check->name);
*matched = check;
+ ret = 1;
break;
}
+
pciFreeDevice(check);
}
closedir(dir);
@@ -510,10 +520,11 @@ pciBusContainsActiveDevices(pciDevice *dev,
/* Is @check the parent of @dev ? */
static int
-pciIsParent(pciDevice *dev, pciDevice *check, void *data ATTRIBUTE_UNUSED)
+pciIsParent(pciDevice *dev, pciDevice *check, void *data)
{
uint16_t device_class;
uint8_t header_type, secondary, subordinate;
+ pciDevice **best = data;
if (dev->domain != check->domain)
return 0;
@@ -533,16 +544,54 @@ pciIsParent(pciDevice *dev, pciDevice *check, void *data ATTRIBUTE_UNUSED)
VIR_DEBUG("%s %s: found parent device %s", dev->id, dev->name, check->name);
- /* No, it's superman! */
- return (dev->bus >= secondary && dev->bus <= subordinate);
+ /* 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)
+ return 1;
+
+ /* otherwise, SRIOV allows VFs to be on different busses then their PFs.
+ * 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 (*best == NULL) {
+ *best = pciGetDevice(check->domain, check->bus, check->slot,
+ check->function);
+ if (*best == NULL)
+ return -1;
+ }
+ else {
+ /* OK, we had already recorded a previous "best" match for the
+ * parent. See if the current device is more restrictive than the
+ * best, and if so, make it the new best
+ */
+ if (secondary > pciRead8(*best, PCI_SECONDARY_BUS)) {
+ pciFreeDevice(*best);
+ *best = pciGetDevice(check->domain, check->bus, check->slot,
+ check->function);
+ if (*best == NULL)
+ return -1;
+ }
+ }
+ }
+
+ return 0;
}
-static pciDevice *
-pciGetParentDevice(pciDevice *dev)
+static int
+pciGetParentDevice(pciDevice *dev, pciDevice **parent)
{
- pciDevice *parent = NULL;
- pciIterDevices(pciIsParent, dev, &parent, NULL);
- return parent;
+ pciDevice *best = NULL;
+ int ret;
+
+ *parent = NULL;
+ ret = pciIterDevices(pciIsParent, dev, parent, &best);
+ if (ret == 1)
+ pciFreeDevice(best);
+ else if (ret == 0)
+ *parent = best;
+ return ret;
}
/* Secondary Bus Reset is our sledgehammer - it resets all
@@ -570,7 +619,8 @@ pciTrySecondaryBusReset(pciDevice *dev,
}
/* Find the parent bus */
- parent = pciGetParentDevice(dev);
+ if (pciGetParentDevice(dev, &parent) < 0)
+ return -1;
if (!parent) {
pciReportError(VIR_ERR_NO_SUPPORT,
_("Failed to find parent device for %s"),
@@ -1377,7 +1427,8 @@ pciDeviceIsBehindSwitchLackingACS(pciDevice *dev)
{
pciDevice *parent;
- parent = pciGetParentDevice(dev);
+ if (pciGetParentDevice(dev, &parent) < 0)
+ return -1;
if (!parent) {
/* if we have no parent, and this is the root bus, ACS doesn't come
* into play since devices on the root bus can't P2P without going
@@ -1400,6 +1451,7 @@ pciDeviceIsBehindSwitchLackingACS(pciDevice *dev)
do {
pciDevice *tmp;
int acs;
+ int ret;
acs = pciDeviceDownstreamLacksACS(parent);
@@ -1412,8 +1464,10 @@ pciDeviceIsBehindSwitchLackingACS(pciDevice *dev)
}
tmp = parent;
- parent = pciGetParentDevice(parent);
+ ret = pciGetParentDevice(parent, &parent);
pciFreeDevice(tmp);
+ if (ret < 0)
+ return -1;
} while (parent);
return 0;
--
1.7.1.1
14 years, 3 months
[libvirt] [PATCH] Free up memballoon def.
by Chris Lalancette
Forgetting to do this was causing a memory leak.
Signed-off-by: Chris Lalancette <clalance(a)redhat.com>
---
src/conf/domain_conf.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index ca4bc6e..1ddea0a 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -768,6 +768,8 @@ void virDomainDefFree(virDomainDefPtr def)
virDomainWatchdogDefFree(def->watchdog);
+ virDomainMemballoonDefFree(def->memballoon);
+
virSecurityLabelDefFree(def);
virCPUDefFree(def->cpu);
--
1.7.2
14 years, 3 months