Devel
Threads by month
- ----- 2026 -----
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- 37 participants
- 40384 discussions
We are still awaiting a CVE number to be assigned, but Reco
reported in Debian bug #732394 that a malicious guest could
cause virDomainShutdown and virDomainReboot to cause the
host to misbehave, if the host blindly follows symlinks in
its own mount namespace instead of the guest's namespace.
I have not yet tried to patch the bugs in virDomainDeviceAttach
dereferencing /dev from the wrong namespace, which also suffers
from the same vulnerability, but virProcessRunInMountNamespace
should also be usable in that situation.
While working on this series, I found several issues with
virFork and virt-login-shell; since those are also related
to correct namespace usage, I've bundled everything into
one series; but the CVE is not fixed until patch 7/7 plus
the future patch to /dev. I've done some pretty decent
testing on the new virt-login-shell, but did not get as
much testing on virDomainReboot. Since this series does
address a CVE, and also regressions caused by our previous
CVE fix in the same area of code (CVE-2013-4400 is
unfortunately a poor example of shipping "fixes" without
testing that the code still worked), I'd definitely
appreciate a close review.
Patch 6/7 is interesting: it uses virFork to use the mount
namespace without impacting the parent process. However,
since setns() is thread-safe, I wonder if it would be
simpler to instead use pthread_create to do the callback
within the same process instead of having to create a
separate process, as that would make for easier coordination
for passing the results back to the remaining threads that
have not changed namespace. Thankfully, I think we came
up with a good abstraction - I'm fairly confident that
6/7 could be rewritten to use pthread_create without
changing the function signatures, in which case patch
7/7 would not need any changes to pick up the changed
backend.
Eric Blake (7):
virt-login-shell: fix regressions in behavior
virFork: simplify semantics
virt-login-shell: use single instead of double fork
virt-login-shell: saner exit value
virsh: report exit status of failed lxc-enter-namespace
lxc: add virProcessRunInMountNamespace
lxc: security fix for virInitctlSetRunLevel
src/internal.h | 7 +++
src/libvirt.c | 2 +-
src/libvirt_private.syms | 1 +
src/lxc/lxc_driver.c | 38 ++++++------
src/util/vircommand.c | 128 +++++++++++++++-----------------------
src/util/vircommand.h | 2 +-
src/util/virfile.c | 25 ++------
src/util/virinitctl.c | 28 ++++-----
src/util/virinitctl.h | 5 +-
src/util/virprocess.c | 81 ++++++++++++++++++++++--
src/util/virprocess.h | 11 ++++
tools/virsh-domain.c | 34 ++++++----
tools/virsh.pod | 3 +-
tools/virt-login-shell.c | 151 ++++++++++++++++++++-------------------------
tools/virt-login-shell.pod | 23 ++++++-
15 files changed, 299 insertions(+), 240 deletions(-)
--
1.8.4.2
4
18
This series is in response to:
https://www.redhat.com/archives/libvir-list/2013-December/msg01101.html
It turned into a much bigger cleanup project, where I ended up
with a lot of changes; hopefully the division into multiple
patches makes review easier, and the end result diffstat shows
that the code base is more compact when all is said and done.
Eric Blake (24):
maint: consistent formatting in libvirt.c
maint: improve debug of libvirt-{qemu,lxc} apis
maint: move debug statements first in public API
maint: improve error condition style in public API
maint: don't leave garbage on early API exit
maint: reset error on entrance to public API
maint: avoid nested public calls
maint: improve VIR_ERR_NO_SUPPORT usage
maint: improve VIR_ERR_OPERATION_DENIED usage
maint: improve VIR_ERR_INVALID_CONN usage
maint: inline VIR_IS_CONNECT macro
maint: improve VIR_ERR_INVALID_DOMAIN usage
maint: inline VIR_IS*_DOMAIN macro
maint: improve VIR_ERR_INVALID_NETWORK usage
maint: improve VIR_ERR_INVALID_INTERFACE usage
maint: improve VIR_ERR_INVALID_STORAGE_POOL usage
maint: improve VIR_ERR_INVALID_STORAGE_VOL usage
maint: improve VIR_ERR_INVALID_NODE_DEVICE usage
maint: improve VIR_ERR_INVALID_SECRET usage
maint: improve VIR_ERR_INVALID_STREAM usage
maint: improve VIR_ERR_INVALID_NWFILTER usage
maint: improve VIR_ERR_INVALID_DOMAIN_SNAPSHOT usage
maint: clean up error reporting in migration
maint: replace remaining virLib*Error with better names
cfg.mk | 10 -
docs/api_extension.html.in | 7 +-
po/POTFILES.in | 1 -
src/datatypes.c | 104 +-
src/datatypes.h | 318 ++-
src/internal.h | 9 +
src/libvirt-lxc.c | 38 +-
src/libvirt-qemu.c | 65 +-
src/libvirt.c | 5342 +++++++++++++--------------------------
src/locking/lock_daemon.c | 16 +-
src/lxc/lxc_driver.c | 2 +-
src/qemu/qemu_migration.c | 10 +-
src/security/security_manager.c | 46 +-
src/util/virerror.c | 2 +-
src/util/virerror.h | 8 +
src/util/virinitctl.c | 4 +-
src/util/virtypedparam.c | 14 +-
src/util/viruuid.h | 20 +-
src/xen/xen_driver.c | 11 +-
19 files changed, 2250 insertions(+), 3777 deletions(-)
--
1.8.4.2
2
75
[libvirt] [PATCH] storage: fix crash when listing volumes or undefining a pool
by Martin Kletzander 09 Jan '14
by Martin Kletzander 09 Jan '14
09 Jan '14
The commit cad3cf9a951d26da9d2ee0f5b52fb1a2dbb74af1 introduced a crash
due to wrong order of parameters being passed to the function. When
deleting an element, the function decreased the iterator instead of
count and if listing volumes after that (or undefining the pool, NULL
was being dereferenced.
Signed-off-by: Martin Kletzander <mkletzan(a)redhat.com>
---
src/storage/storage_driver.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c
index aaa0f02..85fc0f2 100644
--- a/src/storage/storage_driver.c
+++ b/src/storage/storage_driver.c
@@ -1566,7 +1566,7 @@ storageVolDelete(virStorageVolPtr obj,
vol->name, pool->def->name);
virStorageVolDefFree(vol);
- VIR_DELETE_ELEMENT(pool->volumes.objs, pool->volumes.count, i);
+ VIR_DELETE_ELEMENT(pool->volumes.objs, i, pool->volumes.count);
break;
}
}
--
1.8.5.2
2
2
09 Jan '14
The error handling in libvirt-java is sort of a mess.
Each and every class contains a processError() method which
just forwards to ErrorHandler.processError(jna.Libvirt).
Furthermore, this processError() method is often called unnecessarily
after every libvirt call, although its return code did not indicate an
error at all.
So, this patchset removes the cruft with the added benefit of avoiding
calls into native code when possible.
Patch #1 starts the refactoring. It adds a few helper methods to the
ErrorHandler class which will be removed by patch #15.
Patch #2 to #13 are mostly mechanical, just wrapping calls of any libvirt
function into a call to processError(int) or processError<T>(T).
Patch #14 removes the obsolete processError(Libvirt) method.
Patch #15 cleans up patch #1.
Claudio Bley (15):
Start refactoring of error handling
Remove processError from Device class
Remove processError from Domain class
Remove processError from DomainSnapshot class
Remove processError from Interface class
Remove processError method from Network class
Remove processError method from NetworkFilter class
Remove processError method from Secret class
Remove processError method from StoragePool class
Remove processError method from StorageVol class
Remove processError method from Stream class
Remove processError method from Connect class
Call processError only when virInitialize signalled an error
Remove ErrorHandler.processError(Libvirt) method
fixup! Start refactoring of error handling
src/main/java/org/libvirt/Connect.java | 69 +-----
src/main/java/org/libvirt/Device.java | 49 ++--
src/main/java/org/libvirt/Domain.java | 328 +++++++++-----------------
src/main/java/org/libvirt/DomainSnapshot.java | 23 +-
src/main/java/org/libvirt/ErrorHandler.java | 44 +++-
src/main/java/org/libvirt/Interface.java | 43 +---
src/main/java/org/libvirt/Library.java | 4 +-
src/main/java/org/libvirt/Network.java | 61 ++---
src/main/java/org/libvirt/NetworkFilter.java | 43 +---
src/main/java/org/libvirt/Secret.java | 61 ++---
src/main/java/org/libvirt/StoragePool.java | 95 +++-----
src/main/java/org/libvirt/StorageVol.java | 56 ++---
src/main/java/org/libvirt/Stream.java | 64 ++---
13 files changed, 297 insertions(+), 643 deletions(-)
--
1.8.5.2.msysgit.0
1
15
[libvirt] [PATCH RESEND] qemuBuildNicDevStr: Set vectors= on Multiqueue
by Michal Privoznik 09 Jan '14
by Michal Privoznik 09 Jan '14
09 Jan '14
Yet another advice appeared on the Multiqueue wiki page:
http://www.linux-kvm.org/page/Multiqueue#Enable_MQ_feature
We should add vectors=N onto the qemu command line, where
N = 2 * (number of queues) + 1.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
src/qemu/qemu_command.c | 13 +++++++------
src/qemu/qemu_command.h | 2 +-
src/qemu/qemu_hotplug.c | 4 +---
3 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 35b7c67..81486df 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -4980,7 +4980,7 @@ qemuBuildNicDevStr(virDomainDefPtr def,
virDomainNetDefPtr net,
int vlan,
int bootindex,
- bool multiqueue,
+ int vhostfdSize,
virQEMUCapsPtr qemuCaps)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
@@ -5035,8 +5035,11 @@ qemuBuildNicDevStr(virDomainDefPtr def,
virDomainVirtioEventIdxTypeToString(net->driver.virtio.event_idx));
}
}
- if (usingVirtio && multiqueue)
- virBufferAddLit(&buf, ",mq=on");
+ if (usingVirtio && vhostfdSize > 1) {
+ /* As advised at http://www.linux-kvm.org/page/Multiqueue
+ * we should add vectors=2*N+1 where N is the vhostfdSize */
+ virBufferAsprintf(&buf, ",mq=on,vectors=%d", 2 * vhostfdSize + 1);
+ }
if (vlan == -1)
virBufferAsprintf(&buf, ",netdev=host%s", net->info.alias);
else
@@ -7591,10 +7594,8 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,
virCommandAddArgList(cmd, "-netdev", host, NULL);
}
if (qemuDomainSupportsNicdev(def, qemuCaps, net)) {
- bool multiqueue = tapfdSize > 1 || vhostfdSize > 1;
-
if (!(nic = qemuBuildNicDevStr(def, net, vlan, bootindex,
- multiqueue, qemuCaps)))
+ vhostfdSize, qemuCaps)))
goto cleanup;
virCommandAddArgList(cmd, "-device", nic, NULL);
} else {
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index 66c23cc..de7683d 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -105,7 +105,7 @@ char * qemuBuildNicDevStr(virDomainDefPtr def,
virDomainNetDefPtr net,
int vlan,
int bootindex,
- bool multiqueue,
+ int vhostfdSize,
virQEMUCapsPtr qemuCaps);
char *qemuDeviceDriveHostAlias(virDomainDiskDefPtr disk,
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 7a8caf1..4315df2 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -998,10 +998,8 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
}
if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
- bool multiqueue = tapfdSize > 1 || vhostfdSize > 1;
-
if (!(nicstr = qemuBuildNicDevStr(vm->def, net, vlan, 0,
- multiqueue, priv->qemuCaps)))
+ vhostfdSize, priv->qemuCaps)))
goto try_remove;
} else {
if (!(nicstr = qemuBuildNicStr(net, NULL, vlan)))
--
1.8.5.1
2
1
09 Jan '14
We point to the manpages where available and redirect to libvirt's
homepage as a last resort.
---
daemon/libvirtd.service.in | 2 ++
src/locking/virtlockd.service.in | 2 ++
tools/libvirt-guests.service.in | 2 ++
3 files changed, 6 insertions(+)
diff --git a/daemon/libvirtd.service.in b/daemon/libvirtd.service.in
index 25979ef..dc2433a 100644
--- a/daemon/libvirtd.service.in
+++ b/daemon/libvirtd.service.in
@@ -9,6 +9,8 @@ Before=libvirt-guests.service
After=network.target
After=dbus.service
After=iscsid.service
+Documentation=man:libvirtd(8)
+Documentation=http://libvirt.org
[Service]
EnvironmentFile=-/etc/sysconfig/libvirtd
diff --git a/src/locking/virtlockd.service.in b/src/locking/virtlockd.service.in
index a1298a3..57089b0 100644
--- a/src/locking/virtlockd.service.in
+++ b/src/locking/virtlockd.service.in
@@ -1,6 +1,8 @@
[Unit]
Description=Virtual machine lock manager
Requires=virtlockd.socket
+Documentation=man:virtlockd(8)
+Documentation=http://libvirt.org
[Service]
EnvironmentFile=-/etc/sysconfig/virtlockd
diff --git a/tools/libvirt-guests.service.in b/tools/libvirt-guests.service.in
index d48d4b8..d8d7adf 100644
--- a/tools/libvirt-guests.service.in
+++ b/tools/libvirt-guests.service.in
@@ -1,6 +1,8 @@
[Unit]
Description=Suspend Active Libvirt Guests
After=network.target libvirtd.service
+Documentation=man:libvirtd(8)
+Documentation=http://libvirt.org
[Service]
EnvironmentFile=-/etc/sysconfig/libvirt-guests
--
1.8.5.2
2
2
09 Jan '14
Let the Device.listCapabilities method return an array filled with
non-null string objects. Furthermore, the decoding of the character
data does no longer depend upon the default JVM charset.
This also fixes a memleak because the allocated memory was not freed
in the old code.
Patch #2 just adds a unit test which simply uses this function.
Claudio Bley (2):
Make Device.listCapabilities return only valid array elements
test: ensure the Device.listCapabilities method works
src/main/java/org/libvirt/Device.java | 10 +++++++---
src/main/java/org/libvirt/jna/Libvirt.java | 2 +-
src/test/java/org/libvirt/TestJavaBindings.java | 14 ++++++++++++++
3 files changed, 22 insertions(+), 4 deletions(-)
--
1.8.5.2.msysgit.0
1
2
Stefan Bader wrote:
> This basically reverts commit ba64b97134a6129a48684f22f31be92c3b6eef96
> "libxl: Allow libxl to set NIC devid". However assigning devid's
> before calling libxlMakeNic does not work as that is calling
> libxl_device_nic_init which sets it back to -1.
> Right now auto-assignment only works in the hotplug case. But even if
> that would be fixed at some point (if that is possible at all), this
> would add a weird dependency between Xen and libvirt versions.
Yeah, I had numerous inquires and bugs come my way even after fixing vfb and
vkb devid initialization in libxl with xen.git commit 5420f265. It took
some time for the fix to make its way to downstream users. Since there is
not yet a fix in Xen, it only makes sense to do the nic devid initialization
in libvirt to fix PXE booting HVM domains.
> The change here should accept any auto-assignment that makes it into
> libxl_device_nic_init. My understanding is that a caller always is
> allowed to make the devid choice itself. And assuming libxlMakeNicList
> is only used on domain creation, a sequential numbering should be ok.
>
> Signed-off-by: Stefan Bader <stefan.bader(a)canonical.com>
> ---
> src/libxl/libxl_conf.c | 7 +++++++
> 1 file changed, 7 insertions(+)
>
> diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c
> index 04d01af..4cefadf 100644
> --- a/src/libxl/libxl_conf.c
> +++ b/src/libxl/libxl_conf.c
> @@ -918,6 +918,13 @@ libxlMakeNicList(virDomainDefPtr def,
> libxl_domain_config *d_config)
> for (i = 0; i < nnics; i++) {
> if (libxlMakeNic(def, l_nics[i], &x_nics[i]))
> goto error;
> + /*
> + * The devid (at least right now) will not get initialized by
> + * libxl in the setup case but is required for starting the
> + * device-model.
> + */
> + if (x_nics[i].devid < 0)
> + x_nics[i].devid = i;
I think this is a better approach than the original code removed by ba64b971.
I've pushed this since it is clearly a bug fix and appropriate for 1.2.1.
Regards,
Jim
> }
>
> d_config->nics = x_nics;
1
0
Chunyan Liu wrote:
> Extract code from qemu_hostdev.c and make it reusable for multiple drivers,
> meanwhile maintain a global hostdev state to solve conflict between
> different
> drivers.
>
> Signed-off-by: Chunyan Liu <cyliu(a)suse.com>
> ---
> po/POTFILES.in | 1 +
> src/Makefile.am | 1 +
> src/libvirt_private.syms | 21 +
> src/lxc/lxc_hostdev.c | 11 +-
> src/qemu/qemu_driver.c | 4 +-
> src/qemu/qemu_hostdev.c | 42 +-
> src/util/virhostdev.c | 1691
> ++++++++++++++++++++++++++++++++++++++++++++++
> src/util/virhostdev.h | 134 ++++
> src/util/virpci.c | 30 +-
> src/util/virpci.h | 9 +-
> src/util/virscsi.c | 28 +-
> src/util/virscsi.h | 8 +-
> src/util/virusb.c | 29 +-
> src/util/virusb.h | 8 +-
> 14 files changed, 1969 insertions(+), 48 deletions(-)
> create mode 100644 src/util/virhostdev.c
> create mode 100644 src/util/virhostdev.h
>
> diff --git a/po/POTFILES.in b/po/POTFILES.in
> index 49dfc9c..ba63428 100644
> --- a/po/POTFILES.in
> +++ b/po/POTFILES.in
> @@ -161,6 +161,7 @@ src/util/vireventpoll.c
> src/util/virfile.c
> src/util/virhash.c
> src/util/virhook.c
> +src/util/virhostdev.c
> src/util/viridentity.c
> src/util/virinitctl.c
> src/util/viriptables.c
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 57e163f..98233cd 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -104,6 +104,7 @@ UTIL_SOURCES = \
> util/virhash.c util/virhash.h \
> util/virhashcode.c util/virhashcode.h \
> util/virhook.c util/virhook.h \
> + util/virhostdev.c util/virhostdev.h \
> util/viridentity.c util/viridentity.h \
> util/virinitctl.c util/virinitctl.h \
> util/viriptables.c util/viriptables.h \
> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
> index 2dbb8f8..dcb0a3e 100644
> --- a/src/libvirt_private.syms
> +++ b/src/libvirt_private.syms
> @@ -1264,6 +1264,27 @@ virHookInitialize;
> virHookPresent;
>
>
> +#util/virhostdev.h
> +virHostdevHostSupportsPassthroughKVM;
> +virHostdevHostSupportsPassthroughVFIO;
> +virHostdevManagerGetDefault;
> +virHostdevPciNodeDeviceDetach;
> +virHostdevPciNodeDeviceReAttach;
> +virHostdevPciNodeDeviceReset;
> +virHostdevPrepareDomainHostdevs;
> +virHostdevPreparePciHostdevs;
> +virHostdevPrepareScsiHostdevs;
> +virHostdevPrepareUsbHostdevs;
> +virHostdevReAttachDomainHostdevs;
> +virHostdevReAttachPciHostdevs;
> +virHostdevReAttachScsiHostdevs;
> +virHostdevReAttachUsbHostdevs;
> +virHostdevUpdateActiveHostdevs;
> +virHostdevUpdateActivePciHostdevs;
> +virHostdevUpdateActiveScsiHostdevs;
> +virHostdevUpdateActiveUsbHostdevs;
> +
> +
> # util/viridentity.h
> virIdentityGetAttr;
> virIdentityGetCurrent;
> diff --git a/src/lxc/lxc_hostdev.c b/src/lxc/lxc_hostdev.c
> index 3b371fc..77ce965 100644
> --- a/src/lxc/lxc_hostdev.c
> +++ b/src/lxc/lxc_hostdev.c
> @@ -60,7 +60,7 @@ virLXCUpdateActiveUsbHostdevs(virLXCDriverPtr driver,
> continue;
> }
>
> - virUSBDeviceSetUsedBy(usb, def->name);
> + virUSBDeviceSetUsedBy(usb, "QEMU", def->name);
>
> virObjectLock(driver->activeUsbHostdevs);
> if (virUSBDeviceListAdd(driver->activeUsbHostdevs, usb) < 0) {
> @@ -90,7 +90,9 @@ virLXCPrepareHostdevUSBDevices(virLXCDriverPtr driver,
> for (i = 0; i < count; i++) {
> virUSBDevicePtr usb = virUSBDeviceListGet(list, i);
> if ((tmp = virUSBDeviceListFind(driver->activeUsbHostdevs, usb))) {
> - const char *other_name = virUSBDeviceGetUsedBy(tmp);
> + const char *other_name = NULL;
> + const char *other_drvname = NULL;
> + virUSBDeviceGetUsedBy(tmp, &other_drvname, &other_name);
>
> if (other_name)
> virReportError(VIR_ERR_OPERATION_INVALID,
> @@ -103,7 +105,7 @@ virLXCPrepareHostdevUSBDevices(virLXCDriverPtr driver,
> goto error;
> }
>
> - virUSBDeviceSetUsedBy(usb, name);
> + virUSBDeviceSetUsedBy(usb, "QEMU", name);
> VIR_DEBUG("Adding %03d.%03d dom=%s to activeUsbHostdevs",
> virUSBDeviceGetBus(usb), virUSBDeviceGetDevno(usb),
> name);
> /*
> @@ -352,6 +354,7 @@ virLXCDomainReAttachHostUsbDevices(virLXCDriverPtr
> driver,
> virDomainHostdevDefPtr hostdev = hostdevs[i];
> virUSBDevicePtr usb, tmp;
> const char *used_by = NULL;
> + const char *used_by_drvname = NULL;
>
> if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
> continue;
> @@ -389,7 +392,7 @@ virLXCDomainReAttachHostUsbDevices(virLXCDriverPtr
> driver,
> continue;
> }
>
> - used_by = virUSBDeviceGetUsedBy(tmp);
> + virUSBDeviceGetUsedBy(tmp, &used_by_drvname, &used_by);
> if (STREQ_NULLABLE(used_by, name)) {
> VIR_DEBUG("Removing %03d.%03d dom=%s from activeUsbHostdevs",
> hostdev->source.subsys.u.usb.bus,
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index 45d11cd..90820ab 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -10885,7 +10885,9 @@ qemuNodeDeviceReAttach(virNodeDevicePtr dev)
> virObjectLock(driver->inactivePciHostdevs);
> other = virPCIDeviceListFind(driver->activePciHostdevs, pci);
> if (other) {
> - const char *other_name = virPCIDeviceGetUsedBy(other);
> + const char *other_name = NULL;
> + const char *other_drvname = NULL;
> + virPCIDeviceGetUsedBy(other, &other_drvname, &other_name);
>
> if (other_name)
> virReportError(VIR_ERR_OPERATION_INVALID,
> diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c
> index dee61e7..1dc652b 100644
> --- a/src/qemu/qemu_hostdev.c
> +++ b/src/qemu/qemu_hostdev.c
> @@ -177,7 +177,7 @@ qemuUpdateActivePciHostdevs(virQEMUDriverPtr driver,
> goto cleanup;
>
> }
> - virPCIDeviceSetUsedBy(dev, def->name);
> + virPCIDeviceSetUsedBy(dev, "QEMU", def->name);
>
> /* Setup the original states for the PCI device */
> virPCIDeviceSetUnbindFromStub(dev,
> hostdev->origstates.states.pci.unbind_from_stub);
> @@ -230,7 +230,7 @@ qemuUpdateActiveUsbHostdevs(virQEMUDriverPtr driver,
> continue;
> }
>
> - virUSBDeviceSetUsedBy(usb, def->name);
> + virUSBDeviceSetUsedBy(usb, "QEMU", def->name);
>
> if (virUSBDeviceListAdd(driver->activeUsbHostdevs, usb) < 0) {
> virUSBDeviceFree(usb);
> @@ -270,7 +270,7 @@ qemuUpdateActiveScsiHostdevs(virQEMUDriverPtr driver,
> hostdev->readonly)))
> goto cleanup;
>
> - virSCSIDeviceSetUsedBy(scsi, def->name);
> + virSCSIDeviceSetUsedBy(scsi, "QEMU", def->name);
>
> if (virSCSIDeviceListAdd(driver->activeScsiHostdevs, scsi) < 0) {
> virSCSIDeviceFree(scsi);
> @@ -683,7 +683,9 @@ qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver,
> * the dev is in list driver->activePciHostdevs.
> */
> if ((other = virPCIDeviceListFind(driver->activePciHostdevs, dev))) {
> - const char *other_name = virPCIDeviceGetUsedBy(other);
> + const char *other_name = NULL;
> + const char *other_drvname = NULL;
> + virPCIDeviceGetUsedBy(other, &other_drvname, &other_name);
>
> if (other_name)
> virReportError(VIR_ERR_OPERATION_INVALID,
> @@ -756,7 +758,7 @@ qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver,
> activeDev = virPCIDeviceListFind(driver->activePciHostdevs, dev);
>
> if (activeDev)
> - virPCIDeviceSetUsedBy(activeDev, name);
> + virPCIDeviceSetUsedBy(activeDev, "QEMU", name);
> }
>
> /* Loop 8: Now set the original states for hostdev def */
> @@ -847,7 +849,9 @@ qemuPrepareHostdevUSBDevices(virQEMUDriverPtr driver,
> for (i = 0; i < count; i++) {
> virUSBDevicePtr usb = virUSBDeviceListGet(list, i);
> if ((tmp = virUSBDeviceListFind(driver->activeUsbHostdevs, usb))) {
> - const char *other_name = virUSBDeviceGetUsedBy(tmp);
> + const char *other_name = NULL;
> + const char *other_drvname = NULL;
> + virUSBDeviceGetUsedBy(tmp, &other_drvname, &other_name);
>
> if (other_name)
> virReportError(VIR_ERR_OPERATION_INVALID,
> @@ -860,7 +864,7 @@ qemuPrepareHostdevUSBDevices(virQEMUDriverPtr driver,
> goto error;
> }
>
> - virUSBDeviceSetUsedBy(usb, name);
> + virUSBDeviceSetUsedBy(usb, "QEMU", name);
> VIR_DEBUG("Adding %03d.%03d dom=%s to activeUsbHostdevs",
> virUSBDeviceGetBus(usb), virUSBDeviceGetDevno(usb),
> name);
> /*
> @@ -1116,7 +1120,9 @@ qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver,
> for (i = 0; i < count; i++) {
> virSCSIDevicePtr scsi = virSCSIDeviceListGet(list, i);
> if ((tmp = virSCSIDeviceListFind(driver->activeScsiHostdevs, scsi)))
> {
> - const char *other_name = virSCSIDeviceGetUsedBy(tmp);
> + const char *other_name = NULL;
> + const char *other_drvname = NULL;
> + virSCSIDeviceGetUsedBy(tmp, &other_drvname, &other_name);
>
> if (other_name)
> virReportError(VIR_ERR_OPERATION_INVALID,
> @@ -1129,7 +1135,7 @@ qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver,
> goto error;
> }
>
> - virSCSIDeviceSetUsedBy(scsi, name);
> + virSCSIDeviceSetUsedBy(scsi, "QEMU", name);
> VIR_DEBUG("Adding %s to activeScsiHostdevs",
> virSCSIDeviceGetName(scsi));
>
> if (virSCSIDeviceListAdd(driver->activeScsiHostdevs, scsi) < 0)
> @@ -1258,10 +1264,14 @@ qemuDomainReAttachHostdevDevices(virQEMUDriverPtr
> driver,
> * been used by this domain.
> */
> activeDev = virPCIDeviceListFind(driver->activePciHostdevs, dev);
> - if (activeDev &&
> - STRNEQ_NULLABLE(name, virPCIDeviceGetUsedBy(activeDev))) {
> - virPCIDeviceListDel(pcidevs, dev);
> - continue;
> + if (activeDev) {
> + const char *tmp_name = NULL;
> + const char *tmp_drvname = NULL;
> + virPCIDeviceGetUsedBy(activeDev, &tmp_drvname, &tmp_name);
> + if (STRNEQ_NULLABLE(name, tmp_name)) {
> + virPCIDeviceListDel(pcidevs, dev);
> + continue;
> + }
> }
>
> virPCIDeviceListDel(driver->activePciHostdevs, dev);
> @@ -1316,6 +1326,7 @@ qemuDomainReAttachHostUsbDevices(virQEMUDriverPtr
> driver,
> virDomainHostdevDefPtr hostdev = hostdevs[i];
> virUSBDevicePtr usb, tmp;
> const char *used_by = NULL;
> + const char *used_by_drvname = NULL;
>
> if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
> continue;
> @@ -1353,7 +1364,7 @@ qemuDomainReAttachHostUsbDevices(virQEMUDriverPtr
> driver,
> continue;
> }
>
> - used_by = virUSBDeviceGetUsedBy(tmp);
> + virUSBDeviceGetUsedBy(tmp, &used_by_drvname, &used_by);
> if (STREQ_NULLABLE(used_by, name)) {
> VIR_DEBUG("Removing %03d.%03d dom=%s from activeUsbHostdevs",
> hostdev->source.subsys.u.usb.bus,
> @@ -1380,6 +1391,7 @@ qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr
> driver,
> virDomainHostdevDefPtr hostdev = hostdevs[i];
> virSCSIDevicePtr scsi, tmp;
> const char *used_by = NULL;
> + const char *used_by_drvname = NULL;
> virDomainDeviceDef dev;
>
> dev.type = VIR_DOMAIN_DEVICE_HOSTDEV;
> @@ -1421,7 +1433,7 @@ qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr
> driver,
> continue;
> }
>
> - used_by = virSCSIDeviceGetUsedBy(tmp);
> + virSCSIDeviceGetUsedBy(tmp, &used_by_drvname, &used_by);
> if (STREQ_NULLABLE(used_by, name)) {
> VIR_DEBUG("Removing %s:%d:%d:%d dom=%s from
> activeScsiHostdevs",
> hostdev->source.subsys.u.scsi.adapter,
> diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c
> new file mode 100644
> index 0000000..63690b7
> --- /dev/null
> +++ b/src/util/virhostdev.c
> @@ -0,0 +1,1691 @@
> +/* virhostdev.c: hostdev management
> + *
> + * Copyright (C) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany.
> + * Copyright (C) 2006-2007, 2009-2013 Red Hat, Inc.
> + * Copyright (C) 2006 Daniel P. Berrange
> + *
> + * 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: Chunyan Liu <cyliu(a)suse.com>
> + * Author: Daniel P. Berrange <berrange(a)redhat.com>
> + */
> +
> +#include <config.h>
> +
> +#include <dirent.h>
> +#include <fcntl.h>
> +#include <sys/ioctl.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +
> +#include "virhostdev.h"
> +#include "viralloc.h"
> +#include "virstring.h"
> +#include "virfile.h"
> +#include "virerror.h"
> +#include "virlog.h"
> +#include "virnetdev.h"
> +#include "virutil.h"
> +#include "configmake.h"
> +
> +#define VIR_FROM_THIS VIR_FROM_NONE
> +
> +#define HOSTDEV_STATE_DIR LOCALSTATEDIR "/run/libvirt/hostdevmgr"
> +
> +/* for upgrade, may need to find netconfig file in old qemu state dir */
> +#define QEMU_STATE_DIR LOCALSTATEDIR "/run/libvirt/qemu"
> +
> +static virHostdevManagerPtr hostdevMgr;
> +
> +static void
> +virHostdevManagerCleanup(void)
> +{
> + if (!hostdevMgr)
> + return;
> +
> + virObjectUnref(hostdevMgr->activePciHostdevs);
> + virObjectUnref(hostdevMgr->inactivePciHostdevs);
> + virObjectUnref(hostdevMgr->activeUsbHostdevs);
> + VIR_FREE(hostdevMgr->stateDir);
> +
> + VIR_FREE(hostdevMgr);
> +}
> +
> +static int
> +virHostdevOnceInit(void)
> +{
> + if (VIR_ALLOC(hostdevMgr) < 0)
> + goto error;
> +
> + if ((hostdevMgr->activePciHostdevs = virPCIDeviceListNew()) == NULL)
> + goto error;
> +
> + if ((hostdevMgr->activeUsbHostdevs = virUSBDeviceListNew()) == NULL)
> + goto error;
> +
> + if ((hostdevMgr->inactivePciHostdevs = virPCIDeviceListNew()) == NULL)
> + goto error;
> +
> + if ((hostdevMgr->activeScsiHostdevs = virSCSIDeviceListNew()) == NULL)
> + goto error;
> +
> + if (VIR_STRDUP(hostdevMgr->stateDir, HOSTDEV_STATE_DIR) < 0)
> + goto error;
> +
> + if (virFileMakePath(hostdevMgr->stateDir) < 0) {
> + virReportError(VIR_ERR_OPERATION_FAILED,
> + _("Failed to create state dir '%s'"),
> + hostdevMgr->stateDir);
> + goto error;
> + }
> +
> + return 0;
> +
> +error:
> + virHostdevManagerCleanup();
> + return -1;
> +}
> +
> +VIR_ONCE_GLOBAL_INIT(virHostdev)
> +
> +virHostdevManagerPtr
> +virHostdevManagerGetDefault(void)
> +{
> + if (virHostdevInitialize() < 0)
> + return NULL;
> + return hostdevMgr;
> +}
> +
> +static int
> +virHostdevPciSysfsPath(virDomainHostdevDefPtr hostdev, char **sysfs_path)
> +{
> + virPCIDeviceAddress config_address;
> +
> + config_address.domain = hostdev->source.subsys.u.pci.addr.domain;
> + config_address.bus = hostdev->source.subsys.u.pci.addr.bus;
> + config_address.slot = hostdev->source.subsys.u.pci.addr.slot;
> + config_address.function = hostdev->source.subsys.u.pci.addr.function;
> +
> + return virPCIDeviceAddressGetSysfsFile(&config_address, sysfs_path);
> +}
> +
> +static int
> +virHostdevIsVirtualFunction(virDomainHostdevDefPtr hostdev)
> +{
> + char *sysfs_path = NULL;
> + int ret = -1;
> +
> + if (virHostdevPciSysfsPath(hostdev, &sysfs_path) < 0)
> + return ret;
> +
> + ret = virPCIIsVirtualFunction(sysfs_path);
> +
> + VIR_FREE(sysfs_path);
> +
> + return ret;
> +}
> +
> +static int
> +virHostdevNetDevice(virDomainHostdevDefPtr hostdev,
> + char **linkdev,
> + int *vf)
> +{
> + int ret = -1;
> + char *sysfs_path = NULL;
> +
> + if (virHostdevPciSysfsPath(hostdev, &sysfs_path) < 0)
> + return ret;
> +
> + if (virPCIIsVirtualFunction(sysfs_path) == 1) {
> + if (virPCIGetVirtualFunctionInfo(sysfs_path, linkdev, vf) < 0)
> + goto cleanup;
> + } else {
> + if (virPCIGetNetName(sysfs_path, linkdev) < 0)
> + goto cleanup;
> + *vf = -1;
> + }
> +
> + ret = 0;
> +
> +cleanup:
> + VIR_FREE(sysfs_path);
> +
> + return ret;
> +}
> +
> +static int
> +virHostdevNetConfigVirtPortProfile(const char *linkdev, int vf,
> + virNetDevVPortProfilePtr virtPort,
> + const virMacAddr *macaddr,
> + const unsigned char *uuid,
> + int associate)
> +{
> + int ret = -1;
> +
> + if (!virtPort)
> + return ret;
> +
> + switch (virtPort->virtPortType) {
> + case VIR_NETDEV_VPORT_PROFILE_NONE:
> + case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH:
> + case VIR_NETDEV_VPORT_PROFILE_8021QBG:
> + case VIR_NETDEV_VPORT_PROFILE_LAST:
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
> + _("virtualport type %s is "
> + "currently not supported on interfaces of type "
> + "hostdev"),
> + virNetDevVPortTypeToString(virtPort->virtPortType));
> + break;
> +
> + case VIR_NETDEV_VPORT_PROFILE_8021QBH:
> + if (associate)
> + ret = virNetDevVPortProfileAssociate(NULL, virtPort, macaddr,
> + linkdev, vf, uuid,
> +
> VIR_NETDEV_VPORT_PROFILE_OP_CREATE, false);
> + else
> + ret = virNetDevVPortProfileDisassociate(NULL, virtPort,
> + macaddr, linkdev, vf,
> +
> VIR_NETDEV_VPORT_PROFILE_OP_DESTROY);
> + break;
> + }
> +
> + return ret;
> +}
> +
> +static int
> +virHostdevNetConfigReplace(virDomainHostdevDefPtr hostdev,
> + const unsigned char *uuid,
> + char *stateDir)
> +{
> + char *linkdev = NULL;
> + virNetDevVlanPtr vlan;
> + virNetDevVPortProfilePtr virtPort;
> + int ret = -1;
> + int vf = -1;
> + int vlanid = -1;
> + int port_profile_associate = 1;
> + int isvf;
> +
> + isvf = virHostdevIsVirtualFunction(hostdev);
> + if (isvf <= 0) {
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> + _("Interface type hostdev is currently supported on
> "
> + "SR-IOV Virtual Functions only"));
> + return ret;
> + }
> +
> + if (virHostdevNetDevice(hostdev, &linkdev, &vf) < 0)
> + return ret;
> +
> + vlan = virDomainNetGetActualVlan(hostdev->parent.data.net)
> + virtPort =
> virDomainNetGetActualVirtPortProfile(hostdev->parent.data.net)
> + if (virtPort) {
> + if (vlan) {
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
> + _("direct setting of the vlan tag is not allowed
> "
> + "for hostdev devices using %s mode"),
> +
> virNetDevVPortTypeToString(virtPort->virtPortType));
> + goto cleanup;
> + }
> + ret = virHostdevNetConfigVirtPortProfile(linkdev, vf,
> + virtPort,
> + &hostdev->parent.data.net->mac,
> + uuid,
> + port_profile_associate);
> + } else {
> + /* Set only mac and vlan */
> + if (vlan) {
> + if (vlan->nTags != 1 || vlan->trunk) {
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> + _("vlan trunking is not supported "
> + "by SR-IOV network devices"));
> + goto cleanup;
> + }
> + if (vf == -1) {
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
> + _("vlan can only be set for SR-IOV VFs, but "
> + "%s is not a VF"), linkdev);
> + goto cleanup;
> + }
> + vlanid = vlan->tag[0];
> + } else if (vf >= 0) {
> + vlanid = 0; /* assure any current vlan tag is reset */
> + }
> +
> + ret = virNetDevReplaceNetConfig(linkdev, vf,
> + &hostdev->parent.data.net->mac,
> + vlanid, stateDir);
> + }
> +cleanup:
> + VIR_FREE(linkdev);
> + return ret;
> +}
> +
> +/* oldStateDir:
> + * For upgrade, if there is an existing VM on QEMU, the hostdev netconfig
> file
> + * is previously stored in /var/run/libvirt/qemu. With new version, it
> tries to
> + * find in hostdevManager->stateDir location but certainly it cannot find it.
> + * In this case, we should find in the old state dir.
> + */
> +static int
> +virHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev,
> + char *stateDir,
> + char *oldStateDir)
> +{
> + char *linkdev = NULL;
> + virNetDevVPortProfilePtr virtPort;
> + int ret = -1;
> + int vf = -1;
> + int port_profile_associate = 0;
> + int isvf;
> +
> + /* This is only needed for PCI devices that have been defined
> + * using <interface type='hostdev'>. For all others, it is a NOP.
> + */
> + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
> + hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI ||
> + hostdev->parent.type != VIR_DOMAIN_DEVICE_NET ||
> + !hostdev->parent.data.net)
> + return 0;
> +
> + isvf = virHostdevIsVirtualFunction(hostdev);
> + if (isvf <= 0) {
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> + _("Interface type hostdev is currently supported on
> "
> + "SR-IOV Virtual Functions only"));
> + return ret;
> + }
> +
> + if (virHostdevNetDevice(hostdev, &linkdev, &vf) < 0)
> + return ret;
> +
> + virtPort =
> virDomainNetGetActualVirtPortProfile(hostdev->parent.data.net)
> + if (virtPort)
> + ret = virHostdevNetConfigVirtPortProfile(linkdev, vf, virtPort,
> + &hostdev->parent.data.net->mac,
> + NULL,
> port_profile_associate);
> + else {
> + ret = virNetDevRestoreNetConfig(linkdev, vf, stateDir);
> + if (ret < 0 && oldStateDir != NULL)
> + ret = virNetDevRestoreNetConfig(linkdev, vf, oldStateDir);
> + }
> +
> + VIR_FREE(linkdev);
> +
> + return ret;
> +}
> +
> +static virPCIDeviceListPtr
> +virHostdevGetPciHostDeviceList(virDomainHostdevDefPtr *hostdevs, int
> nhostdevs)
> +{
> + virPCIDeviceListPtr list;
> + size_t i;
> +
> + if (!(list = virPCIDeviceListNew()))
> + return NULL;
> +
> + for (i = 0; i < nhostdevs; i++) {
> + virDomainHostdevDefPtr hostdev = hostdevs[i];
> + virPCIDevicePtr dev;
> +
> + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
> + continue;
> + if (hostdev->source.subsys.type !=
> VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
> + continue;
> +
> + dev = virPCIDeviceNew(hostdev->source.subsys.u.pci.addr.domain,
> + hostdev->source.subsys.u.pci.addr.bus,
> + hostdev->source.subsys.u.pci.addr.slot,
> + hostdev->source.subsys.u.pci.addr.function);
> + if (!dev) {
> + virObjectUnref(list);
> + return NULL;
> + }
> +
> + if (virPCIDeviceListAdd(list, dev) < 0) {
> + virPCIDeviceFree(dev);
> + virObjectUnref(list);
> + return NULL;
> + }
> +
> + virPCIDeviceSetManaged(dev, hostdev->managed);
> +
> + switch (hostdev->source.subsys.u.pci.backend) {
> + case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO:
> + if (virPCIDeviceSetStubDriver(dev, "vfio-pci") < 0) {
> + virObjectUnref(list);
> + return NULL;
> + }
> + break;
> +
> + case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM :
> + case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT:
> + if (virPCIDeviceSetStubDriver(dev, "pci-stub") < 0) {
> + virObjectUnref(list);
> + return NULL;
> + }
> + break;
> + }
> + }
> +
> + return list;
> +}
> +
> +bool
> +virHostdevHostSupportsPassthroughVFIO(void)
> +{
> + DIR *iommuDir = NULL;
> + struct dirent *iommuGroup = NULL;
> + bool ret = false;
> +
> + /* condition 1 - /sys/kernel/iommu_groups/ contains entries */
> + if (!(iommuDir = opendir("/sys/kernel/iommu_groups/")))
> + goto cleanup;
> +
> + while ((iommuGroup = readdir(iommuDir))) {
> + /* skip ./ ../ */
> + if (STRPREFIX(iommuGroup->d_name, "."))
> + continue;
> +
> + /* assume we found a group */
> + break;
> + }
> +
> + if (!iommuGroup)
> + goto cleanup;
> + /* okay, iommu is on and recognizes groups */
> +
> + /* condition 2 - /dev/vfio/vfio exists */
> + if (!virFileExists("/dev/vfio/vfio"))
> + goto cleanup;
> +
> + ret = true;
> +
> +cleanup:
> + if (iommuDir)
> + closedir(iommuDir);
> +
> + return ret;
> +}
> +
> +
> +#if HAVE_LINUX_KVM_H
> +# include <linux/kvm.h>
> +bool
> +virHostdevHostSupportsPassthroughKVM(void)
> +{
> + int kvmfd = -1;
> + bool ret = false;
> +
> + if ((kvmfd = open("/dev/kvm", O_RDONLY)) < 0)
> + goto cleanup;
> +
> +# ifdef KVM_CAP_IOMMU
> + if ((ioctl(kvmfd, KVM_CHECK_EXTENSION, KVM_CAP_IOMMU)) < 0)
Like the original code in qemu_hostdev.c, this needs to be <= 0. Otherwise, if intel_iommu=off, the ioctl returns 0, the function returns true, and we attempt to start a domain that is destined to fail.
I've been doing a fair bit of testing of this series and with the exception of the above issue, haven't noticed any problems thus far. Unfortunately, you will need to rebase the series and post a v9, but I'm confident we can get this pushed after the 1.2.1 freeze. Thanks!
Regards,
Jim
> + goto cleanup;
> +
> + ret = true;
> +# endif
> +
> +cleanup:
> + VIR_FORCE_CLOSE(kvmfd);
> +
> + return ret;
> +}
> +#else
> +bool
> +virHostdevHostSupportsPassthroughKVM(void)
> +{
> + return false;
> +}
> +#endif
> +
> +static bool
> +virHostdevPCICheckSupport(virDomainHostdevDefPtr *hostdevs,
> + size_t nhostdevs)
> +{
> + bool supportsPassthroughVFIO = virHostdevHostSupportsPassthroughVFIO();
> + bool supportsPassthroughKVM = virHostdevHostSupportsPassthroughKVM();
> + size_t i;
> +
> + /* assign defaults for hostdev passthrough */
> + for (i = 0; i < nhostdevs; i++) {
> + virDomainHostdevDefPtr hostdev = hostdevs[i];
> + int *backend = &hostdev->source.subsys.u.pci.backend;
> +
> + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
> + continue;
> + if (hostdev->source.subsys.type !=
> VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
> + continue;
> +
> + switch ((virDomainHostdevSubsysPciBackendType) *backend) {
> + case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO:
> + if (!supportsPassthroughVFIO) {
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> + _("host doesn't support VFIO PCI
> passthrough"));
> + return false;
> + }
> + break;
> +
> + case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT:
> + case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM:
> + if (!supportsPassthroughKVM) {
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> + _("host doesn't support legacy PCI
> passthrough"));
> + return false;
> + }
> +
> + break;
> +
> + default:
> + break;
> + }
> + }
> +
> + return true;
> +}
> +int
> +virHostdevPreparePciHostdevs(virHostdevManagerPtr mgr,
> + const char *drv_name,
> + const char *dom_name,
> + const unsigned char *uuid,
> + virDomainHostdevDefPtr *hostdevs,
> + int nhostdevs,
> + unsigned int flags)
> +{
> + virPCIDeviceListPtr pcidevs = NULL;
> + int last_processed_hostdev_vf = -1;
> + size_t i;
> + int ret = -1;
> +
> + if (!nhostdevs)
> + return 0;
> + if (mgr == NULL)
> + return -1;
> +
> + virObjectLock(mgr->activePciHostdevs);
> + virObjectLock(mgr->inactivePciHostdevs);
> +
> + if (!virHostdevPCICheckSupport(hostdevs, nhostdevs))
> + goto cleanup;
> +
> + if (!(pcidevs = virHostdevGetPciHostDeviceList(hostdevs, nhostdevs)))
> + goto cleanup;
> +
> + /* We have to use 9 loops here. *All* devices must
> + * be detached before we reset any of them, because
> + * in some cases you have to reset the whole PCI,
> + * which impacts all devices on it. Also, all devices
> + * must be reset before being marked as active.
> + */
> +
> + /* Loop 1: validate that non-managed device isn't in use, eg
> + * by checking that device is either un-bound, or bound
> + * to stub driver
> + */
> +
> + for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
> + virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
> + virPCIDevicePtr other;
> + bool strict_acs_check = !!(flags & VIR_STRICT_ACS_CHECK);
> +
> + if (!virPCIDeviceIsAssignable(dev, strict_acs_check)) {
> + virReportError(VIR_ERR_OPERATION_INVALID,
> + _("PCI device %s is not assignable"),
> + virPCIDeviceGetName(dev));
> + goto cleanup;
> + }
> + /* The device is in use by other active domain if
> + * the dev is in list activePciHostdevs.
> + */
> + if ((other = virPCIDeviceListFind(mgr->activePciHostdevs, dev))) {
> + const char *other_drvname;
> + const char *other_domname;
> +
> + virPCIDeviceGetUsedBy(other, &other_drvname, &other_domname);
> + if (other_drvname && other_domname)
> + virReportError(VIR_ERR_OPERATION_INVALID,
> + _("PCI device %s is in use by driver
> %s,domain %s"),
> + virPCIDeviceGetName(dev), other_drvname,
> + other_domname);
> + else
> + virReportError(VIR_ERR_OPERATION_INVALID,
> + _("PCI device %s is already in use"),
> + virPCIDeviceGetName(dev));
> + goto cleanup;
> + }
> + }
> +
> + /* Loop 2: detach managed devices */
> + for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
> + virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
> + if (virPCIDeviceGetManaged(dev) &&
> + virPCIDeviceDetach(dev, mgr->activePciHostdevs, NULL) < 0)
> + goto reattachdevs;
> + }
> +
> + /* Loop 3: Now that all the PCI hostdevs have been detached, we
> + * can safely reset them */
> + for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
> + virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
> + if (virPCIDeviceReset(dev, mgr->activePciHostdevs,
> + mgr->inactivePciHostdevs) < 0)
> + goto reattachdevs;
> + }
> +
> + /* Loop 4: For SRIOV network devices, Now that we have detached the
> + * the network device, set the netdev config */
> + for (i = 0; i < nhostdevs; i++) {
> + virDomainHostdevDefPtr hostdev = hostdevs[i];
> + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
> + continue;
> + if (hostdev->source.subsys.type !=
> VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
> + continue;
> + if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET &&
> + hostdev->parent.data.net) {
> + if (virHostdevNetConfigReplace(hostdev, uuid, mgr->stateDir) < 0)
> + goto resetvfnetconfig;
> + }
> + last_processed_hostdev_vf = i;
> + }
> +
> + /* Loop 5: Now mark all the devices as active */
> + for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
> + virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
> + if (virPCIDeviceListAdd(mgr->activePciHostdevs, dev) < 0)
> + goto inactivedevs;
> + }
> +
> + /* Loop 6: Now remove the devices from inactive list. */
> + for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
> + virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
> + virPCIDeviceListDel(mgr->inactivePciHostdevs, dev);
> + }
> +
> + /* Loop 7: Now set the used_by_domain of the device in
> + * driver->activePciHostdevs as domain name.
> + */
> + for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
> + virPCIDevicePtr dev, activeDev;
> +
> + dev = virPCIDeviceListGet(pcidevs, i);
> + activeDev = virPCIDeviceListFind(mgr->activePciHostdevs, dev);
> +
> + if (activeDev)
> + virPCIDeviceSetUsedBy(activeDev, drv_name, dom_name);
> + }
> +
> + /* Loop 8: Now set the original states for hostdev def */
> + for (i = 0; i < nhostdevs; i++) {
> + virPCIDevicePtr dev;
> + virPCIDevicePtr pcidev;
> + virDomainHostdevDefPtr hostdev = hostdevs[i];
> +
> + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
> + continue;
> + if (hostdev->source.subsys.type !=
> VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
> + continue;
> +
> + dev = virPCIDeviceNew(hostdev->source.subsys.u.pci.addr.domain,
> + hostdev->source.subsys.u.pci.addr.bus,
> + hostdev->source.subsys.u.pci.addr.slot,
> + hostdev->source.subsys.u.pci.addr.function);
> +
> + /* original states "unbind_from_stub", "remove_slot",
> + * "reprobe" were already set by pciDettachDevice in
> + * loop 2.
> + */
> + if ((pcidev = virPCIDeviceListFind(pcidevs, dev))) {
> + hostdev->origstates.states.pci.unbind_from_stub =
> + virPCIDeviceGetUnbindFromStub(pcidev);
> + hostdev->origstates.states.pci.remove_slot =
> + virPCIDeviceGetRemoveSlot(pcidev);
> + hostdev->origstates.states.pci.reprobe =
> + virPCIDeviceGetReprobe(pcidev);
> + }
> +
> + virPCIDeviceFree(dev);
> + }
> +
> + /* Loop 9: Now steal all the devices from pcidevs */
> + while (virPCIDeviceListCount(pcidevs) > 0)
> + virPCIDeviceListStealIndex(pcidevs, 0);
> +
> + ret = 0;
> + goto cleanup;
> +
> +inactivedevs:
> + /* Only steal all the devices from driver->activePciHostdevs. We will
> + * free them in virObjectUnref().
> + */
> + while (virPCIDeviceListCount(pcidevs) > 0) {
> + virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, 0);
> + virPCIDeviceListSteal(mgr->activePciHostdevs, dev);
> + }
> +
> +resetvfnetconfig:
> + for (i = 0;
> + last_processed_hostdev_vf != -1 && i < last_processed_hostdev_vf; i++)
> + virHostdevNetConfigRestore(hostdevs[i], mgr->stateDir, NULL);
> +
> +reattachdevs:
> + for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
> + virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
> + virPCIDeviceReattach(dev, mgr->activePciHostdevs, NULL);
> + }
> +
> +cleanup:
> + virObjectUnlock(mgr->activePciHostdevs);
> + virObjectUnlock(mgr->inactivePciHostdevs);
> + virObjectUnref(pcidevs);
> + return ret;
> +}
> +
> +static int
> +virHostdevFindUSBDevice(virDomainHostdevDefPtr hostdev,
> + bool mandatory,
> + virUSBDevicePtr *usb)
> +{
> + unsigned vendor = hostdev->source.subsys.u.usb.vendor;
> + unsigned product = hostdev->source.subsys.u.usb.product;
> + unsigned bus = hostdev->source.subsys.u.usb.bus;
> + unsigned device = hostdev->source.subsys.u.usb.device;
> + bool autoAddress = hostdev->source.subsys.u.usb.autoAddress;
> + int rc;
> +
> + *usb = NULL;
> +
> + if (vendor && bus) {
> + rc = virUSBDeviceFind(vendor, product, bus, device,
> + NULL,
> + autoAddress ? false : mandatory,
> + usb);
> + if (rc < 0) {
> + return -1;
> + } else if (!autoAddress) {
> + goto out;
> + } else {
> + VIR_INFO("USB device %x:%x could not be found at previous"
> + " address (bus:%u device:%u)",
> + vendor, product, bus, device);
> + }
> + }
> +
> + /* When vendor is specified, its USB address is either unspecified or
> the
> + * device could not be found at the USB device where it had been
> + * automatically found before.
> + */
> + if (vendor) {
> + virUSBDeviceListPtr devs;
> +
> + rc = virUSBDeviceFindByVendor(vendor, product, NULL, mandatory,
> &devs);
> + if (rc < 0)
> + return -1;
> +
> + if (rc == 1) {
> + *usb = virUSBDeviceListGet(devs, 0);
> + virUSBDeviceListSteal(devs, *usb);
> + }
> + virObjectUnref(devs);
> +
> + if (rc == 0) {
> + goto out;
> + } else if (rc > 1) {
> + if (autoAddress) {
> + virReportError(VIR_ERR_OPERATION_FAILED,
> + _("Multiple USB devices for %x:%x were
> found, "
> + "but none of them is at bus:%u
> device:%u"),
> + vendor, product, bus, device);
> + } else {
> + virReportError(VIR_ERR_OPERATION_FAILED,
> + _("Multiple USB devices for %x:%x, "
> + "use <address> to specify one"),
> + vendor, product);
> + }
> + return -1;
> + }
> +
> + hostdev->source.subsys.u.usb.bus = virUSBDeviceGetBus(*usb);
> + hostdev->source.subsys.u.usb.device = virUSBDeviceGetDevno(*usb);
> + hostdev->source.subsys.u.usb.autoAddress = true;
> +
> + if (autoAddress) {
> + VIR_INFO("USB device %x:%x found at bus:%u device:%u (moved"
> + " from bus:%u device:%u)",
> + vendor, product,
> + hostdev->source.subsys.u.usb.bus,
> + hostdev->source.subsys.u.usb.device,
> + bus, device);
> + }
> + } else if (!vendor && bus) {
> + if (virUSBDeviceFindByBus(bus, device, NULL, mandatory, usb) < 0)
> + return -1;
> + }
> +
> +out:
> + if (!*usb)
> + hostdev->missing = true;
> + return 0;
> +}
> +
> +static int
> +virHostdevMarkUsbHostdevs(virHostdevManagerPtr mgr,
> + const char *drv_name,
> + const char *dom_name,
> + virUSBDeviceListPtr list)
> +{
> + size_t i, j;
> + unsigned int count;
> + virUSBDevicePtr tmp;
> +
> + virObjectLock(mgr->activeUsbHostdevs);
> + count = virUSBDeviceListCount(list);
> +
> + for (i = 0; i < count; i++) {
> + virUSBDevicePtr usb = virUSBDeviceListGet(list, i);
> + if ((tmp = virUSBDeviceListFind(mgr->activeUsbHostdevs, usb))) {
> + const char *other_drvname;
> + const char *other_domname;
> +
> + virUSBDeviceGetUsedBy(tmp, &other_drvname, &other_domname);
> + if (other_drvname && other_domname)
> + virReportError(VIR_ERR_OPERATION_INVALID,
> + _("USB device %s is in use by "
> + "driver %s,domain %s"),
> + virUSBDeviceGetName(tmp),
> + other_drvname, other_domname);
> + else
> + virReportError(VIR_ERR_OPERATION_INVALID,
> + _("USB device %s is already in use"),
> + virUSBDeviceGetName(tmp));
> + goto error;
> + }
> +
> + virUSBDeviceSetUsedBy(usb, drv_name, dom_name);
> + VIR_DEBUG("Adding %03d.%03d driver= %s dom=%s to
> activeUsbHostdevs",
> + virUSBDeviceGetBus(usb), virUSBDeviceGetDevno(usb),
> + drv_name, dom_name);
> + /*
> + * The caller is responsible to steal these usb devices
> + * from the virUSBDeviceList that passed in on success,
> + * perform rollback on failure.
> + */
> + if (virUSBDeviceListAdd(mgr->activeUsbHostdevs, usb) < 0)
> + goto error;
> + }
> +
> + virObjectUnlock(mgr->activeUsbHostdevs);
> + return 0;
> +
> +error:
> + for (j = 0; j < i; j++) {
> + tmp = virUSBDeviceListGet(list, j);
> + virUSBDeviceListSteal(mgr->activeUsbHostdevs, tmp);
> + }
> + virObjectUnlock(mgr->activeUsbHostdevs);
> + return -1;
> +}
> +
> +int
> +virHostdevPrepareUsbHostdevs(virHostdevManagerPtr mgr,
> + const char *drv_name,
> + const char *dom_name,
> + virDomainHostdevDefPtr *hostdevs,
> + int nhostdevs,
> + bool coldBoot)
> +{
> + size_t i;
> + int ret = -1;
> + virUSBDeviceListPtr list;
> + virUSBDevicePtr tmp;
> +
> + if (!nhostdevs)
> + return 0;
> + if (mgr == NULL)
> + return -1;
> +
> + /* To prevent situation where USB device is assigned to two domains
> + * we need to keep a list of currently assigned USB devices.
> + * This is done in several loops which cannot be joined into one
> + * big loop.
> + */
> + if (!(list = virUSBDeviceListNew()))
> + goto cleanup;
> +
> + /* Loop 1: build temporary list
> + */
> + for (i = 0; i < nhostdevs; i++) {
> + virDomainHostdevDefPtr hostdev = hostdevs[i];
> + bool required = true;
> + virUSBDevicePtr usb;
> +
> + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
> + continue;
> + if (hostdev->source.subsys.type !=
> VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
> + continue;
> +
> + if (hostdev->startupPolicy == VIR_DOMAIN_STARTUP_POLICY_OPTIONAL ||
> + (hostdev->startupPolicy == VIR_DOMAIN_STARTUP_POLICY_REQUISITE &&
> + !coldBoot))
> + required = false;
> +
> + if (virHostdevFindUSBDevice(hostdev, required, &usb) < 0)
> + goto cleanup;
> +
> + if (usb && virUSBDeviceListAdd(list, usb) < 0) {
> + virUSBDeviceFree(usb);
> + goto cleanup;
> + }
> + }
> +
> + /* Mark devices in temporary list as used by @name
> + * and add them do active list. However, if something goes
> + * wrong, perform rollback.
> + */
> + if (virHostdevMarkUsbHostdevs(mgr, drv_name, dom_name, list) < 0)
> + goto cleanup;
> +
> + /* Loop 2: Temporary list was successfully merged with
> + * active list, so steal all items to avoid freeing them
> + * in cleanup label.
> + */
> + while (virUSBDeviceListCount(list) > 0) {
> + tmp = virUSBDeviceListGet(list, 0);
> + virUSBDeviceListSteal(list, tmp);
> + }
> +
> + ret = 0;
> +
> +cleanup:
> + virObjectUnref(list);
> + return ret;
> +}
> +
> +int
> +virHostdevPrepareScsiHostdevs(virHostdevManagerPtr mgr,
> + const char *drv_name,
> + const char *dom_name,
> + virDomainHostdevDefPtr *hostdevs,
> + int nhostdevs)
> +{
> + size_t i, j;
> + int count;
> + virSCSIDeviceListPtr list;
> + virSCSIDevicePtr tmp;
> +
> + if (!nhostdevs)
> + return 0;
> + if (mgr == NULL)
> + return -1;
> +
> + /* To prevent situation where SCSI device is assigned to two domains
> + * we need to keep a list of currently assigned SCSI devices.
> + */
> + if (!(list = virSCSIDeviceListNew()))
> + goto cleanup;
> +
> + /* Loop 1: build temporary list */
> + for (i = 0; i < nhostdevs; i++) {
> + virDomainHostdevDefPtr hostdev = hostdevs[i];
> + virSCSIDevicePtr scsi;
> +
> + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
> + hostdev->source.subsys.type !=
> VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI)
> + continue;
> +
> + if (hostdev->managed) {
> + virReportError(VIR_ERR_XML_ERROR, "%s",
> + _("SCSI host device doesn't support managed
> mode"));
> + goto cleanup;
> + }
> +
> + if (!(scsi = virSCSIDeviceNew(hostdev->source.subsys.u.scsi.adapter,
> + hostdev->source.subsys.u.scsi.bus,
> + hostdev->source.subsys.u.scsi.target,
> + hostdev->source.subsys.u.scsi.unit,
> + hostdev->readonly)))
> + goto cleanup;
> +
> + if (scsi && virSCSIDeviceListAdd(list, scsi) < 0) {
> + virSCSIDeviceFree(scsi);
> + goto cleanup;
> + }
> + }
> +
> + /* Loop 2: Mark devices in temporary list as used by
> + * and add them to driver list. However, if something goes
> + * wrong, perform rollback.
> + */
> + virObjectLock(mgr->activeScsiHostdevs);
> + count = virSCSIDeviceListCount(list);
> +
> + for (i = 0; i < count; i++) {
> + virSCSIDevicePtr scsi = virSCSIDeviceListGet(list, i);
> + if ((tmp = virSCSIDeviceListFind(mgr->activeScsiHostdevs, scsi))) {
> + const char *other_drvname;
> + const char *other_domname;
> +
> + virSCSIDeviceGetUsedBy(tmp, &other_drvname, &other_domname);
> + if (other_drvname && other_domname)
> + virReportError(VIR_ERR_OPERATION_INVALID,
> + _("SCSI device %s is in use by "
> + "driver %s domain %s"),
> + virSCSIDeviceGetName(tmp),
> + other_drvname, other_domname);
> + else
> + virReportError(VIR_ERR_OPERATION_INVALID,
> + _("SCSI device %s is already in use"),
> + virSCSIDeviceGetName(tmp));
> + goto error;
> + }
> +
> + virSCSIDeviceSetUsedBy(scsi, drv_name, dom_name);
> + VIR_DEBUG("Adding %s to activeScsiHostdevs",
> virSCSIDeviceGetName(scsi));
> +
> + if (virSCSIDeviceListAdd(mgr->activeScsiHostdevs, scsi) < 0)
> + goto error;
> + }
> +
> + virObjectUnlock(mgr->activeScsiHostdevs);
> +
> + /* Loop 3: Temporary list was successfully merged with
> + * driver list, so steal all items to avoid freeing them
> + * when freeing temporary list.
> + */
> + while (virSCSIDeviceListCount(list) > 0) {
> + tmp = virSCSIDeviceListGet(list, 0);
> + virSCSIDeviceListSteal(list, tmp);
> + }
> +
> + virObjectUnref(list);
> + return 0;
> +
> +error:
> + for (j = 0; j < i; j++) {
> + tmp = virSCSIDeviceListGet(list, j);
> + virSCSIDeviceListSteal(mgr->activeScsiHostdevs, tmp);
> + }
> + virObjectUnlock(mgr->activeScsiHostdevs);
> +cleanup:
> + virObjectUnref(list);
> + return -1;
> +}
> +
> +int
> +virHostdevPrepareDomainHostdevs(virHostdevManagerPtr mgr,
> + const char *driver,
> + virDomainDefPtr def,
> + unsigned int flags)
> +{
> + if (!def->nhostdevs)
> + return 0;
> +
> + if (mgr == NULL)
> + return -1;
> +
> + if (flags & VIR_SP_PCI_HOSTDEV) {
> + if (virHostdevPreparePciHostdevs(mgr, driver,
> + def->name, def->uuid,
> + def->hostdevs,
> + def->nhostdevs,
> + flags) < 0)
> + return -1;
> + }
> +
> + if (flags & VIR_SP_USB_HOSTDEV) {
> + bool coldBoot = !!(flags & VIR_COLD_BOOT);
> + if (virHostdevPrepareUsbHostdevs(mgr, driver, def->name,
> + def->hostdevs, def->nhostdevs,
> + coldBoot) < 0)
> + return -1;
> + }
> +
> + if (flags & VIR_SP_SCSI_HOSTDEV) {
> + if (virHostdevPrepareScsiHostdevs(mgr, driver, def->name,
> + def->hostdevs, def->nhostdevs) < 0)
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +/*
> + * Pre-condition: mgr->inactivePciHostdevs & mgr->activePciHostdevs
> + * are locked
> + */
> +static void
> +virHostdevReAttachPciDevice(virHostdevManagerPtr mgr, virPCIDevicePtr dev)
> +{
> + /* If the device is not managed and was attached to guest
> + * successfully, it must have been inactive.
> + */
> + if (!virPCIDeviceGetManaged(dev)) {
> + if (virPCIDeviceListAdd(mgr->inactivePciHostdevs, dev) < 0)
> + virPCIDeviceFree(dev);
> + return;
> + }
> +
> + /* Wait for device cleanup if it is qemu/kvm */
> + if (STREQ(virPCIDeviceGetStubDriver(dev), "pci-stub")) {
> + int retries = 100;
> + while (virPCIDeviceWaitForCleanup(dev, "kvm_assigned_device")
> + && retries) {
> + usleep(100*1000);
> + retries--;
> + }
> + }
> +
> + if (virPCIDeviceReattach(dev, mgr->activePciHostdevs,
> + mgr->inactivePciHostdevs) < 0) {
> + virErrorPtr err = virGetLastError();
> + VIR_ERROR(_("Failed to re-attach PCI device: %s"),
> + err ? err->message : _("unknown error"));
> + virResetError(err);
> + }
> + virPCIDeviceFree(dev);
> +}
> +
> +/*
> + * Pre-condition: mgr->activePciHostdevs is locked
> + */
> +static virPCIDeviceListPtr
> +virHostdevGetActivePciHostDeviceList(virHostdevManagerPtr mgr,
> + virDomainHostdevDefPtr *hostdevs,
> + int nhostdevs)
> +{
> + virPCIDeviceListPtr list;
> + size_t i;
> +
> + if (!(list = virPCIDeviceListNew()))
> + return NULL;
> +
> + for (i = 0; i < nhostdevs; i++) {
> + virDomainHostdevDefPtr hostdev = hostdevs[i];
> + virPCIDevicePtr dev;
> + virPCIDevicePtr activeDev;
> +
> + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
> + continue;
> + if (hostdev->source.subsys.type !=
> VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
> + continue;
> +
> + dev = virPCIDeviceNew(hostdev->source.subsys.u.pci.addr.domain,
> + hostdev->source.subsys.u.pci.addr.bus,
> + hostdev->source.subsys.u.pci.addr.slot,
> + hostdev->source.subsys.u.pci.addr.function);
> + if (!dev) {
> + virObjectUnref(list);
> + return NULL;
> + }
> +
> + if ((activeDev = virPCIDeviceListFind(mgr->activePciHostdevs, dev)))
> {
> + if (virPCIDeviceListAdd(list, activeDev) < 0) {
> + virPCIDeviceFree(dev);
> + virObjectUnref(list);
> + return NULL;
> + }
> + }
> +
> + virPCIDeviceFree(dev);
> + }
> +
> + return list;
> +}
> +
> +int
> +virHostdevUpdateActivePciHostdevs(virHostdevManagerPtr mgr,
> + virDomainHostdevDefPtr *hostdevs,
> + int nhostdevs,
> + const char *drv_name,
> + const char *dom_name)
> +{
> + virDomainHostdevDefPtr hostdev = NULL;
> + virPCIDevicePtr dev = NULL;
> + size_t i;
> + int ret = -1;
> +
> + if (!nhostdevs)
> + return 0;
> +
> + if (!mgr)
> + return -1;
> +
> + virObjectLock(mgr->activePciHostdevs);
> + virObjectLock(mgr->inactivePciHostdevs);
> +
> + for (i = 0; i < nhostdevs; i++) {
> + hostdev = hostdevs[i];
> +
> + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
> + continue;
> + if (hostdev->source.subsys.type !=
> VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
> + continue;
> +
> + dev = virPCIDeviceNew(hostdev->source.subsys.u.pci.addr.domain,
> + hostdev->source.subsys.u.pci.addr.bus,
> + hostdev->source.subsys.u.pci.addr.slot,
> + hostdev->source.subsys.u.pci.addr.function);
> +
> + if (!dev)
> + goto cleanup;
> +
> + virPCIDeviceSetManaged(dev, hostdev->managed);
> + switch (hostdev->source.subsys.u.pci.backend) {
> + case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO:
> + if (virPCIDeviceSetStubDriver(dev, "vfio-pci") < 0)
> + goto cleanup;
> + break;
> +
> + case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM :
> + case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT:
> + if (virPCIDeviceSetStubDriver(dev, "pci-stub") < 0)
> + goto cleanup;
> + break;
> + }
> + virPCIDeviceSetUsedBy(dev, drv_name, dom_name);
> +
> + /* Setup the original states for the PCI device */
> + virPCIDeviceSetUnbindFromStub(dev,
> hostdev->origstates.states.pci.unbind_from_stub);
> + virPCIDeviceSetRemoveSlot(dev,
> hostdev->origstates.states.pci.remove_slot);
> + virPCIDeviceSetReprobe(dev, hostdev->origstates.states.pci.reprobe);
> +
> + if (virPCIDeviceListAdd(mgr->activePciHostdevs, dev) < 0)
> + goto cleanup;
> + dev = NULL;
> + }
> +
> + ret = 0;
> +cleanup:
> + virPCIDeviceFree(dev);
> + virObjectUnlock(mgr->activePciHostdevs);
> + virObjectUnlock(mgr->inactivePciHostdevs);
> + return ret;
> +}
> +
> +
> +int
> +virHostdevUpdateActiveUsbHostdevs(virHostdevManagerPtr mgr,
> + virDomainHostdevDefPtr *hostdevs,
> + int nhostdevs,
> + const char *drv_name,
> + const char *dom_name)
> +{
> + virDomainHostdevDefPtr hostdev = NULL;
> + size_t i;
> + int ret = -1;
> +
> + if (!nhostdevs)
> + return 0;
> +
> + if (!mgr)
> + return -1;
> +
> + virObjectLock(mgr->activeUsbHostdevs);
> + for (i = 0; i < nhostdevs; i++) {
> + virUSBDevicePtr usb = NULL;
> + hostdev = hostdevs[i];
> +
> + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
> + continue;
> + if (hostdev->source.subsys.type !=
> VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
> + continue;
> +
> + usb = virUSBDeviceNew(hostdev->source.subsys.u.usb.bus,
> + hostdev->source.subsys.u.usb.device,
> + NULL);
> + if (!usb) {
> + VIR_WARN("Unable to reattach USB device %03d.%03d "
> + "on driver %s domain %s",
> + hostdev->source.subsys.u.usb.bus,
> + hostdev->source.subsys.u.usb.device,
> + drv_name, dom_name);
> + continue;
> + }
> +
> + virUSBDeviceSetUsedBy(usb, drv_name, dom_name);
> +
> + if (virUSBDeviceListAdd(mgr->activeUsbHostdevs, usb) < 0) {
> + virUSBDeviceFree(usb);
> + goto cleanup;
> + }
> + }
> + ret = 0;
> +cleanup:
> + virObjectUnlock(mgr->activeUsbHostdevs);
> + return ret;
> +}
> +
> +int
> +virHostdevUpdateActiveScsiHostdevs(virHostdevManagerPtr mgr,
> + virDomainHostdevDefPtr *hostdevs,
> + int nhostdevs,
> + const char *drv_name,
> + const char *dom_name)
> +{
> + virDomainHostdevDefPtr hostdev = NULL;
> + size_t i;
> + int ret = -1;
> +
> + if (!nhostdevs)
> + return 0;
> +
> + if (!mgr)
> + return -1;
> +
> + virObjectLock(mgr->activeScsiHostdevs);
> + for (i = 0; i < nhostdevs; i++) {
> + virSCSIDevicePtr scsi = NULL;
> + hostdev = hostdevs[i];
> +
> + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
> + hostdev->source.subsys.type !=
> VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI)
> + continue;
> +
> + if (!(scsi = virSCSIDeviceNew(hostdev->source.subsys.u.scsi.adapter,
> + hostdev->source.subsys.u.scsi.bus,
> + hostdev->source.subsys.u.scsi.target,
> + hostdev->source.subsys.u.scsi.unit,
> + hostdev->readonly)))
> + goto cleanup;
> +
> + virSCSIDeviceSetUsedBy(scsi, drv_name, dom_name);
> +
> + if (virSCSIDeviceListAdd(mgr->activeScsiHostdevs, scsi) < 0) {
> + virSCSIDeviceFree(scsi);
> + goto cleanup;
> + }
> + }
> + ret = 0;
> +
> +cleanup:
> + virObjectUnlock(mgr->activeScsiHostdevs);
> + return ret;
> +}
> +
> +int
> +virHostdevUpdateActiveHostdevs(virHostdevManagerPtr mgr,
> + const char *driver,
> + virDomainDefPtr def,
> + unsigned int flags)
> +{
> + if (!def->nhostdevs)
> + return 0;
> +
> + if (flags & VIR_SP_PCI_HOSTDEV) {
> + if (virHostdevUpdateActivePciHostdevs(mgr,
> + def->hostdevs,
> + def->nhostdevs,
> + driver, def->name) < 0)
> + return -1;
> + }
> +
> + if (flags & VIR_SP_USB_HOSTDEV) {
> + if (virHostdevUpdateActiveUsbHostdevs(mgr,
> + def->hostdevs,
> + def->nhostdevs,
> + driver, def->name) < 0)
> + return -1;
> + }
> +
> + if (flags & VIR_SP_SCSI_HOSTDEV) {
> + if (virHostdevUpdateActiveScsiHostdevs(mgr,
> + def->hostdevs,
> + def->nhostdevs,
> + driver, def->name) < 0)
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +
> +void
> +virHostdevReAttachPciHostdevs(virHostdevManagerPtr mgr,
> + const char *drv_name,
> + const char *dom_name,
> + virDomainHostdevDefPtr *hostdevs,
> + int nhostdevs)
> +{
> + virPCIDeviceListPtr pcidevs;
> + size_t i;
> + char *oldStateDir = NULL;
> +
> + if (!nhostdevs || !mgr)
> + return;
> +
> + virObjectLock(mgr->activePciHostdevs);
> + virObjectLock(mgr->inactivePciHostdevs);
> +
> + /* for upgrade, if netconfig file is not found in mgr->stateDir,
> + * find in old state dir */
> + if (VIR_STRDUP(oldStateDir, QEMU_STATE_DIR) < 0)
> + goto cleanup;
> +
> + if (!(pcidevs = virHostdevGetActivePciHostDeviceList(mgr,
> + hostdevs,
> + nhostdevs))) {
> + virErrorPtr err = virGetLastError();
> + VIR_ERROR(_("Failed to allocate PCI device list: %s"),
> + err ? err->message : _("unknown error"));
> + virResetError(err);
> + goto cleanup;
> + }
> +
> + /* Again 4 loops; mark all devices as inactive before reset
> + * them and reset all the devices before re-attach.
> + * Attach mac and port profile parameters to devices
> + */
> + for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
> + virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
> + virPCIDevicePtr activeDev = NULL;
> + const char *usedby_drvname;
> + const char *usedby_domname;
> +
> + /* Never delete the dev from list driver->activePciHostdevs
> + * if it's used by other domain.
> + */
> + activeDev = virPCIDeviceListFind(mgr->activePciHostdevs, dev);
> + if (activeDev) {
> + virPCIDeviceGetUsedBy(activeDev, &usedby_drvname,
> &usedby_domname);
> + if (STRNEQ_NULLABLE(drv_name, usedby_drvname) ||
> + STRNEQ_NULLABLE(dom_name, usedby_domname)) {
> + virPCIDeviceListSteal(pcidevs, dev);
> + continue;
> + }
> + }
> +
> + virPCIDeviceListSteal(mgr->activePciHostdevs, dev);
> + }
> +
> + /*
> + * For SRIOV net host devices, unset mac and port profile before
> + * reset and reattach device
> + */
> + for (i = 0; i < nhostdevs; i++)
> + virHostdevNetConfigRestore(hostdevs[i], mgr->stateDir, oldStateDir);
> +
> + for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
> + virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
> + if (virPCIDeviceReset(dev, mgr->activePciHostdevs,
> + mgr->inactivePciHostdevs) < 0) {
> + virErrorPtr err = virGetLastError();
> + VIR_ERROR(_("Failed to reset PCI device: %s"),
> + err ? err->message : _("unknown error"));
> + virResetError(err);
> + }
> + }
> +
> + while (virPCIDeviceListCount(pcidevs) > 0) {
> + virPCIDevicePtr dev = virPCIDeviceListStealIndex(pcidevs, 0);
> + virHostdevReAttachPciDevice(mgr, dev);
> + }
> +
> + virObjectUnref(pcidevs);
> +cleanup:
> + VIR_FREE(oldStateDir);
> + virObjectUnlock(mgr->activePciHostdevs);
> + virObjectUnlock(mgr->inactivePciHostdevs);
> +}
> +
> +void
> +virHostdevReAttachUsbHostdevs(virHostdevManagerPtr mgr,
> + const char *drv_name,
> + const char *dom_name,
> + virDomainHostdevDefPtr *hostdevs,
> + int nhostdevs)
> +{
> + size_t i;
> +
> + if (!nhostdevs || !mgr)
> + return;
> +
> + virObjectLock(mgr->activeUsbHostdevs);
> + for (i = 0; i < nhostdevs; i++) {
> + virDomainHostdevDefPtr hostdev = hostdevs[i];
> + virUSBDevicePtr usb, tmp;
> + const char *usedby_drvname;
> + const char *usedby_domname;
> +
> + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
> + continue;
> + if (hostdev->source.subsys.type !=
> VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
> + continue;
> + if (hostdev->missing)
> + continue;
> +
> + usb = virUSBDeviceNew(hostdev->source.subsys.u.usb.bus,
> + hostdev->source.subsys.u.usb.device,
> + NULL);
> +
> + if (!usb) {
> + VIR_WARN("Unable to reattach USB device %03d.%03d "
> + "on driver %s domain %s",
> + hostdev->source.subsys.u.usb.bus,
> + hostdev->source.subsys.u.usb.device,
> + drv_name, dom_name);
> + continue;
> + }
> +
> + /* Delete only those USB devices which belongs
> + * to domain. Therefore we want to steal only
> + * those devices from the list which were taken
> + * by domain */
> +
> + tmp = virUSBDeviceListFind(mgr->activeUsbHostdevs, usb);
> + virUSBDeviceFree(usb);
> +
> + if (!tmp) {
> + VIR_WARN("Unable to find device %03d.%03d "
> + "in list of active USB devices",
> + hostdev->source.subsys.u.usb.bus,
> + hostdev->source.subsys.u.usb.device);
> + continue;
> + }
> +
> + virUSBDeviceGetUsedBy(tmp, &usedby_drvname, &usedby_domname);
> + if (STREQ_NULLABLE(drv_name, usedby_drvname) &&
> + STREQ_NULLABLE(dom_name, usedby_domname)) {
> + VIR_DEBUG("Removing %03d.%03d dom=%s:%s",
> + hostdev->source.subsys.u.usb.bus,
> + hostdev->source.subsys.u.usb.device,
> + drv_name, dom_name);
> + virUSBDeviceListDel(mgr->activeUsbHostdevs, tmp);
> + }
> +
> + }
> +
> + virObjectUnlock(mgr->activeUsbHostdevs);
> +}
> +
> +void
> +virHostdevReAttachScsiHostdevs(virHostdevManagerPtr mgr,
> + const char *drv_name,
> + const char *dom_name,
> + virDomainHostdevDefPtr *hostdevs,
> + int nhostdevs)
> +{
> + size_t i;
> +
> + if (!nhostdevs || !mgr)
> + return;
> +
> + virObjectLock(mgr->activeScsiHostdevs);
> + for (i = 0; i < nhostdevs; i++) {
> + virDomainHostdevDefPtr hostdev = hostdevs[i];
> + virSCSIDevicePtr scsi, tmp;
> + const char *usedby_drvname;
> + const char *usedby_domname;
> +
> + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
> + hostdev->source.subsys.type !=
> VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI)
> + continue;
> +
> + if (!(scsi = virSCSIDeviceNew(hostdev->source.subsys.u.scsi.adapter,
> + hostdev->source.subsys.u.scsi.bus,
> + hostdev->source.subsys.u.scsi.target,
> + hostdev->source.subsys.u.scsi.unit,
> + hostdev->readonly))) {
> + VIR_WARN("Unable to reattach SCSI device %s:%d:%d:%d on driver
> %s domain %s",
> + hostdev->source.subsys.u.scsi.adapter,
> + hostdev->source.subsys.u.scsi.bus,
> + hostdev->source.subsys.u.scsi.target,
> + hostdev->source.subsys.u.scsi.unit,
> + drv_name, dom_name);
> + continue;
> + }
> +
> + tmp = virSCSIDeviceListFind(mgr->activeScsiHostdevs, scsi);
> + virSCSIDeviceFree(scsi);
> +
> + if (!tmp) {
> + VIR_WARN("Unable to find device %s:%d:%d:%d "
> + "in list of active SCSI devices",
> + hostdev->source.subsys.u.scsi.adapter,
> + hostdev->source.subsys.u.scsi.bus,
> + hostdev->source.subsys.u.scsi.target,
> + hostdev->source.subsys.u.scsi.unit);
> + continue;
> + }
> +
> + virSCSIDeviceGetUsedBy(tmp, &usedby_drvname, &usedby_domname);
> + if (STREQ_NULLABLE(usedby_drvname, drv_name) &&
> + STREQ_NULLABLE(usedby_domname, dom_name)) {
> + VIR_DEBUG("Removing %s:%d:%d:%d driver:%s dom:%s from
> activeScsiHostdevs",
> + hostdev->source.subsys.u.scsi.adapter,
> + hostdev->source.subsys.u.scsi.bus,
> + hostdev->source.subsys.u.scsi.target,
> + hostdev->source.subsys.u.scsi.unit,
> + drv_name, dom_name);
> + virSCSIDeviceListDel(mgr->activeScsiHostdevs, tmp);
> + }
> + }
> +
> + virObjectUnlock(mgr->activeScsiHostdevs);
> +}
> +
> +void
> +virHostdevReAttachDomainHostdevs(virHostdevManagerPtr mgr,
> + const char *driver,
> + virDomainDefPtr def,
> + unsigned int flags)
> +{
> + if (!def->nhostdevs || !mgr)
> + return;
> +
> + if (flags & VIR_SP_PCI_HOSTDEV) {
> + virHostdevReAttachPciHostdevs(mgr, driver, def->name,
> + def->hostdevs, def->nhostdevs);
> + }
> +
> + if (flags & VIR_SP_USB_HOSTDEV) {
> + virHostdevReAttachUsbHostdevs(mgr, driver, def->name,
> + def->hostdevs, def->nhostdevs);
> + }
> +
> + if (flags & VIR_SP_SCSI_HOSTDEV) {
> + virHostdevReAttachScsiHostdevs(mgr, driver, def->name,
> + def->hostdevs, def->nhostdevs);
> + }
> +}
> +
> +/* following functions are used by NodeDevDetach/Reattach/Reset */
> +int
> +virHostdevPciNodeDeviceDetach(virHostdevManagerPtr mgr,
> + virPCIDevicePtr pci)
> +{
> + int ret;
> +
> + if (!mgr || !pci)
> + return -1;
> +
> + virObjectLock(mgr->activePciHostdevs);
> + virObjectLock(mgr->inactivePciHostdevs);
> + if (virPCIDeviceDetach(pci, mgr->activePciHostdevs,
> + mgr->inactivePciHostdevs) < 0)
> + ret = -1;
> + else
> + ret = 0;
> +
> + virObjectUnlock(mgr->inactivePciHostdevs);
> + virObjectUnlock(mgr->activePciHostdevs);
> + return ret;
> +}
> +
> +int
> +virHostdevPciNodeDeviceReAttach(virHostdevManagerPtr mgr,
> + virPCIDevicePtr pci)
> +{
> + int ret = -1;
> + virPCIDevicePtr other;
> +
> + if (!mgr || !pci)
> + return -1;
> +
> + virObjectLock(mgr->activePciHostdevs);
> + virObjectLock(mgr->inactivePciHostdevs);
> + other = virPCIDeviceListFind(mgr->activePciHostdevs, pci);
> + if (other) {
> + const char *other_drvname;
> + const char *other_domname;
> +
> + virPCIDeviceGetUsedBy(other, &other_drvname, &other_domname);
> + if (other_drvname && other_domname)
> + virReportError(VIR_ERR_OPERATION_INVALID,
> + _("PCI device %s is still in use by driver %s,
> domain %s"),
> + virPCIDeviceGetName(pci), other_drvname,
> other_domname);
> + else
> + virReportError(VIR_ERR_OPERATION_INVALID,
> + _("PCI device %s is still in use"),
> + virPCIDeviceGetName(pci));
> + goto out;
> + }
> +
> + virPCIDeviceReattachInit(pci);
> +
> + if (virPCIDeviceReattach(pci, mgr->activePciHostdevs,
> + mgr->inactivePciHostdevs) < 0)
> + goto out;
> +
> + ret = 0;
> +out:
> + virObjectUnlock(mgr->inactivePciHostdevs);
> + virObjectUnlock(mgr->activePciHostdevs);
> + return ret;
> +}
> +
> +int
> +virHostdevPciNodeDeviceReset(virHostdevManagerPtr mgr,
> + virPCIDevicePtr pci)
> +{
> + int ret;
> +
> + if (!mgr || !pci)
> + return -1;
> +
> + virObjectLock(mgr->activePciHostdevs);
> + virObjectLock(mgr->inactivePciHostdevs);
> + if (virPCIDeviceReset(pci, mgr->activePciHostdevs,
> + mgr->inactivePciHostdevs) < 0)
> + ret = -1;
> + else
> + ret = 0;
> +
> + virObjectUnlock(mgr->inactivePciHostdevs);
> + virObjectUnlock(mgr->activePciHostdevs);
> + return ret;
> +}
> diff --git a/src/util/virhostdev.h b/src/util/virhostdev.h
> new file mode 100644
> index 0000000..fc69540
> --- /dev/null
> +++ b/src/util/virhostdev.h
> @@ -0,0 +1,134 @@
> +/* virhostdev.h: hostdev management
> + *
> + * Copyright (C) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany.
> + * Copyright (C) 2006-2007, 2009-2013 Red Hat, Inc.
> + * Copyright (C) 2006 Daniel P. Berrange
> + *
> + * 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: Chunyan Liu <cyliu(a)suse.com>
> + * Author: Daniel P. Berrange <berrange(a)redhat.com>
> + */
> +
> +#ifndef __VIR_HOSTDEV_H__
> +# define __VIR_HOSTDEV_H__
> +
> +# include "internal.h"
> +
> +# include "domain_conf.h"
> +# include "virpci.h"
> +# include "virusb.h"
> +# include "virscsi.h"
> +
> +typedef enum {
> + VIR_SP_PCI_HOSTDEV = (1 << 0), /* support pci passthrough */
> + VIR_SP_USB_HOSTDEV = (1 << 1), /* support usb passthrough */
> + VIR_SP_SCSI_HOSTDEV = (1 << 2), /* support scsi passthrough */
> +
> + VIR_COLD_BOOT = (1 << 8), /* cold boot */
> + VIR_STRICT_ACS_CHECK = (1 << 9), /* strict acs check */
> +} virHostdevManagerFlag;
> +
> +typedef struct _virHostdevManager virHostdevManager;
> +typedef virHostdevManager *virHostdevManagerPtr;
> +struct _virHostdevManager{
> + char *stateDir;
> +
> + virPCIDeviceListPtr activePciHostdevs;
> + virPCIDeviceListPtr inactivePciHostdevs;
> + virUSBDeviceListPtr activeUsbHostdevs;
> + virSCSIDeviceListPtr activeScsiHostdevs;
> +};
> +
> +virHostdevManagerPtr virHostdevManagerGetDefault(void);
> +
> +bool virHostdevHostSupportsPassthroughVFIO(void);
> +bool virHostdevHostSupportsPassthroughKVM(void);
> +
> +/* functions used to prepare/unprepare hostdevs for domain */
> +int virHostdevPrepareDomainHostdevs(virHostdevManagerPtr mgr,
> + const char *driver,
> + virDomainDefPtr def,
> + unsigned int flags);
> +void virHostdevReAttachDomainHostdevs(virHostdevManagerPtr mgr,
> + const char *driver,
> + virDomainDefPtr def,
> + unsigned int flags);
> +int virHostdevPreparePciHostdevs(virHostdevManagerPtr mgr,
> + const char *drv_name,
> + const char *dom_name,
> + const unsigned char *uuid,
> + virDomainHostdevDefPtr *hostdevs,
> + int nhostdevs,
> + unsigned int flags);
> +int virHostdevPrepareUsbHostdevs(virHostdevManagerPtr mgr,
> + const char *drv_name,
> + const char *dom_name,
> + virDomainHostdevDefPtr *hostdevs,
> + int nhostdevs,
> + bool coldBoot);
> +int virHostdevPrepareScsiHostdevs(virHostdevManagerPtr mgr,
> + const char *drv_name,
> + const char *dom_name,
> + virDomainHostdevDefPtr *hostdevs,
> + int nhostdevs);
> +void virHostdevReAttachPciHostdevs(virHostdevManagerPtr mgr,
> + const char *drv_name,
> + const char *dom_name,
> + virDomainHostdevDefPtr *hostdevs,
> + int nhostdevs);
> +void virHostdevReAttachUsbHostdevs(virHostdevManagerPtr mgr,
> + const char *drv_name,
> + const char *dom_name,
> + virDomainHostdevDefPtr *hostdevs,
> + int nhostdevs);
> +void virHostdevReAttachScsiHostdevs(virHostdevManagerPtr mgr,
> + const char *drv_name,
> + const char *dom_name,
> + virDomainHostdevDefPtr *hostdevs,
> + int nhostdevs);
> +int
> +virHostdevUpdateActivePciHostdevs(virHostdevManagerPtr mgr,
> + virDomainHostdevDefPtr *hostdevs,
> + int nhostdevs,
> + const char *drv_name,
> + const char *dom_name);
> +int
> +virHostdevUpdateActiveUsbHostdevs(virHostdevManagerPtr mgr,
> + virDomainHostdevDefPtr *hostdevs,
> + int nhostdevs,
> + const char *drv_name,
> + const char *dom_name);
> +int
> +virHostdevUpdateActiveScsiHostdevs(virHostdevManagerPtr mgr,
> + virDomainHostdevDefPtr *hostdevs,
> + int nhostdevs,
> + const char *drv_name,
> + const char *dom_name);
> +int
> +virHostdevUpdateActiveHostdevs(virHostdevManagerPtr mgr,
> + const char *driver,
> + virDomainDefPtr def,
> + unsigned int flags);
> +
> +/* functions used by NodeDevDetach/Reattach/Reset */
> +int virHostdevPciNodeDeviceDetach(virHostdevManagerPtr mgr,
> + virPCIDevicePtr pci);
> +int virHostdevPciNodeDeviceReAttach(virHostdevManagerPtr mgr,
> + virPCIDevicePtr pci);
> +int virHostdevPciNodeDeviceReset(virHostdevManagerPtr mgr,
> + virPCIDevicePtr pci);
> +
> +#endif /* __VIR_HOSTDEV_H__ */
> diff --git a/src/util/virpci.c b/src/util/virpci.c
> index 8ec642f..7402898 100644
> --- a/src/util/virpci.c
> +++ b/src/util/virpci.c
> @@ -58,7 +58,10 @@ struct _virPCIDevice {
> char name[PCI_ADDR_LEN]; /* domain:bus:slot.function */
> char id[PCI_ID_LEN]; /* product vendor */
> char *path;
> - const char *used_by; /* The domain which uses the device */
> +
> + /* The driver:domain which uses the device */
> + char *used_by_drvname;
> + char *used_by_domname;
>
> unsigned int pcie_cap_pos;
> unsigned int pci_pm_cap_pos;
> @@ -1562,6 +1565,8 @@ virPCIDeviceFree(virPCIDevicePtr dev)
> VIR_DEBUG("%s %s: freeing", dev->id, dev->name);
> VIR_FREE(dev->path);
> VIR_FREE(dev->stubDriver);
> + VIR_FREE(dev->used_by_drvname);
> + VIR_FREE(dev->used_by_domname);
> VIR_FREE(dev);
> }
>
> @@ -1631,16 +1636,27 @@ virPCIDeviceSetReprobe(virPCIDevicePtr dev, bool
> reprobe)
> dev->reprobe = reprobe;
> }
>
> -void
> -virPCIDeviceSetUsedBy(virPCIDevicePtr dev, const char *name)
> +int
> +virPCIDeviceSetUsedBy(virPCIDevicePtr dev,
> + const char *drv_name,
> + const char *dom_name)
> {
> - dev->used_by = name;
> + if (VIR_STRDUP(dev->used_by_drvname, drv_name) < 0)
> + return -1;
> +
> + if (VIR_STRDUP(dev->used_by_domname, dom_name) < 0)
> + return -1;
> +
> + return 0;
> }
>
> -const char *
> -virPCIDeviceGetUsedBy(virPCIDevicePtr dev)
> +void
> +virPCIDeviceGetUsedBy(virPCIDevicePtr dev,
> + const char **drv_name,
> + const char **dom_name)
> {
> - return dev->used_by;
> + *drv_name = dev->used_by_drvname;
> + *dom_name = dev->used_by_domname;
> }
>
> void virPCIDeviceReattachInit(virPCIDevicePtr pci)
> diff --git a/src/util/virpci.h b/src/util/virpci.h
> index 0479f0b..2347b95 100644
> --- a/src/util/virpci.h
> +++ b/src/util/virpci.h
> @@ -65,9 +65,12 @@ unsigned int virPCIDeviceGetManaged(virPCIDevice *dev);
> int virPCIDeviceSetStubDriver(virPCIDevicePtr dev,
> const char *driver);
> const char *virPCIDeviceGetStubDriver(virPCIDevicePtr dev);
> -void virPCIDeviceSetUsedBy(virPCIDevice *dev,
> - const char *used_by);
> -const char *virPCIDeviceGetUsedBy(virPCIDevice *dev);
> +int virPCIDeviceSetUsedBy(virPCIDevice *dev,
> + const char *drv_name,
> + const char *dom_name);
> +void virPCIDeviceGetUsedBy(virPCIDevice *dev,
> + const char **drv_name,
> + const char **dom_name);
> unsigned int virPCIDeviceGetUnbindFromStub(virPCIDevicePtr dev);
> void virPCIDeviceSetUnbindFromStub(virPCIDevice *dev,
> bool unbind);
> diff --git a/src/util/virscsi.c b/src/util/virscsi.c
> index 7aca9e6..062e8bd 100644
> --- a/src/util/virscsi.c
> +++ b/src/util/virscsi.c
> @@ -55,7 +55,10 @@ struct _virSCSIDevice {
> char *name; /* adapter:bus:target:unit */
> char *id; /* model:vendor */
> char *sg_path; /* e.g. /dev/sg2 */
> - const char *used_by; /* name of the domain using this dev */
> +
> + /* driver:domain using this dev */
> + char *used_by_drvname;
> + char *used_by_domname;
>
> bool readonly;
> };
> @@ -259,20 +262,31 @@ virSCSIDeviceFree(virSCSIDevicePtr dev)
> VIR_FREE(dev->id);
> VIR_FREE(dev->name);
> VIR_FREE(dev->sg_path);
> + VIR_FREE(dev->used_by_drvname);
> + VIR_FREE(dev->used_by_domname);
> VIR_FREE(dev);
> }
>
> -void
> +int
> virSCSIDeviceSetUsedBy(virSCSIDevicePtr dev,
> - const char *name)
> + const char *drvname,
> + const char *domname)
> {
> - dev->used_by = name;
> + if (VIR_STRDUP(dev->used_by_drvname, drvname) < 0)
> + return -1;
> + if (VIR_STRDUP(dev->used_by_domname, domname) < 0)
> + return -1;
> +
> + return 0;
> }
>
> -const char *
> -virSCSIDeviceGetUsedBy(virSCSIDevicePtr dev)
> +void
> +virSCSIDeviceGetUsedBy(virSCSIDevicePtr dev,
> + const char **drvname,
> + const char **domname)
> {
> - return dev->used_by;
> + *drvname = dev->used_by_drvname;
> + *domname = dev->used_by_domname;
> }
>
> const char *
> diff --git a/src/util/virscsi.h b/src/util/virscsi.h
> index cce5df4..263b175 100644
> --- a/src/util/virscsi.h
> +++ b/src/util/virscsi.h
> @@ -49,8 +49,12 @@ virSCSIDevicePtr virSCSIDeviceNew(const char *adapter,
> bool readonly);
>
> void virSCSIDeviceFree(virSCSIDevicePtr dev);
> -void virSCSIDeviceSetUsedBy(virSCSIDevicePtr dev, const char *name);
> -const char *virSCSIDeviceGetUsedBy(virSCSIDevicePtr dev);
> +int virSCSIDeviceSetUsedBy(virSCSIDevicePtr dev,
> + const char *drvname,
> + const char *domname);
> +void virSCSIDeviceGetUsedBy(virSCSIDevicePtr dev,
> + const char **drvname,
> + const char **domname);
> const char *virSCSIDeviceGetName(virSCSIDevicePtr dev);
> unsigned int virSCSIDeviceGetAdapter(virSCSIDevicePtr dev);
> unsigned int virSCSIDeviceGetBus(virSCSIDevicePtr dev);
> diff --git a/src/util/virusb.c b/src/util/virusb.c
> index 3c82200..7b17b0a 100644
> --- a/src/util/virusb.c
> +++ b/src/util/virusb.c
> @@ -55,7 +55,10 @@ struct _virUSBDevice {
> char name[USB_ADDR_LEN]; /* domain:bus:slot.function */
> char id[USB_ID_LEN]; /* product vendor */
> char *path;
> - const char *used_by; /* name of the domain using this dev
> */
> +
> + /* driver:domain using this dev */
> + char *used_by_drvname;
> + char *used_by_domname;
> };
>
> struct _virUSBDeviceList {
> @@ -375,19 +378,31 @@ virUSBDeviceFree(virUSBDevicePtr dev)
> return;
> VIR_DEBUG("%s %s: freeing", dev->id, dev->name);
> VIR_FREE(dev->path);
> + VIR_FREE(dev->used_by_drvname);
> + VIR_FREE(dev->used_by_domname);
> VIR_FREE(dev);
> }
>
> -
> -void virUSBDeviceSetUsedBy(virUSBDevicePtr dev,
> - const char *name)
> +int
> +virUSBDeviceSetUsedBy(virUSBDevicePtr dev,
> + const char *drv_name,
> + const char *dom_name)
> {
> - dev->used_by = name;
> + if (VIR_STRDUP(dev->used_by_drvname, drv_name) < 0)
> + return -1;
> + if (VIR_STRDUP(dev->used_by_domname, dom_name) < 0)
> + return -1;
> +
> + return 0;
> }
>
> -const char * virUSBDeviceGetUsedBy(virUSBDevicePtr dev)
> +void
> +virUSBDeviceGetUsedBy(virUSBDevicePtr dev,
> + const char **drv_name,
> + const char **dom_name)
> {
> - return dev->used_by;
> + *drv_name = dev->used_by_drvname;
> + *dom_name = dev->used_by_domname;
> }
>
> const char *virUSBDeviceGetName(virUSBDevicePtr dev)
> diff --git a/src/util/virusb.h b/src/util/virusb.h
> index aa59d12..41e680f 100644
> --- a/src/util/virusb.h
> +++ b/src/util/virusb.h
> @@ -60,8 +60,12 @@ int virUSBDeviceFind(unsigned int vendor,
> virUSBDevicePtr *usb);
>
> void virUSBDeviceFree(virUSBDevicePtr dev);
> -void virUSBDeviceSetUsedBy(virUSBDevicePtr dev, const char *name);
> -const char *virUSBDeviceGetUsedBy(virUSBDevicePtr dev);
> +int virUSBDeviceSetUsedBy(virUSBDevicePtr dev,
> + const char *drv_name,
> + const char *dom_name);
> +void virUSBDeviceGetUsedBy(virUSBDevicePtr dev,
> + const char **drv_name,
> + const char **dom_name);
> const char *virUSBDeviceGetName(virUSBDevicePtr dev);
>
> unsigned int virUSBDeviceGetBus(virUSBDevicePtr dev);
1
0
All,
This is a release notification for ruby-libvirt 0.5.2.
ruby-libvirt is a ruby wrapper around the libvirt API. The changelog
between 0.5.1 and 0.5.2 is:
* Fix to make sure we don't free more entries than retrieved (potential crash)
Version 0.5.2 is available from http://libvirt.org/ruby:
Tarball: http://libvirt.org/ruby/download/ruby-libvirt-0.5.2.tgz
Gem: http://libvirt.org/ruby/download/ruby-libvirt-0.5.2.gem
It is also available from rubygems.org; to get the latest version, run:
$ gem install ruby-libvirt
As usual, if you run into questions, problems, or bugs, please feel free to
mail me (clalancette gmail com) and the libvirt mailing list.
Thanks to Guido Günther for the patch to fix this problem.
1
0