Devel
Threads by month
- ----- 2026 -----
- 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
- 38 participants
- 40204 discussions
Hi everyone
I'm using Ubuntu 12.04.3 LTS with the Xen hypervisor
installed (package version: 4.1.2-2ubuntu2.10),
and Libvirt v0.10.2.2 (that interacts with Xen through
the libxl driver).
I performed some adjustments to have the required
features:
- Switch from Xend to libxl:
I created upstart jobs for xenstored and xenconsoled
so that necessary daemons are started earlier enough
and Libvirt can contact the hypervisor through libxl.
- Add support for Open vSwitch:
I added the script 'vif-openvswitch', taken from
the master branch of the GIT repository, to the
/etc/xen/scripts directory in order to plug network
interfaces to Open vSwitch switches.
I know that the support for libxl is experimental
in Xen 4.1, but I'm wondering if someone has a solution
to the following issues:
1) On domain destroy, the host configuration is not clean:
if the flag 'force' is set to 0 some entries in the
xenstored database are not removed (console, ...)
if the flag 'force' is set to 1 (as it is done
in Libvirt), the event 'online' associated to the
network interface is not triggered and, thus, the
vif is not removed from the Open vSwitch switch.
To fix this issue, I temporarily added a call
to vif-openvswitch into the xen-hotplug-cleanup script.
2) When a domain is started from Libvirt, the console
source path does not appear in the output of the
command 'virsh dumpxml instance-00000381'
3) Sometimes, a domU is not started at all. If I start
a virtual machine from Libvirt through virsh or directly
through xl, these tools report that the virtual machine
is running but I see no messages coming from the console
and the CPU time remains fixed.
I'm attaching some files that may be useful to understand
the problem:
- libvirt.xml: domain specifications (Libvirt format)
- domain.xl: domain specifications (Xen format)
- libvirt_virsh_dumpxml.log: output of the command
'virsh dumpxml instance-00000381'
- xl_create.log: output of the command 'xl create -d domain.xl'
- xl_info.log: output of the command 'xl info'
- qemu-dm-instance-00000381.log: qemu-dm log
- syslog_vif6_0.log: vif attach/detach logs from /var/log/syslog
- xenstore-db-not-clean.log: xenstore db entries not removed
after 'xl destroy'
- libvirt_libxl.log: log from /var/log/libvirt/libxl.log
after the execution of the command 'virsh create libvirt.xml'
Lastly, I want to add that the image I'm using for the tests
is Ubuntu Precise 12.04.3 LTS, taken from the URL:
http://cloud-images.ubuntu.com/precise/current/precise-server-cloudimg-amd6…
and the kernel is taken from the URL:
http://cloud-images.ubuntu.com/precise/current/unpacked/precise-server-clou…
Thanks
Roberto Sassu
2
2
12 Sep '13
From: "Daniel P. Berrange" <berrange(a)redhat.com>
The change to query org.freedesktop.DBus.ListActivatableNames
to detect systemd broke the test suite, since we did not have
stubs to respond to this dbus call.
Signed-off-by: Daniel P. Berrange <berrange(a)redhat.com>
---
tests/virsystemdmock.c | 54 +++++++++++++++++++++++++++++++++-----------------
tests/virsystemdtest.c | 4 ++++
2 files changed, 40 insertions(+), 18 deletions(-)
Pushed under build break rule.
diff --git a/tests/virsystemdmock.c b/tests/virsystemdmock.c
index 5dbd33f..59b312d 100644
--- a/tests/virsystemdmock.c
+++ b/tests/virsystemdmock.c
@@ -65,29 +65,47 @@ dbus_bool_t dbus_message_set_reply_serial(DBusMessage *message ATTRIBUTE_UNUSED,
}
DBusMessage *dbus_connection_send_with_reply_and_block(DBusConnection *connection ATTRIBUTE_UNUSED,
- DBusMessage *message ATTRIBUTE_UNUSED,
+ DBusMessage *message,
int timeout_milliseconds ATTRIBUTE_UNUSED,
- DBusError *error)
+ DBusError *error ATTRIBUTE_UNUSED)
{
DBusMessage *reply = NULL;
+ const char *service = dbus_message_get_destination(message);
- if (getenv("FAIL_BAD_SERVICE")) {
- DBusMessageIter iter;
- const char *error_message = "Something went wrong creating the machine";
- if (!(reply = dbus_message_new(DBUS_MESSAGE_TYPE_ERROR)))
- return NULL;
- dbus_message_set_error_name(reply, "org.freedesktop.systemd.badthing");
- dbus_message_iter_init_append(reply, &iter);
- if (!dbus_message_iter_append_basic(&iter,
- DBUS_TYPE_STRING,
- &error_message)) {
- dbus_message_unref(reply);
- return NULL;
+ if (STREQ(service, "org.freedesktop.machine1")) {
+ if (getenv("FAIL_BAD_SERVICE")) {
+ DBusMessageIter iter;
+ const char *error_message = "Something went wrong creating the machine";
+ if (!(reply = dbus_message_new(DBUS_MESSAGE_TYPE_ERROR)))
+ return NULL;
+ dbus_message_set_error_name(reply, "org.freedesktop.systemd.badthing");
+ dbus_message_iter_init_append(reply, &iter);
+ if (!dbus_message_iter_append_basic(&iter,
+ DBUS_TYPE_STRING,
+ &error_message)) {
+ dbus_message_unref(reply);
+ return NULL;
+ }
+ } else {
+ reply = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN);
}
- } else if (getenv("FAIL_NO_SERVICE")) {
- dbus_set_error(error,
- "org.freedesktop.DBus.Error.ServiceUnknown",
- "%s", "The name org.freedesktop.machine1 was not provided by any .service files");
+ } else if (STREQ(service, "org.freedesktop.DBus")) {
+ const char *svc1 = "org.foo.bar.wizz";
+ const char *svc2 = "org.freedesktop.machine1";
+ DBusMessageIter iter, sub;
+ reply = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ "s", &sub);
+
+ dbus_message_iter_append_basic(&sub,
+ DBUS_TYPE_STRING,
+ &svc1);
+ if (!getenv("FAIL_NO_SERVICE"))
+ dbus_message_iter_append_basic(&sub,
+ DBUS_TYPE_STRING,
+ &svc2);
+ dbus_message_iter_close_container(&iter, &sub);
} else {
reply = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN);
}
diff --git a/tests/virsystemdtest.c b/tests/virsystemdtest.c
index a9c6d32..7dc7520 100644
--- a/tests/virsystemdtest.c
+++ b/tests/virsystemdtest.c
@@ -94,9 +94,11 @@ static int testCreateNoSystemd(const void *opaque ATTRIBUTE_UNUSED)
123,
false,
NULL)) == 0) {
+ unsetenv("FAIL_NO_SERVICE");
fprintf(stderr, "%s", "Unexpected create machine success\n");
return -1;
}
+ unsetenv("FAIL_NO_SERVICE");
if (rv != -2) {
fprintf(stderr, "%s", "Unexpected create machine error\n");
@@ -126,9 +128,11 @@ static int testCreateBadSystemd(const void *opaque ATTRIBUTE_UNUSED)
123,
false,
NULL)) == 0) {
+ unsetenv("FAIL_BAD_SERVICE");
fprintf(stderr, "%s", "Unexpected create machine success\n");
return -1;
}
+ unsetenv("FAIL_BAD_SERVICE");
if (rv != -1) {
fprintf(stderr, "%s", "Unexpected create machine error\n");
--
1.8.3.1
3
2
12 Sep '13
Currently users are required to pre-create storage on their own upon migration.
This patch set implements the feature for RAW, QCOW and QCOW2 images. While for
the RAW fallocate() is used (so we are guaranteed subsequent write() won't fail
with ENOSPC, for the latter two we have no other option than using qemu-img,
which uses ftruncate(). On the other hand, this is not such big deal. If the
spare runs out as a domain is migrating, the migration is aborted, and
pre-created storage unlink()-ed. There's no difference to what will happen if
user will pre-create storage by hand.
https://bugzilla.redhat.com/show_bug.cgi?id=927252
Michal Privoznik (4):
qemu: Expose file opening functions
qemu_domain: Introduce qemuDomainGetDiskBlockInfo
qemu_migration: Check size prerequisites
qemu_migration: Unlink pre-created storage on error
src/qemu/qemu_domain.c | 299 ++++++++++++++++++++++++++++++++++++++++++++-
src/qemu/qemu_domain.h | 16 +++
src/qemu/qemu_driver.c | 276 ++---------------------------------------
src/qemu/qemu_migration.c | 304 +++++++++++++++++++++++++++++++++++++++++++++-
src/qemu/qemu_process.c | 8 ++
5 files changed, 627 insertions(+), 276 deletions(-)
--
1.8.1.5
1
4
12 Sep '13
Commit 38ab1225 changed the default value of ret from true to false but
forgot to set ret = true when job is NONE. Thus, virsh domjobinfo
returned 1 when there was no job running for a domain but it used to
(and should) return 0 in this case.
---
tools/virsh-domain.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 74feca1..3479a1c 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -5018,6 +5018,7 @@ cmdDomjobinfo(vshControl *ctl, const vshCmd *cmd)
case VIR_DOMAIN_JOB_NONE:
default:
vshPrint(ctl, "%-12s\n", _("None"));
+ ret = true;
goto cleanup;
}
--
1.8.3.2
2
2
Ajia pointed out this was broken, I pushed the following patch to
fix it, pushed as site breaker
Daniel
--
Daniel Veillard | Open Source and Standards, Red Hat
veillard(a)redhat.com | libxml Gnome XML XSLT toolkit http://xmlsoft.org/
http://veillard.com/ | virtualization library http://libvirt.org/
1
0
[libvirt] [PATCHv2 RESEND] Add forwarders attribute to <dns /> element.
by Diego Woitasen 12 Sep '13
by Diego Woitasen 12 Sep '13
12 Sep '13
Useful to set custom forwarders instead of using the contents of
/etc/resolv.conf. It helps me to setup dnsmasq as local nameserver to resolv VM
domain names from domain 0, when domain option is used.
Signed-off-by: Diego Woitasen <diego.woitasen(a)vhgroup.net>
---
docs/formatnetwork.html.in | 8 ++++
docs/schemas/network.rng | 5 +++
src/conf/network_conf.c | 43 ++++++++++++++++++++--
src/conf/network_conf.h | 2 +
src/network/bridge_driver.c | 8 ++++
.../nat-network-dns-forwarders.conf | 16 ++++++++
.../nat-network-dns-forwarders.xml | 12 ++++++
tests/networkxml2conftest.c | 1 +
8 files changed, 92 insertions(+), 3 deletions(-)
create mode 100644 tests/networkxml2confdata/nat-network-dns-forwarders.conf
create mode 100644 tests/networkxml2confdata/nat-network-dns-forwarders.xml
diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in
index e1482db..4dd809a 100644
--- a/docs/formatnetwork.html.in
+++ b/docs/formatnetwork.html.in
@@ -631,6 +631,8 @@
<domain name="example.com"/>
<dns>
<txt name="example" value="example value" />
+ <forwarders addr="8.8.8.8" />
+ <forwarders addr="8.8.4.4" />
<srv service='name' protocol='tcp' domain='test-domain-name' target='.' port='1024' priority='10' weight='10'/>
<host ip='192.168.122.2'>
<hostname>myhost</hostname>
@@ -685,6 +687,12 @@
Currently supported sub-elements of <code><dns></code> are:
<dl>
+ <dt><code>forwarders</code></dt>
+ <dd>A <code>dns</code> element can have 0 or more <code>forwarders</code> elements.
+ Each forwarders element defines an IP address to be used as forwarder
+ in DNS server configuration. The addr attribute is required and defines the
+ IP address of every forwarder. <span class="since">Since N/A</span>
+ </dd>
<dt><code>txt</code></dt>
<dd>A <code>dns</code> element can have 0 or more <code>txt</code> elements.
Each txt element defines a DNS TXT record and has two attributes, both
diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng
index ab183f1..e0c2b51 100644
--- a/docs/schemas/network.rng
+++ b/docs/schemas/network.rng
@@ -217,6 +217,11 @@
</attribute>
</optional>
<zeroOrMore>
+ <element name="forwarders">
+ <attribute name="addr"><ref name="ipAddr"/></attribute>
+ </element>
+ </zeroOrMore>
+ <zeroOrMore>
<element name="txt">
<attribute name="name"><ref name="dnsName"/></attribute>
<attribute name="value"><text/></attribute>
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index d54f2aa..1c1aa64 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -175,6 +175,11 @@ virNetworkDNSSrvDefClear(virNetworkDNSSrvDefPtr def)
static void
virNetworkDNSDefClear(virNetworkDNSDefPtr def)
{
+ if (def->forwarders) {
+ while (def->nfwds)
+ VIR_FREE(def->forwarders[--def->nfwds]);
+ VIR_FREE(def->forwarders);
+ }
if (def->txts) {
while (def->ntxts)
virNetworkDNSTxtDefClear(&def->txts[--def->ntxts]);
@@ -1037,8 +1042,9 @@ virNetworkDNSDefParseXML(const char *networkName,
xmlNodePtr *hostNodes = NULL;
xmlNodePtr *srvNodes = NULL;
xmlNodePtr *txtNodes = NULL;
+ xmlNodePtr *fwdNodes = NULL;
char *forwardPlainNames = NULL;
- int nhosts, nsrvs, ntxts;
+ int nfwds, nhosts, nsrvs, ntxts;
size_t i;
int ret = -1;
xmlNodePtr save = ctxt->node;
@@ -1058,6 +1064,30 @@ virNetworkDNSDefParseXML(const char *networkName,
}
}
+ nfwds = virXPathNodeSet("./forwarders", ctxt, &fwdNodes);
+ if (nfwds < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("invalid <forwarders> element found in <dns> of network %s"),
+ networkName);
+ goto cleanup;
+ }
+ if (nfwds > 0) {
+ if (VIR_ALLOC_N(def->forwarders, nfwds) < 0)
+ goto cleanup;
+
+ for (i = 0; i < nfwds; i++) {
+ def->forwarders[i] = virXMLPropString(fwdNodes[i], "addr");
+ if (virSocketAddrParse(NULL, def->forwarders[i], AF_UNSPEC) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid forwarder IP address '%s' "
+ "in network '%s'"),
+ def->forwarders[i], networkName);
+ goto cleanup;
+ }
+ def->nfwds++;
+ }
+ }
+
nhosts = virXPathNodeSet("./host", ctxt, &hostNodes);
if (nhosts < 0) {
virReportError(VIR_ERR_XML_ERROR,
@@ -1121,6 +1151,7 @@ virNetworkDNSDefParseXML(const char *networkName,
ret = 0;
cleanup:
VIR_FREE(forwardPlainNames);
+ VIR_FREE(fwdNodes);
VIR_FREE(hostNodes);
VIR_FREE(srvNodes);
VIR_FREE(txtNodes);
@@ -2267,13 +2298,14 @@ virNetworkDNSDefFormat(virBufferPtr buf,
int result = 0;
size_t i, j;
- if (!(def->forwardPlainNames || def->nhosts || def->nsrvs || def->ntxts))
+ if (!(def->forwardPlainNames || def->forwarders || def->nhosts ||
+ def->nsrvs || def->ntxts))
goto out;
virBufferAddLit(buf, "<dns");
if (def->forwardPlainNames) {
virBufferAddLit(buf, " forwardPlainNames='yes'");
- if (!(def->nhosts || def->nsrvs || def->ntxts)) {
+ if (!(def->forwarders || def->nhosts || def->nsrvs || def->ntxts)) {
virBufferAddLit(buf, "/>\n");
goto out;
}
@@ -2282,6 +2314,11 @@ virNetworkDNSDefFormat(virBufferPtr buf,
virBufferAddLit(buf, ">\n");
virBufferAdjustIndent(buf, 2);
+ for (i = 0; i < def->nfwds; i++) {
+ virBufferAsprintf(buf, "<forwarders addr='%s' />\n",
+ def->forwarders[i]);
+ }
+
for (i = 0; i < def->ntxts; i++) {
virBufferAsprintf(buf, "<txt name='%s' value='%s'/>\n",
def->txts[i].name,
diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
index c28bfae..b425986 100644
--- a/src/conf/network_conf.h
+++ b/src/conf/network_conf.h
@@ -122,6 +122,8 @@ struct _virNetworkDNSDef {
virNetworkDNSHostDefPtr hosts;
size_t nsrvs;
virNetworkDNSSrvDefPtr srvs;
+ size_t nfwds;
+ char **forwarders;
};
typedef struct _virNetworkIpDef virNetworkIpDef;
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 3a8be90..a2cfb35 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -708,6 +708,14 @@ networkDnsmasqConfContents(virNetworkObjPtr network,
if (!network->def->dns.forwardPlainNames)
virBufferAddLit(&configbuf, "domain-needed\n");
+ if (network->def->dns.forwarders) {
+ virBufferAddLit(&configbuf, "no-resolv\n");
+ for (i=0; i < network->def->dns.nfwds; i++) {
+ virBufferAsprintf(&configbuf, "server=%s\n",
+ network->def->dns.forwarders[i]);
+ }
+ }
+
if (network->def->domain) {
virBufferAsprintf(&configbuf,
"domain=%s\n"
diff --git a/tests/networkxml2confdata/nat-network-dns-forwarders.conf b/tests/networkxml2confdata/nat-network-dns-forwarders.conf
new file mode 100644
index 0000000..ebca289
--- /dev/null
+++ b/tests/networkxml2confdata/nat-network-dns-forwarders.conf
@@ -0,0 +1,16 @@
+##WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE
+##OVERWRITTEN AND LOST. Changes to this configuration should be made using:
+## virsh net-edit default
+## or other application using the libvirt API.
+##
+## dnsmasq conf file created by libvirt
+strict-order
+domain-needed
+no-resolv
+server=8.8.8.8
+server=8.8.4.4
+local=//
+except-interface=lo
+bind-dynamic
+interface=virbr0
+addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts
diff --git a/tests/networkxml2confdata/nat-network-dns-forwarders.xml b/tests/networkxml2confdata/nat-network-dns-forwarders.xml
new file mode 100644
index 0000000..9cd2667
--- /dev/null
+++ b/tests/networkxml2confdata/nat-network-dns-forwarders.xml
@@ -0,0 +1,12 @@
+<network>
+ <name>default</name>
+ <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9c</uuid>
+ <forward dev='eth0' mode='nat'/>
+ <bridge name='virbr0' stp='on' delay='0' />
+ <dns>
+ <forwarders addr='8.8.8.8' />
+ <forwarders addr='8.8.4.4' />
+ </dns>
+ <ip address='192.168.122.1' netmask='255.255.255.0'>
+ </ip>
+</network>
diff --git a/tests/networkxml2conftest.c b/tests/networkxml2conftest.c
index 5825af3..ad50e88 100644
--- a/tests/networkxml2conftest.c
+++ b/tests/networkxml2conftest.c
@@ -145,6 +145,7 @@ mymain(void)
DO_TEST("nat-network-dns-srv-record", full);
DO_TEST("nat-network-dns-hosts", full);
DO_TEST("nat-network-dns-forward-plain", full);
+ DO_TEST("nat-network-dns-forwarders", full);
DO_TEST("dhcp6-network", dhcpv6);
DO_TEST("dhcp6-nat-network", dhcpv6);
DO_TEST("dhcp6host-routed-network", dhcpv6);
--
1.8.1.2
4
7
[libvirt] [PATCH] rbd: Use different formatter to display disk format
by Wido den Hollander 12 Sep '13
by Wido den Hollander 12 Sep '13
12 Sep '13
RBD images are always in RAW format and should be displayed that way
Signed-off-by: Wido den Hollander <wido(a)widodh.nl>
---
src/conf/storage_conf.c | 3 ++-
src/storage/storage_backend_rbd.c | 2 ++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c
index 002663f..e54fc64 100644
--- a/src/conf/storage_conf.c
+++ b/src/conf/storage_conf.c
@@ -230,7 +230,8 @@ static virStoragePoolTypeInfo poolTypeInfo[] = {
},
.volOptions = {
.defaultFormat = VIR_STORAGE_FILE_RAW,
- .formatToString = virStoragePoolFormatDiskTypeToString,
+ .formatFromString = virStorageVolumeFormatFromString,
+ .formatToString = virStorageFileFormatTypeToString,
}
},
{.poolType = VIR_STORAGE_POOL_SHEEPDOG,
diff --git a/src/storage/storage_backend_rbd.c b/src/storage/storage_backend_rbd.c
index e5d720e..c435636 100644
--- a/src/storage/storage_backend_rbd.c
+++ b/src/storage/storage_backend_rbd.c
@@ -32,6 +32,7 @@
#include "base64.h"
#include "viruuid.h"
#include "virstring.h"
+#include "virstoragefile.h"
#include "rados/librados.h"
#include "rbd/librbd.h"
@@ -271,6 +272,7 @@ static int volStorageBackendRBDRefreshVolInfo(virStorageVolDefPtr vol,
vol->capacity = info.size;
vol->allocation = info.obj_size * info.num_objs;
vol->type = VIR_STORAGE_VOL_NETWORK;
+ vol->target.format = VIR_STORAGE_FILE_RAW;
VIR_FREE(vol->target.path);
if (virAsprintf(&vol->target.path, "%s/%s",
--
1.7.9.5
1
1
cc-ing libvir-list
On 09/09/2013 08:20 AM, Ján ONDREJ (SAL) wrote:
> Hello,
>
> in sanlock docs (https://fedorahosted.org/sanlock/) there is described,
> how to use it. There is no mention about NFS. Can I use sanlock with LVM
> (without NFS) with livbirt? It this feature implemented in libvirt for
> Fedora or RHEL?
>
> For libvirt I need to define lease dir as:
> disk_lease_dir = "/var/lib/libvirt/sanlock"
> but this have to be a directory. How to configure it to use sanlock on LVM?
>
3
2
---
src/libxl/libxl_conf.h | 4 +
src/libxl/libxl_driver.c | 641 ++++++++++++++++++++++++++++++++++++++++++++++
src/libxl/libxl_driver.h | 5 +
3 files changed, 650 insertions(+), 0 deletions(-)
diff --git a/src/libxl/libxl_conf.h b/src/libxl/libxl_conf.h
index 8ba0ee4..2041cc2 100644
--- a/src/libxl/libxl_conf.h
+++ b/src/libxl/libxl_conf.h
@@ -41,6 +41,9 @@
# define LIBXL_VNC_PORT_MIN 5900
# define LIBXL_VNC_PORT_MAX 65535
+# define LIBXL_MIGRATION_PORT_MIN 49152
+# define LIBXL_MIGRATION_PORT_MAX 49216
+
# define LIBXL_CONFIG_DIR SYSCONFDIR "/libvirt/libxl"
# define LIBXL_AUTOSTART_DIR LIBXL_CONFIG_DIR "/autostart"
# define LIBXL_STATE_DIR LOCALSTATEDIR "/run/libvirt/libxl"
@@ -109,6 +112,7 @@ struct _libxlDriverPrivate {
/* Immutable pointer, self-locking APIs */
virPortAllocatorPtr reservedVNCPorts;
+ virPortAllocatorPtr reservedMigPorts;
/* Immutable pointer, lockless APIs*/
virSysinfoDefPtr hostsysinfo;
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
index e2a6d44..93b7153 100644
--- a/src/libxl/libxl_driver.c
+++ b/src/libxl/libxl_driver.c
@@ -32,6 +32,12 @@
#include <libxl_utils.h>
#include <fcntl.h>
#include <regex.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netdb.h>
#include "internal.h"
#include "virlog.h"
@@ -52,6 +58,7 @@
#include "virsysinfo.h"
#include "viraccessapicheck.h"
#include "viratomic.h"
+#include "rpc/virnetsocket.h"
#define VIR_FROM_THIS VIR_FROM_LIBXL
@@ -69,6 +76,20 @@
static libxlDriverPrivatePtr libxl_driver = NULL;
+typedef struct _libxlMigrateReceiveArgs {
+ virConnectPtr conn;
+ virDomainObjPtr vm;
+
+ /* for freeing listen sockets */
+ virNetSocketPtr *socks;
+ size_t nsocks;
+} libxlMigrateReceiveArgs;
+
+static const char libxlMigrateReceiverReady[]=
+ "libvirt libxl migration receiver ready, send binary domain data";
+static const char libxlMigrateReceiverFinish[]=
+ "domain received, ready to unpause";
+
/* Function declarations */
static int
libxlDomainManagedSaveLoad(virDomainObjPtr vm,
@@ -836,6 +857,12 @@ libxlStateInitialize(bool privileged,
LIBXL_VNC_PORT_MAX)))
goto error;
+ /* Allocate bitmap for migration port reservation */
+ if (!(libxl_driver->reservedMigPorts =
+ virPortAllocatorNew(LIBXL_MIGRATION_PORT_MIN,
+ LIBXL_MIGRATION_PORT_MAX)))
+ goto error;
+
if (!(libxl_driver->domains = virDomainObjListNew()))
goto error;
@@ -4175,11 +4202,620 @@ libxlConnectSupportsFeature(virConnectPtr conn, int feature)
switch (feature) {
case VIR_DRV_FEATURE_TYPED_PARAM_STRING:
return 1;
+ case VIR_DRV_FEATURE_MIGRATION_V3:
+ return 1;
default:
return 0;
}
}
+static int
+libxlCheckMessageBanner(int fd, const char *banner, int banner_sz)
+{
+ char buf[banner_sz];
+ int ret = 0;
+
+ do {
+ ret = saferead(fd, buf, banner_sz);
+ } while (ret == -1 && errno == EAGAIN);
+
+ if (ret != banner_sz || memcmp(buf, banner, banner_sz)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static char *
+libxlDomainMigrateBegin3(virDomainPtr domain,
+ const char *xmlin,
+ char **cookieout ATTRIBUTE_UNUSED,
+ int *cookieoutlen ATTRIBUTE_UNUSED,
+ unsigned long flags,
+ const char *dname ATTRIBUTE_UNUSED,
+ unsigned long resource ATTRIBUTE_UNUSED)
+{
+ libxlDriverPrivatePtr driver = domain->conn->privateData;
+ libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
+ virDomainObjPtr vm;
+ virDomainDefPtr def = NULL;
+ char *xml = NULL;
+
+ virCheckFlags(LIBXL_MIGRATION_FLAGS, NULL);
+
+ vm = virDomainObjListFindByUUID(driver->domains, domain->uuid);
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(domain->uuid, uuidstr);
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("no domain with matching uuid '%s'"), uuidstr);
+ goto cleanup;
+ }
+
+ if (!virDomainObjIsActive(vm)) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("domain is not running"));
+ goto cleanup;
+ }
+
+ if (virDomainMigrateBegin3EnsureACL(domain->conn, vm->def) < 0)
+ goto cleanup;
+
+ if (xmlin) {
+ if (!(def = virDomainDefParseString(xmlin, cfg->caps,
+ driver->xmlopt,
+ 1 << VIR_DOMAIN_VIRT_XEN,
+ VIR_DOMAIN_XML_INACTIVE)))
+ goto cleanup;
+
+ xml = virDomainDefFormat(def, VIR_DOMAIN_XML_SECURE);
+ } else {
+ xml = virDomainDefFormat(vm->def, VIR_DOMAIN_XML_SECURE);
+ }
+
+cleanup:
+ virDomainDefFree(def);
+ if (vm)
+ virObjectUnlock(vm);
+ virObjectUnref(cfg);
+ return xml;
+}
+
+static void
+doMigrateReceive(virNetSocketPtr sock,
+ int events ATTRIBUTE_UNUSED,
+ void *opaque)
+{
+ libxlMigrateReceiveArgs *data = opaque;
+ virConnectPtr conn = data->conn;
+ virDomainObjPtr vm = data->vm;
+ virNetSocketPtr *socks = data->socks;
+ size_t nsocks = data->nsocks;
+ libxlDriverPrivatePtr driver = conn->privateData;
+ virNetSocketPtr client_sock;
+ int recv_fd;
+ int len;
+ size_t i;
+ int ret;
+
+ virNetSocketAccept(sock, &client_sock);
+ if (client_sock == NULL) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("Fail to accept migration connection"));
+ goto cleanup;
+ }
+ VIR_DEBUG("Accepted migration\n");
+ recv_fd = virNetSocketDupFD(client_sock, true);
+ virObjectUnref(client_sock);
+
+ len = sizeof(libxlMigrateReceiverReady);
+ if (safewrite(recv_fd, libxlMigrateReceiverReady, len) != len) {
+ virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+ _("Failed to write libxlMigrateReceiverReady"));
+ goto cleanup;
+ }
+
+ virObjectLock(vm);
+ ret = libxlVmStart(driver, vm, false, recv_fd);
+ virObjectUnlock(vm);
+
+ if (ret < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Failed to restore domain with libxenlight"));
+ if (!vm->persistent) {
+ virDomainObjListRemove(driver->domains, vm);
+ vm = NULL;
+ }
+ goto cleanup;
+ }
+
+ len = sizeof(libxlMigrateReceiverFinish);
+ if (safewrite(recv_fd, libxlMigrateReceiverFinish, len) != len) {
+ virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+ _("Failed to write libxlMigrateReceiverFinish"));
+ }
+
+ /* Remove all listen socks from event handler, and close them. */
+ if (nsocks) {
+ for (i = 0; i < nsocks; i++) {
+ virNetSocketUpdateIOCallback(socks[i], 0);
+ virNetSocketRemoveIOCallback(socks[i]);
+ virNetSocketClose(socks[i]);
+ virObjectUnref(socks[i]);
+ }
+ VIR_FREE(socks);
+ }
+
+cleanup:
+ VIR_FORCE_CLOSE(recv_fd);
+ VIR_FREE(opaque);
+ return;
+}
+
+static int
+doMigrateSend(libxlDriverPrivatePtr driver,
+ virDomainObjPtr vm,
+ unsigned long flags,
+ int sockfd)
+{
+ libxlDomainObjPrivatePtr priv;
+ libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
+ virDomainEventPtr event = NULL;
+ int live = 0;
+ int ret = -1;
+
+ if (flags & VIR_MIGRATE_LIVE)
+ live = LIBXL_SUSPEND_LIVE;
+
+ priv = vm->privateData;
+
+ /* read fixed message from dest (ready to receive) */
+ if (libxlCheckMessageBanner(sockfd, libxlMigrateReceiverReady,
+ sizeof(libxlMigrateReceiverReady)))
+ goto cleanup;
+
+ if (libxl_domain_suspend(priv->ctx, vm->def->id, sockfd, live, NULL) != 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to save domain '%d' with libxenlight"),
+ vm->def->id);
+ goto cleanup;
+ }
+
+ /* read fixed message from dest (receive completed) */
+ if (libxlCheckMessageBanner(sockfd, libxlMigrateReceiverFinish,
+ sizeof(libxlMigrateReceiverFinish))) {
+ if (libxl_domain_resume(priv->ctx, vm->def->id, 0, 0) != 0) {
+ VIR_DEBUG("Failed to resume domain '%d' with libxenlight",
+ vm->def->id);
+ virDomainObjSetState(vm, VIR_DOMAIN_PAUSED,
+ VIR_DOMAIN_PAUSED_MIGRATION);
+ event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_SUSPENDED,
+ VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED);
+ if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
+ goto cleanup;
+ }
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ if (event)
+ libxlDomainEventQueue(driver, event);
+ virObjectUnref(cfg);
+ return ret;
+}
+
+static int
+libxlDomainMigratePrepare3(virConnectPtr dconn,
+ const char *cookiein ATTRIBUTE_UNUSED,
+ int cookieinlen ATTRIBUTE_UNUSED,
+ char **cookieout ATTRIBUTE_UNUSED,
+ int *cookieoutlen ATTRIBUTE_UNUSED,
+ const char *uri_in,
+ char **uri_out,
+ unsigned long flags,
+ const char *dname,
+ unsigned long resource ATTRIBUTE_UNUSED,
+ const char *dom_xml)
+{
+ libxlDriverPrivatePtr driver = dconn->privateData;
+ libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
+ virDomainDefPtr def = NULL;
+ virDomainObjPtr vm = NULL;
+ char *hostname = NULL;
+ unsigned short port;
+ char portstr[100];
+ virURIPtr uri = NULL;
+ virNetSocketPtr *socks = NULL;
+ size_t nsocks = 0;
+ int nsocks_listen = 0;
+ libxlMigrateReceiveArgs *args;
+ size_t i;
+ int ret = -1;
+
+ virCheckFlags(LIBXL_MIGRATION_FLAGS, -1);
+
+ libxlDriverLock(driver);
+ if (!dom_xml) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("no domain XML passed"));
+ goto cleanup;
+ }
+ def = virDomainDefParseString(dom_xml, cfg->caps, driver->xmlopt,
+ 1 << VIR_DOMAIN_VIRT_XEN,
+ VIR_DOMAIN_XML_INACTIVE);
+
+ /* Target domain name, maybe renamed. */
+ if (dname) {
+ if (VIR_STRDUP(def->name, dname) < 0)
+ goto cleanup;
+ }
+
+ if (!(vm = virDomainObjListAdd(driver->domains, def,
+ driver->xmlopt,
+ VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
+ VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
+ NULL)))
+ goto cleanup;
+
+ def = NULL;
+
+ if (virDomainMigratePrepare3EnsureACL(dconn, vm->def) < 0)
+ goto cleanup;
+
+ /* Create socket connection to receive migration data */
+ if (!uri_in) {
+ hostname = virGetHostname();
+ if (hostname == NULL)
+ goto cleanup;
+
+ if (virPortAllocatorAcquire(driver->reservedMigPorts, &port) < 0)
+ goto cleanup;
+
+ if (port == 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Unable to find an unused migrate port"));
+ goto cleanup;
+ }
+
+ if (virAsprintf(uri_out, "tcp://%s:%d", hostname, port) < 0)
+ goto cleanup;
+ } else {
+ if (!strstr(uri_in, "//")) {
+ /* not full URI, add prefix tcp:// */
+ char *tmp;
+ if (virAsprintf(&tmp, "tcp://%s", uri_in) < 0)
+ goto cleanup;
+ uri = virURIParse(tmp);
+ VIR_FREE(tmp);
+ } else {
+ uri = virURIParse(uri_in);
+ }
+
+ if (uri == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("unable to parse URI: %s"),
+ uri_in);
+ goto cleanup;
+ }
+
+ if (uri->server == NULL) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("missing host in migration URI: %s"),
+ uri_in);
+ goto cleanup;
+ } else {
+ hostname = uri->server;
+ }
+
+ if (uri->port == 0) {
+ if (virPortAllocatorAcquire(driver->reservedMigPorts, &port) < 0)
+ goto cleanup;
+
+ if (port == 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Unable to find an unused migrate port"));
+ goto cleanup;
+ }
+ } else {
+ port = uri->port;
+ }
+
+ if (virAsprintf(uri_out, "tcp://%s:%d", hostname, port) < 0)
+ goto cleanup;
+ }
+
+ snprintf(portstr, sizeof(portstr), "%d", port);
+
+ if (virNetSocketNewListenTCP(hostname, portstr, &socks, &nsocks) < 0) {
+ virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+ _("Fail to create socket for incoming migration"));
+ goto cleanup;
+ }
+
+ if (VIR_ALLOC(args) < 0)
+ goto cleanup;
+
+ args->conn = dconn;
+ args->vm = vm;
+ args->socks = socks;
+ args->nsocks = nsocks;
+
+ for (i = 0 ; i < nsocks ; i++) {
+ if (virNetSocketSetBlocking(socks[i], true) < 0)
+ continue;
+ if (virNetSocketListen(socks[i], 1) < 0)
+ continue;
+
+ if (virNetSocketAddIOCallback(socks[i],
+ 0,
+ doMigrateReceive,
+ args,
+ NULL) < 0) {
+ continue;
+ }
+
+ virNetSocketUpdateIOCallback(socks[i], VIR_EVENT_HANDLE_READABLE);
+ nsocks_listen ++;
+ }
+
+ if (!nsocks_listen)
+ goto cleanup;
+
+ ret = 0;
+ goto end;
+
+cleanup:
+ if (nsocks) {
+ for (i = 0 ; i < nsocks ; i++) {
+ virNetSocketClose(socks[i]);
+ virObjectUnref(socks[i]);
+ }
+ VIR_FREE(socks);
+ }
+
+end:
+ virURIFree(uri);
+ if (vm)
+ virObjectUnlock(vm);
+ virObjectUnref(cfg);
+ libxlDriverUnlock(driver);
+ return ret;
+}
+
+static int
+libxlDomainMigratePerform3(virDomainPtr dom,
+ const char *xmlin ATTRIBUTE_UNUSED,
+ const char *cookiein ATTRIBUTE_UNUSED,
+ int cookieinlen ATTRIBUTE_UNUSED,
+ char **cookieout ATTRIBUTE_UNUSED,
+ int *cookieoutlen ATTRIBUTE_UNUSED,
+ const char *dconnuri ATTRIBUTE_UNUSED,
+ const char *uri,
+ unsigned long flags,
+ const char *dname ATTRIBUTE_UNUSED,
+ unsigned long resource ATTRIBUTE_UNUSED)
+{
+ libxlDriverPrivatePtr driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ char *hostname = NULL;
+ unsigned short port = 0;
+ char portstr[100];
+ virURIPtr uri_p = NULL;
+ virNetSocketPtr sock;
+ int sockfd = -1;
+ int saved_errno = EINVAL;
+ int ret = -1;
+
+ virCheckFlags(LIBXL_MIGRATION_FLAGS, -1);
+
+ vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(dom->uuid, uuidstr);
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("no domain with matching uuid '%s'"), uuidstr);
+ goto cleanup;
+ }
+
+ if (virDomainMigratePerform3EnsureACL(dom->conn, vm->def) < 0)
+ goto cleanup;
+
+ /* parse dst host:port from uri */
+ uri_p = virURIParse(uri);
+ if (uri_p == NULL || uri_p->server == NULL || uri_p->port == 0)
+ goto cleanup;
+
+ hostname = uri_p->server;
+ port = uri_p->port;
+ snprintf(portstr, sizeof(portstr), "%d", port);
+
+ /* socket connect to dst host:port */
+ if (virNetSocketNewConnectTCP(hostname, portstr, &sock) < 0) {
+ virReportSystemError(saved_errno,
+ _("unable to connect to '%s:%s'"),
+ hostname, portstr);
+ goto cleanup;
+ }
+
+ if (virNetSocketSetBlocking(sock, true) < 0) {
+ virObjectUnref(sock);
+ goto cleanup;
+ }
+
+ sockfd = virNetSocketDupFD(sock, true);
+ virObjectUnref(sock);
+
+ /* suspend vm and send saved data to dst through socket fd */
+ ret = doMigrateSend(driver, vm, flags, sockfd);
+
+cleanup:
+ VIR_FORCE_CLOSE(sockfd);
+ virURIFree(uri_p);
+ if (vm)
+ virObjectUnlock(vm);
+ return ret;
+}
+
+static virDomainPtr
+libxlDomainMigrateFinish3(virConnectPtr dconn,
+ const char *dname,
+ const char *cookiein ATTRIBUTE_UNUSED,
+ int cookieinlen ATTRIBUTE_UNUSED,
+ char **cookieout ATTRIBUTE_UNUSED,
+ int *cookieoutlen ATTRIBUTE_UNUSED,
+ const char *dconnuri ATTRIBUTE_UNUSED,
+ const char *uri,
+ unsigned long flags,
+ int cancelled)
+{
+ libxlDriverPrivatePtr driver = dconn->privateData;
+ libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
+ unsigned short port = 0;
+ virURIPtr uri_p = NULL;
+ virDomainObjPtr vm = NULL;
+ virDomainPtr dom = NULL;
+ libxlDomainObjPrivatePtr priv;
+ virDomainEventPtr event = NULL;
+ int rc;
+
+ virCheckFlags(LIBXL_MIGRATION_FLAGS, NULL);
+
+ uri_p = virURIParse(uri);
+ if (uri_p == NULL || uri_p->port == 0)
+ VIR_DEBUG("Fail to parse port from URI");
+ port = uri_p->port;
+ if (LIBXL_MIGRATION_PORT_MIN <= port && port < LIBXL_MIGRATION_PORT_MAX) {
+ if (virPortAllocatorRelease(driver->reservedMigPorts, port) < 0)
+ VIR_DEBUG("Could not mark port %d as unused", port);
+ }
+
+ vm = virDomainObjListFindByName(driver->domains, dname);
+ if (!vm)
+ goto cleanup;
+
+ if (virDomainMigrateFinish3EnsureACL(dconn, vm->def) < 0)
+ goto cleanup;
+
+ if (!cancelled) {
+ if (!(flags & VIR_MIGRATE_PAUSED)) {
+ priv = vm->privateData;
+ rc = libxl_domain_unpause(priv->ctx, vm->def->id);
+ if (rc) {
+ virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+ _("Failed to unpause domain"));
+ goto error;
+ }
+
+ virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED);
+ if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
+ goto error;
+ }
+
+ dom = virGetDomain(dconn, vm->def->name, vm->def->uuid);
+ goto cleanup;
+ }
+
+error:
+ if (libxlVmReap(driver, vm, VIR_DOMAIN_SHUTOFF_SAVED)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to destroy domain '%d'"), vm->def->id);
+ goto cleanup;
+ }
+ event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_SAVED);
+ if (!vm->persistent) {
+ virDomainObjListRemove(driver->domains, vm);
+ vm = NULL;
+ }
+
+cleanup:
+ virURIFree(uri_p);
+ if (vm)
+ virObjectUnlock(vm);
+ if (event)
+ libxlDomainEventQueue(driver, event);
+ virObjectUnref(cfg);
+ return dom;
+}
+
+static int
+libxlDomainMigrateConfirm3(virDomainPtr domain,
+ const char *cookiein ATTRIBUTE_UNUSED,
+ int cookieinlen ATTRIBUTE_UNUSED,
+ unsigned long flags,
+ int cancelled)
+{
+ libxlDriverPrivatePtr driver = domain->conn->privateData;
+ libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
+ virDomainObjPtr vm;
+ libxlDomainObjPrivatePtr priv;
+ virDomainEventPtr event = NULL;
+ int ret = -1;
+
+ virCheckFlags(LIBXL_MIGRATION_FLAGS, -1);
+
+ vm = virDomainObjListFindByUUID(driver->domains, domain->uuid);
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(domain->uuid, uuidstr);
+ virReportError(VIR_ERR_NO_DOMAIN,
+ _("no domain with matching uuid '%s'"), uuidstr);
+ goto cleanup;
+ }
+
+ if (virDomainMigrateConfirm3EnsureACL(domain->conn, vm->def) < 0)
+ goto cleanup;
+
+ if (cancelled) {
+ priv = vm->privateData;
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("migration failed, try to resume on our end"));
+ if (!libxl_domain_resume(priv->ctx, vm->def->id, 0, 0)) {
+ ret = 0;
+ } else {
+ VIR_DEBUG("Failed to resume domain '%d' with libxenlight",
+ vm->def->id);
+ virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_MIGRATION);
+ event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_SUSPENDED,
+ VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED);
+ if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
+ goto cleanup;
+ }
+
+ goto cleanup;
+ }
+
+ if (libxlVmReap(driver, vm, VIR_DOMAIN_SHUTOFF_SAVED)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to destroy domain '%d'"), vm->def->id);
+ goto cleanup;
+ }
+
+ event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_SAVED);
+
+ if (flags & VIR_MIGRATE_UNDEFINE_SOURCE)
+ virDomainDeleteConfig(cfg->configDir, cfg->autostartDir, vm);
+
+ if (!vm->persistent || (flags & VIR_MIGRATE_UNDEFINE_SOURCE)) {
+ virDomainObjListRemove(driver->domains, vm);
+ vm = NULL;
+ }
+
+ VIR_DEBUG("Migration successful.\n");
+ ret = 0;
+
+cleanup:
+ if (vm)
+ virObjectUnlock(vm);
+ if (event)
+ libxlDomainEventQueue(driver, event);
+ virObjectUnref(cfg);
+ return ret;
+}
+
static virDriver libxlDriver = {
.no = VIR_DRV_LIBXL,
@@ -4249,6 +4885,11 @@ static virDriver libxlDriver = {
#ifdef LIBXL_HAVE_DOMAIN_NODEAFFINITY
.domainGetNumaParameters = libxlDomainGetNumaParameters, /* 1.1.1 */
#endif
+ .domainMigrateBegin3 = libxlDomainMigrateBegin3, /* 1.1.3 */
+ .domainMigratePrepare3 = libxlDomainMigratePrepare3, /* 1.1.3 */
+ .domainMigratePerform3 = libxlDomainMigratePerform3, /* 1.1.3 */
+ .domainMigrateFinish3 = libxlDomainMigrateFinish3, /* 1.1.3 */
+ .domainMigrateConfirm3 = libxlDomainMigrateConfirm3, /* 1.1.3 */
.nodeGetFreeMemory = libxlNodeGetFreeMemory, /* 0.9.0 */
.nodeGetCellsFreeMemory = libxlNodeGetCellsFreeMemory, /* 1.1.1 */
.connectDomainEventRegister = libxlConnectDomainEventRegister, /* 0.9.0 */
diff --git a/src/libxl/libxl_driver.h b/src/libxl/libxl_driver.h
index a33d60c..25ac2b8 100644
--- a/src/libxl/libxl_driver.h
+++ b/src/libxl/libxl_driver.h
@@ -24,6 +24,11 @@
#ifndef LIBXL_DRIVER_H
# define LIBXL_DRIVER_H
+# define LIBXL_MIGRATION_FLAGS \
+ (VIR_MIGRATE_LIVE | \
+ VIR_MIGRATE_UNDEFINE_SOURCE | \
+ VIR_MIGRATE_PAUSED)
+
int libxlRegister(void);
#endif /* LIBXL_DRIVER_H */
--
1.6.0.2
1
0
Re: [libvirt] [RESEND][PATCHv5 0/4] write separate module for hostdev passthrough
by Jim Fehlig 12 Sep '13
by Jim Fehlig 12 Sep '13
12 Sep '13
Chunyan Liu wrote:
> [rebased to latest libvirt code for applying and reviewing the patches]
>
Odd, but I just noticed that this series is not in the list archives,
nor is the original V5 you sent on Sept. 2. You're obviously subscribed
to the list, so I wouldn't expect the mails to be held for moderation.
Makes it difficult for others on the libvirt list to review...
Regards,
Jim
> These patches implements a separate module for hostdev passthrough so that it
> could be shared by different drivers and can maintain a global state of a host
> device. Plus, add passthrough to libxl driver, and change qemu driver and lxc
> driver to use hostdev common library instead of their own hostdev APIs.
>
> ---
> Changes to v4:
> * change the way checking hypervisor driver name to decide whether use pciback
> or pci-stub as stub driver, instead, using driver callback to handle that.
> * remove get active/inactive list APIs from hostdev common library since
> currently no code uses them.
> * add nodedev-detach/reattach/reset to libxl driver
> * other fixes to Daniel and Jim's comments
> v4 is here:
> https://www.redhat.com/archives/libvir-list/2013-August/msg00806.html
>
> Changes to v3:
> * fix Jim's comments
> v3 is here:
> https://www.redhat.com/archives/libvir-list/2013-August/msg00019.html
>
> Changes to v2:
> * add patches for qemu driver and lxc driver, use common library APIs instead
> of their own hostdev APIs.
> * add APIs for nodedev-detach and nodedev-reattach calling.
> * rename functions to use unified prefix 'virHostdev'
> * use VIR_ONCE_GLOBAL_INIT() as others instead of previous Init and Cleanup.
> * use VIR_STRDUP instead of strdup
> * rebase to latest code
> v2 is here:
> https://www.redhat.com/archives/libvir-list/2013-June/msg00263.html
>
> Chunyan Liu (4):
> add hostdev passthrough common library
> add pci passthrough to libxl driver
> change qemu driver to use hostdev common library
> change lxc driver to use hostdev common library
>
> docs/schemas/domaincommon.rng | 1 +
> po/POTFILES.in | 3 +-
> src/Makefile.am | 3 +-
> src/conf/domain_conf.c | 3 +-
> src/conf/domain_conf.h | 1 +
> src/libvirt_private.syms | 15 +
> src/libxl/libxl_conf.c | 63 ++
> src/libxl/libxl_conf.h | 4 +
> src/libxl/libxl_domain.c | 9 +
> src/libxl/libxl_driver.c | 443 ++++++++++++++-
> src/lxc/lxc_conf.h | 4 -
> src/lxc/lxc_driver.c | 45 +-
> src/lxc/lxc_hostdev.c | 413 -------------
> src/lxc/lxc_hostdev.h | 43 --
> src/lxc/lxc_process.c | 21 +-
> src/qemu/qemu_command.c | 1 -
> src/qemu/qemu_conf.h | 9 +-
> src/qemu/qemu_domain.c | 9 +
> src/qemu/qemu_driver.c | 72 +--
> src/qemu/qemu_hostdev.c | 1289 ---------------------------------------
> src/qemu/qemu_hostdev.h | 72 ---
> src/qemu/qemu_hotplug.c | 126 ++---
> src/qemu/qemu_process.c | 34 +-
> src/util/virhostdev.c | 1335 +++++++++++++++++++++++++++++++++++++++++
> src/util/virhostdev.h | 104 ++++
> src/util/virpci.c | 28 +-
> src/util/virpci.h | 9 +-
> src/util/virscsi.c | 26 +-
> src/util/virscsi.h | 8 +-
> src/util/virusb.c | 27 +-
> src/util/virusb.h | 8 +-
> 31 files changed, 2195 insertions(+), 2033 deletions(-)
> delete mode 100644 src/lxc/lxc_hostdev.c
> delete mode 100644 src/lxc/lxc_hostdev.h
> delete mode 100644 src/qemu/qemu_hostdev.c
> delete mode 100644 src/qemu/qemu_hostdev.h
> create mode 100644 src/util/virhostdev.c
> create mode 100644 src/util/virhostdev.h
>
>
>
2
1
[libvirt] [RESEND][PATCHv5 4/4] change lxc driver to use hostdev common library
by Chunyan Liu 12 Sep '13
by Chunyan Liu 12 Sep '13
12 Sep '13
Change lxc driver to use hostdev common library instead of its own APIs in
lxc_hostdev.[ch]
Signed-off-by: Chunyan Liu <cyliu(a)suse.com>
---
po/POTFILES.in | 1 -
src/Makefile.am | 1 -
src/lxc/lxc_conf.h | 4 -
src/lxc/lxc_driver.c | 45 +++---
src/lxc/lxc_hostdev.c | 413 -------------------------------------------------
src/lxc/lxc_hostdev.h | 43 -----
src/lxc/lxc_process.c | 21 ++-
7 files changed, 43 insertions(+), 485 deletions(-)
delete mode 100644 src/lxc/lxc_hostdev.c
delete mode 100644 src/lxc/lxc_hostdev.h
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 2fc7e67..b3b7832 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -61,7 +61,6 @@ src/locking/lock_manager.c
src/locking/sanlock_helper.c
src/lxc/lxc_cgroup.c
src/lxc/lxc_fuse.c
-src/lxc/lxc_hostdev.c
src/lxc/lxc_container.c
src/lxc/lxc_conf.c
src/lxc/lxc_controller.c
diff --git a/src/Makefile.am b/src/Makefile.am
index c3a8ba0..afae0a8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -600,7 +600,6 @@ LXC_DRIVER_SOURCES = \
lxc/lxc_container.c lxc/lxc_container.h \
lxc/lxc_cgroup.c lxc/lxc_cgroup.h \
lxc/lxc_domain.c lxc/lxc_domain.h \
- lxc/lxc_hostdev.c lxc/lxc_hostdev.h \
lxc/lxc_monitor.c lxc/lxc_monitor.h \
lxc/lxc_process.c lxc/lxc_process.h \
lxc/lxc_fuse.c lxc/lxc_fuse.h \
diff --git a/src/lxc/lxc_conf.h b/src/lxc/lxc_conf.h
index a6208a2..05f2a80 100644
--- a/src/lxc/lxc_conf.h
+++ b/src/lxc/lxc_conf.h
@@ -92,10 +92,6 @@ struct _virLXCDriver {
/* Immutable pointer, self-locking APIs */
virDomainObjListPtr domains;
- /* Immutable pointer. Requires lock to be held before
- * calling APIs. */
- virUSBDeviceListPtr activeUsbHostdevs;
-
/* Immutable pointer, self-locking APIs */
virDomainEventStatePtr domainEventState;
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index b587c22..098f2f0 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -70,6 +70,7 @@
#include "virstring.h"
#include "viraccessapicheck.h"
#include "viraccessapichecklxc.h"
+#include "virhostdev.h"
#define VIR_FROM_THIS VIR_FROM_LXC
@@ -1418,9 +1419,6 @@ static int lxcStateInitialize(bool privileged,
if (!(lxc_driver->securityManager = lxcSecurityInit(cfg)))
goto cleanup;
- if ((lxc_driver->activeUsbHostdevs = virUSBDeviceListNew()) == NULL)
- goto cleanup;
-
if ((virLXCDriverGetCapabilities(lxc_driver, true)) == NULL)
goto cleanup;
@@ -1535,7 +1533,6 @@ static int lxcStateCleanup(void)
virSysinfoDefFree(lxc_driver->hostsysinfo);
- virObjectUnref(lxc_driver->activeUsbHostdevs);
virObjectUnref(lxc_driver->caps);
virObjectUnref(lxc_driver->securityManager);
virObjectUnref(lxc_driver->xmlopt);
@@ -3214,6 +3211,7 @@ lxcDomainAttachDeviceHostdevSubsysUSBLive(virLXCDriverPtr driver,
mode_t mode;
bool created = false;
virUSBDevicePtr usb = NULL;
+ virHostdevManagerPtr hostdev_mgr;
if (virDomainHostdevFind(vm->def, def, NULL) >= 0) {
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
@@ -3221,6 +3219,13 @@ lxcDomainAttachDeviceHostdevSubsysUSBLive(virLXCDriverPtr driver,
return -1;
}
+ hostdev_mgr = virHostdevManagerGetDefault();
+ if (virHostdevPrepareUsbHostdevs(hostdev_mgr,
+ LXC_DRIVER_NAME,
+ vm->def->name,
+ &def, 1, 0) < 0)
+ goto cleanup;
+
if (virAsprintf(&vroot, "/proc/%llu/root",
(unsigned long long)priv->initpid) < 0)
goto cleanup;
@@ -3296,6 +3301,11 @@ lxcDomainAttachDeviceHostdevSubsysUSBLive(virLXCDriverPtr driver,
ret = 0;
cleanup:
+ virHostdevReAttachUsbHostdevs(hostdev_mgr,
+ LXC_DRIVER_NAME,
+ vm->def->name,
+ &def,
+ 1);
virDomainAuditHostdev(vm, def, "attach", ret == 0);
if (ret < 0 && created)
unlink(dstfile);
@@ -3758,8 +3768,7 @@ cleanup:
static int
-lxcDomainDetachDeviceHostdevUSBLive(virLXCDriverPtr driver,
- virDomainObjPtr vm,
+lxcDomainDetachDeviceHostdevUSBLive(virDomainObjPtr vm,
virDomainDeviceDefPtr dev)
{
virLXCDomainObjPrivatePtr priv = vm->privateData;
@@ -3768,6 +3777,7 @@ lxcDomainDetachDeviceHostdevUSBLive(virLXCDriverPtr driver,
char *dst = NULL;
char *vroot = NULL;
virUSBDevicePtr usb = NULL;
+ virHostdevManagerPtr hostdev_mgr;
if ((idx = virDomainHostdevFind(vm->def,
dev->data.hostdev,
@@ -3812,9 +3822,9 @@ lxcDomainDetachDeviceHostdevUSBLive(virLXCDriverPtr driver,
VIR_WARN("cannot deny device %s for domain %s",
dst, vm->def->name);
- virObjectLock(driver->activeUsbHostdevs);
- virUSBDeviceListDel(driver->activeUsbHostdevs, usb);
- virObjectUnlock(driver->activeUsbHostdevs);
+ hostdev_mgr = virHostdevManagerGetDefault();
+ virHostdevReAttachPciHostdevs(hostdev_mgr, LXC_DRIVER_NAME,
+ vm->def->name, &def, 1);
virDomainHostdevRemove(vm->def, idx);
virDomainHostdevDefFree(def);
@@ -3948,13 +3958,12 @@ cleanup:
static int
-lxcDomainDetachDeviceHostdevSubsysLive(virLXCDriverPtr driver,
- virDomainObjPtr vm,
+lxcDomainDetachDeviceHostdevSubsysLive(virDomainObjPtr vm,
virDomainDeviceDefPtr dev)
{
switch (dev->data.hostdev->source.subsys.type) {
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
- return lxcDomainDetachDeviceHostdevUSBLive(driver, vm, dev);
+ return lxcDomainDetachDeviceHostdevUSBLive(vm, dev);
default:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
@@ -3986,8 +3995,7 @@ lxcDomainDetachDeviceHostdevCapsLive(virDomainObjPtr vm,
static int
-lxcDomainDetachDeviceHostdevLive(virLXCDriverPtr driver,
- virDomainObjPtr vm,
+lxcDomainDetachDeviceHostdevLive(virDomainObjPtr vm,
virDomainDeviceDefPtr dev)
{
virLXCDomainObjPrivatePtr priv = vm->privateData;
@@ -4000,7 +4008,7 @@ lxcDomainDetachDeviceHostdevLive(virLXCDriverPtr driver,
switch (dev->data.hostdev->mode) {
case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
- return lxcDomainDetachDeviceHostdevSubsysLive(driver, vm, dev);
+ return lxcDomainDetachDeviceHostdevSubsysLive(vm, dev);
case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
return lxcDomainDetachDeviceHostdevCapsLive(vm, dev);
@@ -4015,8 +4023,7 @@ lxcDomainDetachDeviceHostdevLive(virLXCDriverPtr driver,
static int
-lxcDomainDetachDeviceLive(virLXCDriverPtr driver,
- virDomainObjPtr vm,
+lxcDomainDetachDeviceLive(virDomainObjPtr vm,
virDomainDeviceDefPtr dev)
{
int ret = -1;
@@ -4031,7 +4038,7 @@ lxcDomainDetachDeviceLive(virLXCDriverPtr driver,
break;
case VIR_DOMAIN_DEVICE_HOSTDEV:
- ret = lxcDomainDetachDeviceHostdevLive(driver, vm, dev);
+ ret = lxcDomainDetachDeviceHostdevLive(vm, dev);
break;
default:
@@ -4364,7 +4371,7 @@ static int lxcDomainDetachDeviceFlags(virDomainPtr dom,
if (virDomainDefCompatibleDevice(vm->def, dev_copy) < 0)
goto cleanup;
- if ((ret = lxcDomainDetachDeviceLive(driver, vm, dev_copy)) < 0)
+ if ((ret = lxcDomainDetachDeviceLive(vm, dev_copy)) < 0)
goto cleanup;
/*
* update domain status forcibly because the domain status may be
diff --git a/src/lxc/lxc_hostdev.c b/src/lxc/lxc_hostdev.c
deleted file mode 100644
index 3b371fc..0000000
--- a/src/lxc/lxc_hostdev.c
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * virLXC_hostdev.c: VIRLXC hostdev management
- *
- * Copyright (C) 2006-2007, 2009-2012 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: Daniel P. Berrange <berrange(a)redhat.com>
- */
-
-#include <config.h>
-
-#include "lxc_hostdev.h"
-#include "viralloc.h"
-#include "virlog.h"
-#include "virerror.h"
-
-#define VIR_FROM_THIS VIR_FROM_LXC
-
-int
-virLXCUpdateActiveUsbHostdevs(virLXCDriverPtr driver,
- virDomainDefPtr def)
-{
- virDomainHostdevDefPtr hostdev = NULL;
- size_t i;
-
- if (!def->nhostdevs)
- return 0;
-
- for (i = 0; i < def->nhostdevs; i++) {
- virUSBDevicePtr usb = NULL;
- hostdev = def->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 domain %s",
- hostdev->source.subsys.u.usb.bus,
- hostdev->source.subsys.u.usb.device,
- def->name);
- continue;
- }
-
- virUSBDeviceSetUsedBy(usb, def->name);
-
- virObjectLock(driver->activeUsbHostdevs);
- if (virUSBDeviceListAdd(driver->activeUsbHostdevs, usb) < 0) {
- virObjectUnlock(driver->activeUsbHostdevs);
- virUSBDeviceFree(usb);
- return -1;
- }
- virObjectUnlock(driver->activeUsbHostdevs);
- }
-
- return 0;
-}
-
-
-int
-virLXCPrepareHostdevUSBDevices(virLXCDriverPtr driver,
- const char *name,
- virUSBDeviceList *list)
-{
- size_t i, j;
- unsigned int count;
- virUSBDevicePtr tmp;
-
- count = virUSBDeviceListCount(list);
-
- virObjectLock(driver->activeUsbHostdevs);
- for (i = 0; i < count; i++) {
- virUSBDevicePtr usb = virUSBDeviceListGet(list, i);
- if ((tmp = virUSBDeviceListFind(driver->activeUsbHostdevs, usb))) {
- const char *other_name = virUSBDeviceGetUsedBy(tmp);
-
- if (other_name)
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("USB device %s is in use by domain %s"),
- virUSBDeviceGetName(tmp), other_name);
- else
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("USB device %s is already in use"),
- virUSBDeviceGetName(tmp));
- goto error;
- }
-
- virUSBDeviceSetUsedBy(usb, name);
- VIR_DEBUG("Adding %03d.%03d dom=%s to activeUsbHostdevs",
- virUSBDeviceGetBus(usb), virUSBDeviceGetDevno(usb), name);
- /*
- * The caller is responsible to steal these usb devices
- * from the virUSBDeviceList that passed in on success,
- * perform rollback on failure.
- */
- if (virUSBDeviceListAdd(driver->activeUsbHostdevs, usb) < 0)
- goto error;
- }
- virObjectUnlock(driver->activeUsbHostdevs);
- return 0;
-
-error:
- for (j = 0; j < i; j++) {
- tmp = virUSBDeviceListGet(list, i);
- virUSBDeviceListSteal(driver->activeUsbHostdevs, tmp);
- }
- virObjectUnlock(driver->activeUsbHostdevs);
- return -1;
-}
-
-int
-virLXCFindHostdevUSBDevice(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) {
- virUSBDeviceList *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
-virLXCPrepareHostUSBDevices(virLXCDriverPtr driver,
- virDomainDefPtr def)
-{
- size_t i;
- int ret = -1;
- virUSBDeviceList *list;
- virUSBDevicePtr tmp;
- virDomainHostdevDefPtr *hostdevs = def->hostdevs;
- int nhostdevs = def->nhostdevs;
-
- /* 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. See virLXCPrepareHostdevPCIDevices()
- */
- 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)
- required = false;
-
- if (virLXCFindHostdevUSBDevice(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 driver list. However, if something goes
- * wrong, perform rollback.
- */
- if (virLXCPrepareHostdevUSBDevices(driver, def->name, list) < 0)
- goto cleanup;
-
- /* Loop 2: Temporary list was successfully merged with
- * driver 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 virLXCPrepareHostDevices(virLXCDriverPtr driver,
- virDomainDefPtr def)
-{
- size_t i;
-
- if (!def->nhostdevs)
- return 0;
-
- /* Sanity check for supported configurations only */
- for (i = 0; i < def->nhostdevs; i++) {
- virDomainHostdevDefPtr dev = def->hostdevs[i];
-
- switch (dev->mode) {
- case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
- switch (dev->source.subsys.type) {
- case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
- break;
- default:
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("Unsupported hostdev type %s"),
- virDomainHostdevSubsysTypeToString(dev->source.subsys.type));
- return -1;
- }
- break;
-
- case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
- switch (dev->source.subsys.type) {
- case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE:
- case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC:
- case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET:
- break;
- default:
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("Unsupported hostdev type %s"),
- virDomainHostdevSubsysTypeToString(dev->source.subsys.type));
- return -1;
- }
- break;
-
-
- default:
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("Unsupported hostdev mode %s"),
- virDomainHostdevModeTypeToString(dev->mode));
- return -1;
- }
- }
-
- if (virLXCPrepareHostUSBDevices(driver, def) < 0)
- return -1;
-
- return 0;
-}
-
-
-static void
-virLXCDomainReAttachHostUsbDevices(virLXCDriverPtr driver,
- const char *name,
- virDomainHostdevDefPtr *hostdevs,
- int nhostdevs)
-{
- size_t i;
-
- virObjectLock(driver->activeUsbHostdevs);
- for (i = 0; i < nhostdevs; i++) {
- virDomainHostdevDefPtr hostdev = hostdevs[i];
- virUSBDevicePtr usb, tmp;
- const char *used_by = NULL;
-
- 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 domain %s",
- hostdev->source.subsys.u.usb.bus,
- hostdev->source.subsys.u.usb.device,
- name);
- continue;
- }
-
- /* Delete only those USB devices which belongs
- * to domain @name because virLXCProcessStart() might
- * have failed because USB device is already taken.
- * Therefore we want to steal only those devices from
- * the list which were taken by @name */
-
- tmp = virUSBDeviceListFind(driver->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;
- }
-
- used_by = virUSBDeviceGetUsedBy(tmp);
- if (STREQ_NULLABLE(used_by, name)) {
- VIR_DEBUG("Removing %03d.%03d dom=%s from activeUsbHostdevs",
- hostdev->source.subsys.u.usb.bus,
- hostdev->source.subsys.u.usb.device,
- name);
-
- virUSBDeviceListDel(driver->activeUsbHostdevs, tmp);
- }
- }
- virObjectUnlock(driver->activeUsbHostdevs);
-}
-
-void virLXCDomainReAttachHostDevices(virLXCDriverPtr driver,
- virDomainDefPtr def)
-{
- if (!def->nhostdevs)
- return;
-
- virLXCDomainReAttachHostUsbDevices(driver, def->name, def->hostdevs,
- def->nhostdevs);
-}
diff --git a/src/lxc/lxc_hostdev.h b/src/lxc/lxc_hostdev.h
deleted file mode 100644
index 41bb178..0000000
--- a/src/lxc/lxc_hostdev.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * virLXC_hostdev.h: VIRLXC hostdev management
- *
- * Copyright (C) 2006-2007, 2009-2010 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: Daniel P. Berrange <berrange(a)redhat.com>
- */
-
-#ifndef __LXC_HOSTDEV_H__
-# define __LXC_HOSTDEV_H__
-
-# include "lxc_conf.h"
-# include "domain_conf.h"
-
-int virLXCUpdateActiveUsbHostdevs(virLXCDriverPtr driver,
- virDomainDefPtr def);
-int virLXCFindHostdevUSBDevice(virDomainHostdevDefPtr hostdev,
- bool mandatory,
- virUSBDevicePtr *usb);
-int virLXCPrepareHostdevUSBDevices(virLXCDriverPtr driver,
- const char *name,
- virUSBDeviceListPtr list);
-int virLXCPrepareHostDevices(virLXCDriverPtr driver,
- virDomainDefPtr def);
-void virLXCDomainReAttachHostDevices(virLXCDriverPtr driver,
- virDomainDefPtr def);
-
-#endif /* __LXC_HOSTDEV_H__ */
diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c
index 4835bd5..ed35853 100644
--- a/src/lxc/lxc_process.c
+++ b/src/lxc/lxc_process.c
@@ -45,11 +45,11 @@
#include "virerror.h"
#include "virlog.h"
#include "vircommand.h"
-#include "lxc_hostdev.h"
#include "virhook.h"
#include "virstring.h"
#include "viratomic.h"
#include "virprocess.h"
+#include "virhostdev.h"
#define VIR_FROM_THIS VIR_FROM_LXC
@@ -151,6 +151,7 @@ static void virLXCProcessCleanup(virLXCDriverPtr driver,
virLXCDomainObjPrivatePtr priv = vm->privateData;
virNetDevVPortProfilePtr vport = NULL;
virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
+ virHostdevManagerPtr hostdev_mgr;
VIR_DEBUG("Stopping VM name=%s pid=%d reason=%d",
vm->def->name, (int)vm->pid, (int)reason);
@@ -186,7 +187,11 @@ static void virLXCProcessCleanup(virLXCDriverPtr driver,
if (virAtomicIntDecAndTest(&driver->nactive) && driver->inhibitCallback)
driver->inhibitCallback(false, driver->inhibitOpaque);
- virLXCDomainReAttachHostDevices(driver, vm->def);
+ hostdev_mgr = virHostdevManagerGetDefault();
+ virHostdevReAttachDomainHostdevs(hostdev_mgr,
+ LXC_DRIVER_NAME,
+ vm->def,
+ VIR_SP_USB_HOSTDEV);
for (i = 0; i < vm->def->nnets; i++) {
virDomainNetDefPtr iface = vm->def->nets[i];
@@ -973,6 +978,7 @@ int virLXCProcessStart(virConnectPtr conn,
virErrorPtr err = NULL;
virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
virCgroupPtr selfcgroup;
+ virHostdevManagerPtr hostdev_mgr;
if (virCgroupNewSelf(&selfcgroup) < 0)
return -1;
@@ -1058,7 +1064,11 @@ int virLXCProcessStart(virConnectPtr conn,
/* Must be run before security labelling */
VIR_DEBUG("Preparing host devices");
- if (virLXCPrepareHostDevices(driver, vm->def) < 0)
+ hostdev_mgr = virHostdevManagerGetDefault();
+ if (virHostdevPrepareDomainHostdevs(hostdev_mgr,
+ LXC_DRIVER_NAME,
+ vm->def,
+ VIR_SP_USB_HOSTDEV) < 0)
goto cleanup;
/* Here we open all the PTYs we need on the host OS side.
@@ -1396,6 +1406,7 @@ virLXCProcessReconnectDomain(virDomainObjPtr vm,
{
virLXCDriverPtr driver = opaque;
virLXCDomainObjPrivatePtr priv;
+ virHostdevManagerPtr hostdev_mgr;
int ret = -1;
virObjectLock(vm);
@@ -1428,7 +1439,9 @@ virLXCProcessReconnectDomain(virDomainObjPtr vm,
goto error;
}
- if (virLXCUpdateActiveUsbHostdevs(driver, vm->def) < 0)
+ hostdev_mgr = virHostdevManagerGetDefault();
+ if (virHostdevPrepareDomainHostdevs(hostdev_mgr, LXC_DRIVER_NAME,
+ vm->def, VIR_SP_USB_HOSTDEV) < 0)
goto error;
if (virSecurityManagerReserveLabel(driver->securityManager,
--
1.6.0.2
1
0
[libvirt] [RESEND][PATCHv5 3/4] change qemu driver to use hostdev common library
by Chunyan Liu 12 Sep '13
by Chunyan Liu 12 Sep '13
12 Sep '13
Change qemu driver to use hostdev common library instead of APIs in
qemu_hostdev.[ch]
Signed-off-by: Chunyan Liu <cyliu(a)suse.com>
---
po/POTFILES.in | 1 -
src/Makefile.am | 1 -
src/qemu/qemu_command.c | 1 -
src/qemu/qemu_conf.h | 9 +-
src/qemu/qemu_driver.c | 72 +---
src/qemu/qemu_hostdev.c | 1289 -----------------------------------------------
src/qemu/qemu_hostdev.h | 72 ---
src/qemu/qemu_hotplug.c | 126 ++---
src/qemu/qemu_process.c | 34 +-
9 files changed, 87 insertions(+), 1518 deletions(-)
delete mode 100644 src/qemu/qemu_hostdev.c
delete mode 100644 src/qemu/qemu_hostdev.h
diff --git a/po/POTFILES.in b/po/POTFILES.in
index d01cb99..2fc7e67 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -99,7 +99,6 @@ src/qemu/qemu_command.c
src/qemu/qemu_conf.c
src/qemu/qemu_domain.c
src/qemu/qemu_driver.c
-src/qemu/qemu_hostdev.c
src/qemu/qemu_hotplug.c
src/qemu/qemu_migration.c
src/qemu/qemu_monitor.c
diff --git a/src/Makefile.am b/src/Makefile.am
index e563960..c3a8ba0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -654,7 +654,6 @@ QEMU_DRIVER_SOURCES = \
qemu/qemu_command.c qemu/qemu_command.h \
qemu/qemu_domain.c qemu/qemu_domain.h \
qemu/qemu_cgroup.c qemu/qemu_cgroup.h \
- qemu/qemu_hostdev.c qemu/qemu_hostdev.h \
qemu/qemu_hotplug.c qemu/qemu_hotplug.h \
qemu/qemu_hotplugpriv.h \
qemu/qemu_conf.c qemu/qemu_conf.h \
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 1521431..3abb88d 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -24,7 +24,6 @@
#include <config.h>
#include "qemu_command.h"
-#include "qemu_hostdev.h"
#include "qemu_capabilities.h"
#include "qemu_bridge_filter.h"
#include "cpu/cpu.h"
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index 206f2c6..97c8501 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -52,6 +52,7 @@
# error "Port me"
# endif
+# define QEMU_DRIVER_NAME "QEMU"
typedef struct _virQEMUDriver virQEMUDriver;
typedef virQEMUDriver *virQEMUDriverPtr;
@@ -204,14 +205,6 @@ struct _virQEMUDriver {
/* Immutable pointer. self-locking APIs */
virSecurityManagerPtr securityManager;
- /* Immutable pointers. Requires locks to be held before
- * calling APIs. activePciHostdevs must be locked before
- * inactivePciHostdevs */
- virPCIDeviceListPtr activePciHostdevs;
- virPCIDeviceListPtr inactivePciHostdevs;
- virUSBDeviceListPtr activeUsbHostdevs;
- virSCSIDeviceListPtr activeScsiHostdevs;
-
/* Immutable pointer. Unsafe APIs. XXX */
virHashTablePtr sharedDevices;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index bbf2d23..b289a30 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -50,7 +50,6 @@
#include "qemu_capabilities.h"
#include "qemu_command.h"
#include "qemu_cgroup.h"
-#include "qemu_hostdev.h"
#include "qemu_hotplug.h"
#include "qemu_monitor.h"
#include "qemu_bridge_filter.h"
@@ -94,11 +93,10 @@
#include "virstring.h"
#include "viraccessapicheck.h"
#include "viraccessapicheckqemu.h"
+#include "virhostdev.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
-#define QEMU_DRIVER_NAME "QEMU"
-
#define QEMU_NB_MEM_PARAM 3
#define QEMU_NB_BLOCK_IO_TUNE_PARAM 6
@@ -691,18 +689,6 @@ qemuStateInitialize(bool privileged,
if (qemuSecurityInit(qemu_driver) < 0)
goto error;
- if ((qemu_driver->activePciHostdevs = virPCIDeviceListNew()) == NULL)
- goto error;
-
- if ((qemu_driver->activeUsbHostdevs = virUSBDeviceListNew()) == NULL)
- goto error;
-
- if ((qemu_driver->inactivePciHostdevs = virPCIDeviceListNew()) == NULL)
- goto error;
-
- if ((qemu_driver->activeScsiHostdevs = virSCSIDeviceListNew()) == NULL)
- goto error;
-
if (!(qemu_driver->sharedDevices = virHashCreate(30, qemuSharedDeviceEntryFree)))
goto error;
@@ -983,9 +969,6 @@ qemuStateCleanup(void) {
virNWFilterUnRegisterCallbackDriver(&qemuCallbackDriver);
virObjectUnref(qemu_driver->config);
- virObjectUnref(qemu_driver->activePciHostdevs);
- virObjectUnref(qemu_driver->inactivePciHostdevs);
- virObjectUnref(qemu_driver->activeUsbHostdevs);
virHashFree(qemu_driver->sharedDevices);
virObjectUnref(qemu_driver->caps);
virQEMUCapsCacheFree(qemu_driver->qemuCapsCache);
@@ -10689,12 +10672,12 @@ qemuNodeDeviceDetachFlags(virNodeDevicePtr dev,
const char *driverName,
unsigned int flags)
{
- virQEMUDriverPtr driver = dev->conn->privateData;
virPCIDevicePtr pci = NULL;
unsigned domain = 0, bus = 0, slot = 0, function = 0;
int ret = -1;
virNodeDeviceDefPtr def = NULL;
char *xml = NULL;
+ virHostdevManagerPtr hostdev_mgr;
virCheckFlags(0, -1);
@@ -10728,18 +10711,12 @@ qemuNodeDeviceDetachFlags(virNodeDevicePtr dev,
goto cleanup;
}
- virObjectLock(driver->activePciHostdevs);
- virObjectLock(driver->inactivePciHostdevs);
-
- if (virPCIDeviceDetach(pci, driver->activePciHostdevs,
- driver->inactivePciHostdevs) < 0) {
- goto out;
+ hostdev_mgr = virHostdevManagerGetDefault();
+ if (virHostdevPciNodeDeviceDetach(hostdev_mgr, pci) < 0) {
+ goto cleanup;
}
ret = 0;
-out:
- virObjectUnlock(driver->inactivePciHostdevs);
- virObjectUnlock(driver->activePciHostdevs);
cleanup:
virPCIDeviceFree(pci);
virNodeDeviceDefFree(def);
@@ -10756,13 +10733,12 @@ qemuNodeDeviceDettach(virNodeDevicePtr dev)
static int
qemuNodeDeviceReAttach(virNodeDevicePtr dev)
{
- virQEMUDriverPtr driver = dev->conn->privateData;
virPCIDevicePtr pci = NULL;
- virPCIDevicePtr other;
unsigned domain = 0, bus = 0, slot = 0, function = 0;
int ret = -1;
virNodeDeviceDefPtr def = NULL;
char *xml = NULL;
+ virHostdevManagerPtr hostdev_mgr;
xml = virNodeDeviceGetXMLDesc(dev, 0);
if (!xml)
@@ -10782,33 +10758,12 @@ qemuNodeDeviceReAttach(virNodeDevicePtr dev)
if (!pci)
goto cleanup;
- virObjectLock(driver->activePciHostdevs);
- virObjectLock(driver->inactivePciHostdevs);
- other = virPCIDeviceListFind(driver->activePciHostdevs, pci);
- if (other) {
- const char *other_name = virPCIDeviceGetUsedBy(other);
-
- if (other_name)
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("PCI device %s is still in use by domain %s"),
- virPCIDeviceGetName(pci), other_name);
- else
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("PCI device %s is still in use"),
- virPCIDeviceGetName(pci));
- goto out;
- }
-
- virPCIDeviceReattachInit(pci);
-
- if (virPCIDeviceReattach(pci, driver->activePciHostdevs,
- driver->inactivePciHostdevs) < 0)
+ hostdev_mgr = virHostdevManagerGetDefault();
+ if (virHostdevPciNodeDeviceReAttach(hostdev_mgr, pci) < 0)
goto out;
ret = 0;
out:
- virObjectUnlock(driver->inactivePciHostdevs);
- virObjectUnlock(driver->activePciHostdevs);
virPCIDeviceFree(pci);
cleanup:
virNodeDeviceDefFree(def);
@@ -10819,12 +10774,12 @@ cleanup:
static int
qemuNodeDeviceReset(virNodeDevicePtr dev)
{
- virQEMUDriverPtr driver = dev->conn->privateData;
virPCIDevicePtr pci;
unsigned domain = 0, bus = 0, slot = 0, function = 0;
int ret = -1;
virNodeDeviceDefPtr def = NULL;
char *xml = NULL;
+ virHostdevManagerPtr hostdev_mgr;
xml = virNodeDeviceGetXMLDesc(dev, 0);
if (!xml)
@@ -10844,17 +10799,12 @@ qemuNodeDeviceReset(virNodeDevicePtr dev)
if (!pci)
goto cleanup;
- virObjectLock(driver->activePciHostdevs);
- virObjectLock(driver->inactivePciHostdevs);
-
- if (virPCIDeviceReset(pci, driver->activePciHostdevs,
- driver->inactivePciHostdevs) < 0)
+ hostdev_mgr = virHostdevManagerGetDefault();
+ if (virHostdevPciNodeDeviceReset(hostdev_mgr, pci) < 0)
goto out;
ret = 0;
out:
- virObjectUnlock(driver->inactivePciHostdevs);
- virObjectUnlock(driver->activePciHostdevs);
virPCIDeviceFree(pci);
cleanup:
virNodeDeviceDefFree(def);
diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c
deleted file mode 100644
index 21fe47f..0000000
--- a/src/qemu/qemu_hostdev.c
+++ /dev/null
@@ -1,1289 +0,0 @@
-/*
- * qemu_hostdev.c: QEMU hostdev management
- *
- * 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: Daniel P. Berrange <berrange(a)redhat.com>
- */
-
-#include <config.h>
-
-#include "qemu_hostdev.h"
-#include "virlog.h"
-#include "virerror.h"
-#include "viralloc.h"
-#include "virpci.h"
-#include "virusb.h"
-#include "virscsi.h"
-#include "virnetdev.h"
-
-#define VIR_FROM_THIS VIR_FROM_QEMU
-
-static virPCIDeviceListPtr
-qemuGetPciHostDeviceList(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);
- if (hostdev->source.subsys.u.pci.backend
- == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
- if (virPCIDeviceSetStubDriver(dev, "vfio-pci") < 0) {
- virObjectUnref(list);
- return NULL;
- }
- } else {
- if (virPCIDeviceSetStubDriver(dev, "pci-stub") < 0) {
- virObjectUnref(list);
- return NULL;
- }
- }
- }
-
- return list;
-}
-
-/*
- * qemuGetActivePciHostDeviceList - make a new list with a *copy* of
- * every virPCIDevice object that is found on the activePciHostdevs
- * list *and* is in the hostdev list for this domain.
- *
- * Return the new list, or NULL if there was a failure.
- *
- * Pre-condition: driver->activePciHostdevs is locked
- */
-static virPCIDeviceListPtr
-qemuGetActivePciHostDeviceList(virQEMUDriverPtr driver,
- virDomainHostdevDefPtr *hostdevs,
- int nhostdevs)
-{
- virPCIDeviceListPtr list;
- size_t i;
-
- if (!(list = virPCIDeviceListNew()))
- return NULL;
-
- for (i = 0; i < nhostdevs; i++) {
- virDomainHostdevDefPtr hostdev = hostdevs[i];
- virDevicePCIAddressPtr addr;
- virPCIDevicePtr activeDev;
-
- if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
- continue;
- if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
- continue;
-
- addr = &hostdev->source.subsys.u.pci.addr;
- activeDev = virPCIDeviceListFindByIDs(driver->activePciHostdevs,
- addr->domain, addr->bus,
- addr->slot, addr->function);
- if (activeDev && virPCIDeviceListAddCopy(list, activeDev) < 0) {
- virObjectUnref(list);
- return NULL;
- }
- }
-
- return list;
-}
-
-int qemuUpdateActivePciHostdevs(virQEMUDriverPtr driver,
- virDomainDefPtr def)
-{
- virDomainHostdevDefPtr hostdev = NULL;
- virPCIDevicePtr dev = NULL;
- size_t i;
- int ret = -1;
-
- if (!def->nhostdevs)
- return 0;
-
- virObjectLock(driver->activePciHostdevs);
- virObjectLock(driver->inactivePciHostdevs);
-
- for (i = 0; i < def->nhostdevs; i++) {
- hostdev = def->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);
- if (hostdev->source.subsys.u.pci.backend
- == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
- if (virPCIDeviceSetStubDriver(dev, "vfio-pci") < 0)
- goto cleanup;
- } else {
- if (virPCIDeviceSetStubDriver(dev, "pci-stub") < 0)
- goto cleanup;
-
- }
- virPCIDeviceSetUsedBy(dev, def->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(driver->activePciHostdevs, dev) < 0)
- goto cleanup;
- dev = NULL;
- }
-
- ret = 0;
-cleanup:
- virPCIDeviceFree(dev);
- virObjectUnlock(driver->activePciHostdevs);
- virObjectUnlock(driver->inactivePciHostdevs);
- return ret;
-}
-
-int
-qemuUpdateActiveUsbHostdevs(virQEMUDriverPtr driver,
- virDomainDefPtr def)
-{
- virDomainHostdevDefPtr hostdev = NULL;
- size_t i;
- int ret = -1;
-
- if (!def->nhostdevs)
- return 0;
-
- virObjectLock(driver->activeUsbHostdevs);
- for (i = 0; i < def->nhostdevs; i++) {
- virUSBDevicePtr usb = NULL;
- hostdev = def->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 domain %s",
- hostdev->source.subsys.u.usb.bus,
- hostdev->source.subsys.u.usb.device,
- def->name);
- continue;
- }
-
- virUSBDeviceSetUsedBy(usb, def->name);
-
- if (virUSBDeviceListAdd(driver->activeUsbHostdevs, usb) < 0) {
- virUSBDeviceFree(usb);
- goto cleanup;
- }
- }
- ret = 0;
-cleanup:
- virObjectUnlock(driver->activeUsbHostdevs);
- return ret;
-}
-
-int
-qemuUpdateActiveScsiHostdevs(virQEMUDriverPtr driver,
- virDomainDefPtr def)
-{
- virDomainHostdevDefPtr hostdev = NULL;
- size_t i;
- int ret = -1;
-
- if (!def->nhostdevs)
- return 0;
-
- virObjectLock(driver->activeScsiHostdevs);
- for (i = 0; i < def->nhostdevs; i++) {
- virSCSIDevicePtr scsi = NULL;
- hostdev = def->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, def->name);
-
- if (virSCSIDeviceListAdd(driver->activeScsiHostdevs, scsi) < 0) {
- virSCSIDeviceFree(scsi);
- goto cleanup;
- }
- }
- ret = 0;
-
-cleanup:
- virObjectUnlock(driver->activeScsiHostdevs);
- return ret;
-}
-
-static int
-qemuDomainHostdevPciSysfsPath(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);
-}
-
-int
-qemuDomainHostdevIsVirtualFunction(virDomainHostdevDefPtr hostdev)
-{
- char *sysfs_path = NULL;
- int ret = -1;
-
- if (qemuDomainHostdevPciSysfsPath(hostdev, &sysfs_path) < 0)
- return ret;
-
- ret = virPCIIsVirtualFunction(sysfs_path);
-
- VIR_FREE(sysfs_path);
-
- return ret;
-}
-
-static int
-qemuDomainHostdevNetDevice(virDomainHostdevDefPtr hostdev, char **linkdev,
- int *vf)
-{
- int ret = -1;
- char *sysfs_path = NULL;
-
- if (qemuDomainHostdevPciSysfsPath(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
-qemuDomainHostdevNetConfigVirtPortProfile(const char *linkdev, int vf,
- virNetDevVPortProfilePtr virtPort,
- const virMacAddrPtr macaddr,
- const unsigned char *uuid,
- bool 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;
-}
-
-int
-qemuDomainHostdevNetConfigReplace(virDomainHostdevDefPtr hostdev,
- const unsigned char *uuid,
- char *stateDir)
-{
- char *linkdev = NULL;
- virNetDevVlanPtr vlan;
- virNetDevVPortProfilePtr virtPort;
- int ret = -1;
- int vf = -1;
- int vlanid = -1;
- bool port_profile_associate = true;
- int isvf;
-
- isvf = qemuDomainHostdevIsVirtualFunction(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 (qemuDomainHostdevNetDevice(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 = qemuDomainHostdevNetConfigVirtPortProfile(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;
-}
-
-int
-qemuDomainHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev,
- char *stateDir)
-{
- char *linkdev = NULL;
- virNetDevVPortProfilePtr virtPort;
- int ret = -1;
- int vf = -1;
- bool port_profile_associate = false;
- int isvf;
-
- isvf = qemuDomainHostdevIsVirtualFunction(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 (qemuDomainHostdevNetDevice(hostdev, &linkdev, &vf) < 0)
- return ret;
-
- virtPort = virDomainNetGetActualVirtPortProfile(
- hostdev->parent.data.net)
- if (virtPort)
- ret = qemuDomainHostdevNetConfigVirtPortProfile(linkdev, vf, virtPort,
- &hostdev->parent.data.net->mac, NULL,
- port_profile_associate);
- else
- ret = virNetDevRestoreNetConfig(linkdev, vf, stateDir);
-
- VIR_FREE(linkdev);
-
- return ret;
-}
-
-int qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver,
- const char *name,
- const unsigned char *uuid,
- virDomainHostdevDefPtr *hostdevs,
- int nhostdevs)
-{
- virPCIDeviceListPtr pcidevs;
- int last_processed_hostdev_vf = -1;
- size_t i;
- int ret = -1;
- virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
-
- virObjectLock(driver->activePciHostdevs);
- virObjectLock(driver->inactivePciHostdevs);
-
- if (!(pcidevs = qemuGetPciHostDeviceList(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 pci-stub.ko
- */
-
- for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
- virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
- virPCIDevicePtr other;
-
- if (!virPCIDeviceIsAssignable(dev, !cfg->relaxedACS)) {
- 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 driver->activePciHostdevs.
- */
- if ((other = virPCIDeviceListFind(driver->activePciHostdevs, dev))) {
- const char *other_name = virPCIDeviceGetUsedBy(other);
-
- if (other_name)
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("PCI device %s is in use by domain %s"),
- virPCIDeviceGetName(dev), other_name);
- else
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("PCI device %s is already in use"),
- virPCIDeviceGetName(dev));
- goto cleanup;
- }
- }
-
- /* Loop 2: detach managed devices (i.e. bind to appropriate stub driver) */
- for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
- virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
- if (virPCIDeviceGetManaged(dev) &&
- virPCIDeviceDetach(dev, driver->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, driver->activePciHostdevs,
- driver->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 (qemuDomainHostdevNetConfigReplace(hostdev, uuid,
- cfg->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(driver->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(driver->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(driver->activePciHostdevs, dev);
-
- if (activeDev)
- virPCIDeviceSetUsedBy(activeDev, 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().
- */
- for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
- virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
- virPCIDeviceListSteal(driver->activePciHostdevs, dev);
- }
-
-resetvfnetconfig:
- for (i = 0; last_processed_hostdev_vf != -1 &&
- i < last_processed_hostdev_vf; i++) {
- virDomainHostdevDefPtr hostdev = hostdevs[i];
- if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET &&
- hostdev->parent.data.net) {
- qemuDomainHostdevNetConfigRestore(hostdev, cfg->stateDir);
- }
- }
-
-reattachdevs:
- for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
- virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
-
- /* NB: This doesn't actually re-bind to original driver, just
- * unbinds from the stub driver
- */
- virPCIDeviceReattach(dev, driver->activePciHostdevs, NULL);
- }
-
-cleanup:
- virObjectUnlock(driver->activePciHostdevs);
- virObjectUnlock(driver->inactivePciHostdevs);
- virObjectUnref(pcidevs);
- virObjectUnref(cfg);
- return ret;
-}
-
-int
-qemuPrepareHostdevUSBDevices(virQEMUDriverPtr driver,
- const char *name,
- virUSBDeviceListPtr list)
-{
- size_t i, j;
- unsigned int count;
- virUSBDevicePtr tmp;
-
- virObjectLock(driver->activeUsbHostdevs);
- count = virUSBDeviceListCount(list);
-
- for (i = 0; i < count; i++) {
- virUSBDevicePtr usb = virUSBDeviceListGet(list, i);
- if ((tmp = virUSBDeviceListFind(driver->activeUsbHostdevs, usb))) {
- const char *other_name = virUSBDeviceGetUsedBy(tmp);
-
- if (other_name)
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("USB device %s is in use by domain %s"),
- virUSBDeviceGetName(tmp), other_name);
- else
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("USB device %s is already in use"),
- virUSBDeviceGetName(tmp));
- goto error;
- }
-
- virUSBDeviceSetUsedBy(usb, name);
- VIR_DEBUG("Adding %03d.%03d dom=%s to activeUsbHostdevs",
- virUSBDeviceGetBus(usb), virUSBDeviceGetDevno(usb), name);
- /*
- * The caller is responsible to steal these usb devices
- * from the virUSBDeviceList that passed in on success,
- * perform rollback on failure.
- */
- if (virUSBDeviceListAdd(driver->activeUsbHostdevs, usb) < 0)
- goto error;
- }
-
- virObjectUnlock(driver->activeUsbHostdevs);
- return 0;
-
-error:
- for (j = 0; j < i; j++) {
- tmp = virUSBDeviceListGet(list, i);
- virUSBDeviceListSteal(driver->activeUsbHostdevs, tmp);
- }
- virObjectUnlock(driver->activeUsbHostdevs);
- return -1;
-}
-
-int
-qemuFindHostdevUSBDevice(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
-qemuPrepareHostUSBDevices(virQEMUDriverPtr driver,
- virDomainDefPtr def,
- bool coldBoot)
-{
- size_t i;
- int ret = -1;
- virUSBDeviceListPtr list;
- virUSBDevicePtr tmp;
- virDomainHostdevDefPtr *hostdevs = def->hostdevs;
- int nhostdevs = def->nhostdevs;
-
- /* 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. See qemuPrepareHostdevPCIDevices()
- */
- 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 (qemuFindHostdevUSBDevice(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 driver list. However, if something goes
- * wrong, perform rollback.
- */
- if (qemuPrepareHostdevUSBDevices(driver, def->name, list) < 0)
- goto cleanup;
-
- /* Loop 2: Temporary list was successfully merged with
- * driver 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
-qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver,
- const char *name,
- virDomainHostdevDefPtr *hostdevs,
- int nhostdevs)
-{
- size_t i, j;
- int count;
- virSCSIDeviceListPtr list;
- virSCSIDevicePtr tmp;
-
- /* Loop 1: Add the shared scsi host device to shared device
- * table.
- */
- for (i = 0; i < nhostdevs; i++) {
- virDomainDeviceDef dev;
-
- dev.type = VIR_DOMAIN_DEVICE_HOSTDEV;
- dev.data.hostdev = hostdevs[i];
-
- if (qemuAddSharedDevice(driver, &dev, name) < 0)
- return -1;
-
- if (qemuSetUnprivSGIO(&dev) < 0)
- return -1;
- }
-
- /* To prevent situation where SCSI device is assigned to two domains
- * we need to keep a list of currently assigned SCSI devices.
- * This is done in several loops which cannot be joined into one big
- * loop. See qemuPrepareHostdevPCIDevices()
- */
- if (!(list = virSCSIDeviceListNew()))
- goto cleanup;
-
- /* Loop 2: 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 3: Mark devices in temporary list as used by @name
- * and add them to driver list. However, if something goes
- * wrong, perform rollback.
- */
- virObjectLock(driver->activeScsiHostdevs);
- count = virSCSIDeviceListCount(list);
-
- for (i = 0; i < count; i++) {
- virSCSIDevicePtr scsi = virSCSIDeviceListGet(list, i);
- if ((tmp = virSCSIDeviceListFind(driver->activeScsiHostdevs, scsi))) {
- const char *other_name = virSCSIDeviceGetUsedBy(tmp);
-
- if (other_name)
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("SCSI device %s is in use by domain %s"),
- virSCSIDeviceGetName(tmp), other_name);
- else
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("SCSI device %s is already in use"),
- virSCSIDeviceGetName(tmp));
- goto error;
- }
-
- virSCSIDeviceSetUsedBy(scsi, name);
- VIR_DEBUG("Adding %s to activeScsiHostdevs", virSCSIDeviceGetName(scsi));
-
- if (virSCSIDeviceListAdd(driver->activeScsiHostdevs, scsi) < 0)
- goto error;
- }
-
- virObjectUnlock(driver->activeScsiHostdevs);
-
- /* Loop 4: 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, i);
- virSCSIDeviceListSteal(driver->activeScsiHostdevs, tmp);
- }
- virObjectUnlock(driver->activeScsiHostdevs);
-cleanup:
- virObjectUnref(list);
- return -1;
-}
-
-int qemuPrepareHostDevices(virQEMUDriverPtr driver,
- virDomainDefPtr def,
- bool coldBoot)
-{
- if (!def->nhostdevs)
- return 0;
-
- if (qemuPrepareHostdevPCIDevices(driver, def->name, def->uuid,
- def->hostdevs, def->nhostdevs) < 0)
- return -1;
-
- if (qemuPrepareHostUSBDevices(driver, def, coldBoot) < 0)
- return -1;
-
- if (qemuPrepareHostdevSCSIDevices(driver, def->name,
- def->hostdevs, def->nhostdevs) < 0)
- return -1;
-
- return 0;
-}
-
-
-/*
- * Pre-condition: driver->inactivePciHostdevs & driver->activePciHostdevs
- * are locked
- */
-void qemuReattachPciDevice(virPCIDevicePtr dev, virQEMUDriverPtr driver)
-{
- int retries = 100;
-
- /* If the device is not managed and was attached to guest
- * successfully, it must have been inactive.
- */
- if (!virPCIDeviceGetManaged(dev)) {
- if (virPCIDeviceListAdd(driver->inactivePciHostdevs, dev) < 0)
- virPCIDeviceFree(dev);
- return;
- }
-
- while (virPCIDeviceWaitForCleanup(dev, "kvm_assigned_device")
- && retries) {
- usleep(100*1000);
- retries--;
- }
-
- if (virPCIDeviceReattach(dev, driver->activePciHostdevs,
- driver->inactivePciHostdevs) < 0) {
- virErrorPtr err = virGetLastError();
- VIR_ERROR(_("Failed to re-attach PCI device: %s"),
- err ? err->message : _("unknown error"));
- virResetError(err);
- }
- virPCIDeviceFree(dev);
-}
-
-
-void qemuDomainReAttachHostdevDevices(virQEMUDriverPtr driver,
- const char *name,
- virDomainHostdevDefPtr *hostdevs,
- int nhostdevs)
-{
- virPCIDeviceListPtr pcidevs;
- size_t i;
- virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
-
- virObjectLock(driver->activePciHostdevs);
- virObjectLock(driver->inactivePciHostdevs);
-
- if (!(pcidevs = qemuGetActivePciHostDeviceList(driver,
- 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;
-
- /* delete the copy of the dev from pcidevs if it's used by
- * other domain. Or delete it from activePciHostDevs if it had
- * been used by this domain.
- */
- activeDev = virPCIDeviceListFind(driver->activePciHostdevs, dev);
- if (activeDev &&
- STRNEQ_NULLABLE(name, virPCIDeviceGetUsedBy(activeDev))) {
- virPCIDeviceListDel(pcidevs, dev);
- continue;
- }
-
- virPCIDeviceListDel(driver->activePciHostdevs, dev);
- }
-
- /* At this point, any device that had been used by the guest is in
- * pcidevs, but has been removed from activePciHostdevs.
- */
-
- /*
- * For SRIOV net host devices, unset mac and port profile before
- * reset and reattach device
- */
- 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) {
- qemuDomainHostdevNetConfigRestore(hostdev, cfg->stateDir);
- }
- }
-
- for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
- virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
-
- if (virPCIDeviceReset(dev, driver->activePciHostdevs,
- driver->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);
- qemuReattachPciDevice(dev, driver);
- }
-
- virObjectUnref(pcidevs);
-cleanup:
- virObjectUnlock(driver->activePciHostdevs);
- virObjectUnlock(driver->inactivePciHostdevs);
- virObjectUnref(cfg);
-}
-
-static void
-qemuDomainReAttachHostUsbDevices(virQEMUDriverPtr driver,
- const char *name,
- virDomainHostdevDefPtr *hostdevs,
- int nhostdevs)
-{
- size_t i;
-
- virObjectLock(driver->activeUsbHostdevs);
- for (i = 0; i < nhostdevs; i++) {
- virDomainHostdevDefPtr hostdev = hostdevs[i];
- virUSBDevicePtr usb, tmp;
- const char *used_by = NULL;
-
- 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 domain %s",
- hostdev->source.subsys.u.usb.bus,
- hostdev->source.subsys.u.usb.device,
- name);
- continue;
- }
-
- /* Delete only those USB devices which belongs
- * to domain @name because qemuProcessStart() might
- * have failed because USB device is already taken.
- * Therefore we want to steal only those devices from
- * the list which were taken by @name */
-
- tmp = virUSBDeviceListFind(driver->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;
- }
-
- used_by = virUSBDeviceGetUsedBy(tmp);
- if (STREQ_NULLABLE(used_by, name)) {
- VIR_DEBUG("Removing %03d.%03d dom=%s from activeUsbHostdevs",
- hostdev->source.subsys.u.usb.bus,
- hostdev->source.subsys.u.usb.device,
- name);
-
- virUSBDeviceListDel(driver->activeUsbHostdevs, tmp);
- }
- }
- virObjectUnlock(driver->activeUsbHostdevs);
-}
-
-void
-qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr driver,
- const char *name,
- virDomainHostdevDefPtr *hostdevs,
- int nhostdevs)
-{
- size_t i;
-
- virObjectLock(driver->activeScsiHostdevs);
- for (i = 0; i < nhostdevs; i++) {
- virDomainHostdevDefPtr hostdev = hostdevs[i];
- virSCSIDevicePtr scsi, tmp;
- const char *used_by = NULL;
- virDomainDeviceDef dev;
-
- dev.type = VIR_DOMAIN_DEVICE_HOSTDEV;
- dev.data.hostdev = hostdev;
-
- ignore_value(qemuRemoveSharedDevice(driver, &dev, name));
-
- 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 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,
- name);
- continue;
- }
-
- /* Only delete the devices which are marked as being used by @name,
- * because qemuProcessStart could fail on the half way. */
-
- tmp = virSCSIDeviceListFind(driver->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;
- }
-
- used_by = virSCSIDeviceGetUsedBy(tmp);
- if (STREQ_NULLABLE(used_by, name)) {
- VIR_DEBUG("Removing %s:%d:%d:%d 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,
- name);
-
- virSCSIDeviceListDel(driver->activeScsiHostdevs, tmp);
- }
- }
- virObjectUnlock(driver->activeScsiHostdevs);
-}
-
-void qemuDomainReAttachHostDevices(virQEMUDriverPtr driver,
- virDomainDefPtr def)
-{
- if (!def->nhostdevs)
- return;
-
- qemuDomainReAttachHostdevDevices(driver, def->name, def->hostdevs,
- def->nhostdevs);
-
- qemuDomainReAttachHostUsbDevices(driver, def->name, def->hostdevs,
- def->nhostdevs);
-
- qemuDomainReAttachHostScsiDevices(driver, def->name, def->hostdevs,
- def->nhostdevs);
-}
diff --git a/src/qemu/qemu_hostdev.h b/src/qemu/qemu_hostdev.h
deleted file mode 100644
index 327d4d5..0000000
--- a/src/qemu/qemu_hostdev.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * qemu_hostdev.h: QEMU hostdev management
- *
- * Copyright (C) 2006-2007, 2009-2010 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: Daniel P. Berrange <berrange(a)redhat.com>
- */
-
-#ifndef __QEMU_HOSTDEV_H__
-# define __QEMU_HOSTDEV_H__
-
-# include "qemu_conf.h"
-# include "domain_conf.h"
-
-int qemuUpdateActivePciHostdevs(virQEMUDriverPtr driver,
- virDomainDefPtr def);
-int qemuUpdateActiveUsbHostdevs(virQEMUDriverPtr driver,
- virDomainDefPtr def);
-int qemuUpdateActiveScsiHostdevs(virQEMUDriverPtr driver,
- virDomainDefPtr def);
-int qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver,
- const char *name,
- const unsigned char *uuid,
- virDomainHostdevDefPtr *hostdevs,
- int nhostdevs);
-int qemuFindHostdevUSBDevice(virDomainHostdevDefPtr hostdev,
- bool mandatory,
- virUSBDevicePtr *usb);
-int qemuPrepareHostdevUSBDevices(virQEMUDriverPtr driver,
- const char *name,
- virUSBDeviceListPtr list);
-int qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver,
- const char *name,
- virDomainHostdevDefPtr *hostdevs,
- int nhostdevs);
-int qemuPrepareHostDevices(virQEMUDriverPtr driver,
- virDomainDefPtr def,
- bool coldBoot);
-void qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr driver,
- const char *name,
- virDomainHostdevDefPtr *hostdevs,
- int nhostdevs);
-void qemuReattachPciDevice(virPCIDevicePtr dev, virQEMUDriverPtr driver);
-void qemuDomainReAttachHostdevDevices(virQEMUDriverPtr driver,
- const char *name,
- virDomainHostdevDefPtr *hostdevs,
- int nhostdevs);
-void qemuDomainReAttachHostDevices(virQEMUDriverPtr driver,
- virDomainDefPtr def);
-int qemuDomainHostdevIsVirtualFunction(virDomainHostdevDefPtr hostdev);
-int qemuDomainHostdevNetConfigReplace(virDomainHostdevDefPtr hostdev,
- const unsigned char *uuid,
- char *stateDir);
-int qemuDomainHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev,
- char *stateDir);
-
-#endif /* __QEMU_HOSTDEV_H__ */
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 6cdee44..e659def 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -30,7 +30,7 @@
#include "qemu_domain.h"
#include "qemu_command.h"
#include "qemu_bridge_filter.h"
-#include "qemu_hostdev.h"
+#include "qemu_conf.h"
#include "domain_audit.h"
#include "domain_nwfilter.h"
#include "virlog.h"
@@ -50,6 +50,7 @@
#include "virstoragefile.h"
#include "virstring.h"
#include "virtime.h"
+#include "virhostdev.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
#define CHANGE_MEDIA_RETRIES 10
@@ -1134,12 +1135,19 @@ int qemuDomainAttachHostPciDevice(virQEMUDriverPtr driver,
int configfd = -1;
char *configfd_name = NULL;
bool releaseaddr = false;
+ virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+ virHostdevManagerPtr hostdev_mgr;
+ unsigned int flags = 0;
if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0)
return -1;
- if (qemuPrepareHostdevPCIDevices(driver, vm->def->name, vm->def->uuid,
- &hostdev, 1) < 0)
+ hostdev_mgr = virHostdevManagerGetDefault();
+ if (!cfg->relaxedACS)
+ flags |= VIR_STRICT_ACS_CHECK;
+ if (virHostdevPreparePciHostdevs(hostdev_mgr, QEMU_DRIVER_NAME,
+ vm->def->name, vm->def->uuid,
+ &hostdev, 1, flags) < 0)
return -1;
if (hostdev->source.subsys.u.pci.backend
@@ -1223,7 +1231,8 @@ error:
if (releaseaddr)
qemuDomainReleaseDeviceAddress(vm, hostdev->info, NULL);
- qemuDomainReAttachHostdevDevices(driver, vm->def->name, &hostdev, 1);
+ virHostdevReAttachPciHostdevs(hostdev_mgr, QEMU_DRIVER_NAME,
+ vm->def->name, &hostdev, 1);
VIR_FREE(devstr);
VIR_FREE(configfd_name);
@@ -1408,26 +1417,21 @@ int qemuDomainAttachHostUsbDevice(virQEMUDriverPtr driver,
virDomainHostdevDefPtr hostdev)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
- virUSBDeviceList *list = NULL;
virUSBDevicePtr usb = NULL;
char *devstr = NULL;
bool added = false;
int ret = -1;
+ virHostdevManagerPtr hostdev_mgr;
- if (qemuFindHostdevUSBDevice(hostdev, true, &usb) < 0)
- return -1;
-
- if (!(list = virUSBDeviceListNew()))
- goto cleanup;
-
- if (virUSBDeviceListAdd(list, usb) < 0)
- goto cleanup;
-
- if (qemuPrepareHostdevUSBDevices(driver, vm->def->name, list) < 0)
+ hostdev_mgr = virHostdevManagerGetDefault();
+ if (virHostdevPrepareUsbHostdevs(hostdev_mgr,
+ QEMU_DRIVER_NAME,
+ vm->def->name,
+ &hostdev,
+ 1, 0) < 0)
goto cleanup;
added = true;
- virUSBDeviceListSteal(list, usb);
if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
if (qemuAssignDeviceHostdevAlias(vm->def, hostdev, -1) < 0)
@@ -1456,9 +1460,9 @@ int qemuDomainAttachHostUsbDevice(virQEMUDriverPtr driver,
ret = 0;
cleanup:
if (added)
- virUSBDeviceListSteal(driver->activeUsbHostdevs, usb);
+ virHostdevReAttachUsbHostdevs(hostdev_mgr, QEMU_DRIVER_NAME,
+ vm->def->name, &hostdev, 1);
virUSBDeviceFree(usb);
- virObjectUnref(list);
VIR_FREE(devstr);
return ret;
}
@@ -1472,6 +1476,7 @@ qemuDomainAttachHostScsiDevice(virQEMUDriverPtr driver,
qemuDomainObjPrivatePtr priv = vm->privateData;
char *devstr = NULL;
char *drvstr = NULL;
+ virHostdevManagerPtr hostdev_mgr;
if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DRIVE) ||
!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) ||
@@ -1481,8 +1486,11 @@ qemuDomainAttachHostScsiDevice(virQEMUDriverPtr driver,
return -1;
}
- if (qemuPrepareHostdevSCSIDevices(driver, vm->def->name,
- &hostdev, 1)) {
+ hostdev_mgr = virHostdevManagerGetDefault();
+ if (virHostdevPrepareScsiHostdevs(hostdev_mgr,
+ QEMU_DRIVER_NAME,
+ vm->def->name,
+ &hostdev, 1) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Unable to prepare scsi hostdev: %s:%d:%d:%d"),
hostdev->source.subsys.u.scsi.adapter,
@@ -1530,7 +1538,8 @@ qemuDomainAttachHostScsiDevice(virQEMUDriverPtr driver,
ret = 0;
cleanup:
if (ret < 0)
- qemuDomainReAttachHostScsiDevices(driver, vm->def->name, &hostdev, 1);
+ virHostdevReAttachScsiHostdevs(hostdev_mgr, QEMU_DRIVER_NAME,
+ vm->def->name, &hostdev, 1);
VIR_FREE(drvstr);
VIR_FREE(devstr);
return ret;
@@ -2495,71 +2504,38 @@ qemuDomainRemoveNetDevice(virQEMUDriverPtr driver,
static void
-qemuDomainRemovePCIHostDevice(virQEMUDriverPtr driver,
- virDomainObjPtr vm,
+qemuDomainRemovePCIHostDevice(virDomainObjPtr vm,
virDomainHostdevDefPtr hostdev)
{
- virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
- virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys;
- virPCIDevicePtr pci;
- virPCIDevicePtr activePci;
+ virHostdevManagerPtr hostdev_mgr;
- /*
- * For SRIOV net host devices, unset mac and port profile before
- * reset and reattach device
- */
- if (hostdev->parent.data.net)
- qemuDomainHostdevNetConfigRestore(hostdev, cfg->stateDir);
-
- virObjectLock(driver->activePciHostdevs);
- virObjectLock(driver->inactivePciHostdevs);
- pci = virPCIDeviceNew(subsys->u.pci.addr.domain, subsys->u.pci.addr.bus,
- subsys->u.pci.addr.slot, subsys->u.pci.addr.function);
- if (pci) {
- activePci = virPCIDeviceListSteal(driver->activePciHostdevs, pci);
- if (activePci &&
- virPCIDeviceReset(activePci, driver->activePciHostdevs,
- driver->inactivePciHostdevs) == 0) {
- qemuReattachPciDevice(activePci, driver);
- } else {
- /* reset of the device failed, treat it as if it was returned */
- virPCIDeviceFree(activePci);
- }
- virPCIDeviceFree(pci);
- }
- virObjectUnlock(driver->activePciHostdevs);
- virObjectUnlock(driver->inactivePciHostdevs);
+ hostdev_mgr = virHostdevManagerGetDefault();
+ virHostdevReAttachPciHostdevs(hostdev_mgr, QEMU_DRIVER_NAME,
+ vm->def->name, &hostdev, 1);
qemuDomainReleaseDeviceAddress(vm, hostdev->info, NULL);
- virObjectUnref(cfg);
}
static void
-qemuDomainRemoveUSBHostDevice(virQEMUDriverPtr driver,
- virDomainObjPtr vm ATTRIBUTE_UNUSED,
+qemuDomainRemoveUSBHostDevice(virDomainObjPtr vm,
virDomainHostdevDefPtr hostdev)
{
- virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys;
- virUSBDevicePtr usb;
-
- usb = virUSBDeviceNew(subsys->u.usb.bus, subsys->u.usb.device, NULL);
- if (usb) {
- virObjectLock(driver->activeUsbHostdevs);
- virUSBDeviceListDel(driver->activeUsbHostdevs, usb);
- virObjectUnlock(driver->activeUsbHostdevs);
- virUSBDeviceFree(usb);
- } else {
- VIR_WARN("Unable to find device %03d.%03d in list of used USB devices",
- subsys->u.usb.bus, subsys->u.usb.device);
- }
+ virHostdevManagerPtr hostdev_mgr;
+
+ hostdev_mgr = virHostdevManagerGetDefault();
+ virHostdevReAttachPciHostdevs(hostdev_mgr, QEMU_DRIVER_NAME,
+ vm->def->name, &hostdev, 1);
}
static void
-qemuDomainRemoveSCSIHostDevice(virQEMUDriverPtr driver,
- virDomainObjPtr vm,
+qemuDomainRemoveSCSIHostDevice(virDomainObjPtr vm,
virDomainHostdevDefPtr hostdev)
{
- qemuDomainReAttachHostScsiDevices(driver, vm->def->name, &hostdev, 1);
+ virHostdevManagerPtr hostdev_mgr;
+
+ hostdev_mgr = virHostdevManagerGetDefault();
+ virHostdevReAttachScsiHostdevs(hostdev_mgr, QEMU_DRIVER_NAME,
+ vm->def->name, &hostdev, 1);
}
static void
@@ -2600,13 +2576,13 @@ qemuDomainRemoveHostDevice(virQEMUDriverPtr driver,
switch ((enum virDomainHostdevSubsysType) hostdev->source.subsys.type) {
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
- qemuDomainRemovePCIHostDevice(driver, vm, hostdev);
+ qemuDomainRemovePCIHostDevice(vm, hostdev);
break;
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
- qemuDomainRemoveUSBHostDevice(driver, vm, hostdev);
+ qemuDomainRemoveUSBHostDevice(vm, hostdev);
break;
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
- qemuDomainRemoveSCSIHostDevice(driver, vm, hostdev);
+ qemuDomainRemoveSCSIHostDevice(vm, hostdev);
break;
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
break;
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index c7cec5a..cb64f70 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -39,10 +39,10 @@
#include "qemu_capabilities.h"
#include "qemu_monitor.h"
#include "qemu_command.h"
-#include "qemu_hostdev.h"
#include "qemu_hotplug.h"
#include "qemu_bridge_filter.h"
#include "qemu_migration.h"
+#include "qemu_conf.h"
#include "datatypes.h"
#include "virlog.h"
@@ -65,6 +65,7 @@
#include "viratomic.h"
#include "virnuma.h"
#include "virstring.h"
+#include "virhostdev.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
@@ -3046,6 +3047,8 @@ qemuProcessReconnect(void *opaque)
int reason;
virQEMUDriverConfigPtr cfg;
size_t i;
+ virHostdevManagerPtr hostdev_mgr;
+ unsigned int flags;
memcpy(&oldjob, &data->oldjob, sizeof(oldjob));
@@ -3077,14 +3080,11 @@ qemuProcessReconnect(void *opaque)
priv->agentError = true;
}
- if (qemuUpdateActivePciHostdevs(driver, obj->def) < 0) {
- goto error;
- }
-
- if (qemuUpdateActiveUsbHostdevs(driver, obj->def) < 0)
- goto error;
- if (qemuUpdateActiveScsiHostdevs(driver, obj->def) < 0)
+ hostdev_mgr = virHostdevManagerGetDefault();
+ flags = VIR_SP_PCI_HOSTDEV | VIR_SP_USB_HOSTDEV | VIR_SP_SCSI_HOSTDEV;
+ if (virHostdevPrepareDomainHostdevs(hostdev_mgr, QEMU_DRIVER_NAME,
+ obj->def, flags) < 0)
goto error;
if (qemuConnectCgroup(driver, obj) < 0)
@@ -3481,6 +3481,8 @@ int qemuProcessStart(virConnectPtr conn,
unsigned int stop_flags;
virQEMUDriverConfigPtr cfg;
virCapsPtr caps = NULL;
+ virHostdevManagerPtr hostdev_mgr;
+ unsigned int hostdev_flags;
/* Okay, these are just internal flags,
* but doesn't hurt to check */
@@ -3559,7 +3561,14 @@ int qemuProcessStart(virConnectPtr conn,
/* Must be run before security labelling */
VIR_DEBUG("Preparing host devices");
- if (qemuPrepareHostDevices(driver, vm->def, !migrateFrom) < 0)
+ hostdev_mgr = virHostdevManagerGetDefault();
+ hostdev_flags = VIR_SP_PCI_HOSTDEV | VIR_SP_USB_HOSTDEV | VIR_SP_SCSI_HOSTDEV;
+ if (!migrateFrom)
+ hostdev_flags |= VIR_COLD_BOOT;
+ if (!cfg->relaxedACS)
+ hostdev_flags |= VIR_STRICT_ACS_CHECK;
+ if (virHostdevPrepareDomainHostdevs(hostdev_mgr, QEMU_DRIVER_NAME,
+ vm->def, hostdev_flags) < 0)
goto cleanup;
VIR_DEBUG("Preparing chr devices");
@@ -4101,6 +4110,8 @@ void qemuProcessStop(virQEMUDriverPtr driver,
char *timestamp;
char ebuf[1024];
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+ virHostdevManagerPtr hostdev_mgr;
+ unsigned int hostdev_flags;
VIR_DEBUG("Shutting down VM '%s' pid=%d flags=%x",
vm->def->name, vm->pid, flags);
@@ -4243,7 +4254,10 @@ void qemuProcessStop(virQEMUDriverPtr driver,
priv->ccwaddrs = NULL;
}
- qemuDomainReAttachHostDevices(driver, vm->def);
+ hostdev_mgr = virHostdevManagerGetDefault();
+ hostdev_flags = VIR_SP_PCI_HOSTDEV | VIR_SP_USB_HOSTDEV | VIR_SP_SCSI_HOSTDEV;
+ virHostdevReAttachDomainHostdevs(hostdev_mgr, QEMU_DRIVER_NAME,
+ vm->def, hostdev_flags);
def = vm->def;
for (i = 0; i < def->nnets; i++) {
--
1.6.0.2
1
0
12 Sep '13
Add pci passthrough to libxl driver, support attach-device, detach-device and
start a vm with pci hostdev specified.
Signed-off-by: Chunyan Liu <cyliu(a)suse.com>
---
po/POTFILES.in | 2 +-
src/libxl/libxl_conf.c | 63 +++++++
src/libxl/libxl_conf.h | 4 +
src/libxl/libxl_driver.c | 443 +++++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 510 insertions(+), 2 deletions(-)
diff --git a/po/POTFILES.in b/po/POTFILES.in
index ec205c9..d01cb99 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -159,6 +159,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
@@ -196,7 +197,6 @@ src/util/viruri.c
src/util/virusb.c
src/util/virutil.c
src/util/virxml.c
-src/util/virhostdev.c
src/vbox/vbox_MSCOMGlue.c
src/vbox/vbox_XPCOMCGlue.c
src/vbox/vbox_driver.c
diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c
index d4226b8..31d8f8a 100644
--- a/src/libxl/libxl_conf.c
+++ b/src/libxl/libxl_conf.c
@@ -1128,6 +1128,66 @@ libxlDriverConfigGet(libxlDriverPrivatePtr driver)
return cfg;
}
+int
+libxlMakePci(virDomainHostdevDefPtr hostdev, libxl_device_pci *pcidev)
+{
+ if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
+ return -1;
+ if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
+ return -1;
+
+ pcidev->domain = hostdev->source.subsys.u.pci.addr.domain;
+ pcidev->bus = hostdev->source.subsys.u.pci.addr.bus;
+ pcidev->dev = hostdev->source.subsys.u.pci.addr.slot;
+ pcidev->func = hostdev->source.subsys.u.pci.addr.function;
+
+ return 0;
+}
+
+static int
+libxlMakePciList(virDomainDefPtr def, libxl_domain_config *d_config)
+{
+ virDomainHostdevDefPtr *l_hostdevs = def->hostdevs;
+ size_t nhostdevs = def->nhostdevs;
+ size_t npcidevs = 0;
+ libxl_device_pci *x_pcidevs;
+ size_t i, j;
+
+ if (nhostdevs == 0)
+ return 0;
+
+ if (VIR_ALLOC_N(x_pcidevs, nhostdevs) < 0)
+ return -1;
+
+ for (i = 0, j = 0; i < nhostdevs; i++) {
+ if (l_hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
+ continue;
+ if (l_hostdevs[i]->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
+ continue;
+
+ libxl_device_pci_init(&x_pcidevs[j]);
+
+ if (libxlMakePci(l_hostdevs[i], &x_pcidevs[j]) < 0)
+ goto error;
+
+ npcidevs++;
+ j++;
+ }
+
+ VIR_SHRINK_N(x_pcidevs, nhostdevs, nhostdevs - npcidevs);
+ d_config->pcidevs = x_pcidevs;
+ d_config->num_pcidevs = npcidevs;
+
+ return 0;
+
+error:
+ for (i = 0; i < npcidevs; i++)
+ libxl_device_pci_dispose(&x_pcidevs[i]);
+
+ VIR_FREE(x_pcidevs);
+ return -1;
+}
+
virCapsPtr
libxlMakeCapabilities(libxl_ctx *ctx)
{
@@ -1176,6 +1236,9 @@ libxlBuildDomainConfig(libxlDriverPrivatePtr driver,
if (libxlMakeVfbList(driver, def, d_config) < 0)
return -1;
+ if (libxlMakePciList(def, d_config) < 0)
+ return -1;
+
d_config->on_reboot = def->onReboot;
d_config->on_poweroff = def->onPoweroff;
d_config->on_crash = def->onCrash;
diff --git a/src/libxl/libxl_conf.h b/src/libxl/libxl_conf.h
index 8ba0ee4..31a955a 100644
--- a/src/libxl/libxl_conf.h
+++ b/src/libxl/libxl_conf.h
@@ -38,6 +38,7 @@
# include "virchrdev.h"
+# define LIBXL_DRIVER_NAME "xenlight"
# define LIBXL_VNC_PORT_MIN 5900
# define LIBXL_VNC_PORT_MAX 65535
@@ -148,6 +149,9 @@ libxlMakeVfb(libxlDriverPrivatePtr driver,
virDomainGraphicsDefPtr l_vfb, libxl_device_vfb *x_vfb);
int
+libxlMakePci(virDomainHostdevDefPtr hostdev, libxl_device_pci *pcidev);
+
+int
libxlBuildDomainConfig(libxlDriverPrivatePtr driver,
virDomainObjPtr vm, libxl_domain_config *d_config);
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
index e2a6d44..5bddf45 100644
--- a/src/libxl/libxl_driver.c
+++ b/src/libxl/libxl_driver.c
@@ -52,6 +52,8 @@
#include "virsysinfo.h"
#include "viraccessapicheck.h"
#include "viratomic.h"
+#include "virhostdev.h"
+#include "virhostdev.h"
#define VIR_FROM_THIS VIR_FROM_LIBXL
@@ -328,6 +330,7 @@ libxlVmReap(libxlDriverPrivatePtr driver,
virDomainShutoffReason reason)
{
libxlDomainObjPrivatePtr priv = vm->privateData;
+ virHostdevManagerPtr hostdev_mgr;
if (libxl_domain_destroy(priv->ctx, vm->def->id, NULL) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -335,6 +338,10 @@ libxlVmReap(libxlDriverPrivatePtr driver,
return -1;
}
+ hostdev_mgr = virHostdevManagerGetDefault();
+ virHostdevReAttachDomainHostdevs(hostdev_mgr, LIBXL_DRIVER_NAME,
+ vm->def, VIR_SP_PCI_HOSTDEV);
+
libxlVmCleanup(driver, vm, reason);
return 0;
}
@@ -553,6 +560,7 @@ libxlVmStart(libxlDriverPrivatePtr driver, virDomainObjPtr vm,
int managed_save_fd = -1;
libxlDomainObjPrivatePtr priv = vm->privateData;
libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
+ virHostdevManagerPtr hostdev_mgr;
if (libxlDomainObjPrivateInitCtx(vm) < 0)
goto error;
@@ -611,6 +619,12 @@ libxlVmStart(libxlDriverPrivatePtr driver, virDomainObjPtr vm,
goto error;
}
+ VIR_DEBUG("Preparing host PCI devices");
+ hostdev_mgr = virHostdevManagerGetDefault();
+ if (virHostdevPrepareDomainHostdevs(hostdev_mgr, LIBXL_DRIVER_NAME,
+ vm->def, VIR_SP_PCI_HOSTDEV) < 0)
+ goto error;
+
/* use as synchronous operations => ao_how = NULL and no intermediate reports => ao_progress = NULL */
if (restore_fd < 0)
@@ -706,6 +720,7 @@ libxlReconnectDomain(virDomainObjPtr vm,
libxl_dominfo d_info;
int len;
uint8_t *data = NULL;
+ virHostdevManagerPtr hostdev_mgr;
virObjectLock(vm);
@@ -729,6 +744,13 @@ libxlReconnectDomain(virDomainObjPtr vm,
/* Update domid in case it changed (e.g. reboot) while we were gone? */
vm->def->id = d_info.domid;
+
+ /* Update hostdev state */
+ hostdev_mgr = virHostdevManagerGetDefault();
+ if (virHostdevPrepareDomainHostdevs(hostdev_mgr, LIBXL_DRIVER_NAME,
+ vm->def, VIR_SP_PCI_HOSTDEV) < 0)
+ goto out;
+
virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_UNKNOWN);
if (virAtomicIntInc(&driver->nactive) == 1 && driver->inhibitCallback)
@@ -2896,6 +2918,95 @@ cleanup:
}
static int
+libxlDomainAttachHostPciDevice(libxlDomainObjPrivatePtr priv,
+ virDomainObjPtr vm,
+ virDomainHostdevDefPtr hostdev)
+{
+ libxl_device_pci pcidev;
+ virDomainHostdevDefPtr found;
+ virHostdevManagerPtr hostdev_mgr;
+
+ if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
+ return -1;
+
+ if (virDomainHostdevFind(vm->def, hostdev, &found) >= 0) {
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ _("target pci device %.4x:%.2x:%.2x.%.1x already exists"),
+ 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);
+ return -1;
+ }
+
+ if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0)
+ return -1;
+
+ hostdev_mgr = virHostdevManagerGetDefault();
+ if (virHostdevPreparePciHostdevs(hostdev_mgr, LIBXL_DRIVER_NAME,
+ vm->def->name, vm->def->uuid,
+ &hostdev, 1, 0) < 0) {
+ goto cleanup;
+ }
+
+ if (libxlMakePci(hostdev, &pcidev) < 0)
+ goto reattach_hostdev;
+
+ if (libxl_device_pci_add(priv->ctx, vm->def->id, &pcidev, 0) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("libxenlight failed to attach pci device %.4x:%.2x:%.2x.%.1x"),
+ 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);
+ goto reattach_hostdev;
+ }
+
+ vm->def->hostdevs[vm->def->nhostdevs++] = hostdev;
+ return 0;
+
+reattach_hostdev:
+ virHostdevReAttachPciHostdevs(hostdev_mgr, LIBXL_DRIVER_NAME,
+ vm->def->name, &hostdev, 1);
+
+cleanup:
+ return -1;
+}
+
+static int
+libxlDomainAttachHostDevice(libxlDomainObjPrivatePtr priv,
+ virDomainObjPtr vm,
+ virDomainDeviceDefPtr dev)
+{
+ virDomainHostdevDefPtr hostdev = dev->data.hostdev;
+
+ if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("hostdev mode '%s' not supported"),
+ virDomainHostdevModeTypeToString(hostdev->mode));
+ return -1;
+ }
+
+ switch (hostdev->source.subsys.type) {
+ case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
+ if (libxlDomainAttachHostPciDevice(priv, vm, hostdev) < 0)
+ goto error;
+ break;
+
+ default:
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("hostdev subsys type '%s' not supported"),
+ virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
+ goto error;
+ }
+
+ return 0;
+
+error:
+ return -1;
+}
+
+static int
libxlDomainDetachDeviceDiskLive(libxlDomainObjPrivatePtr priv,
virDomainObjPtr vm, virDomainDeviceDefPtr dev)
{
@@ -2962,6 +3073,12 @@ libxlDomainAttachDeviceLive(libxlDomainObjPrivatePtr priv, virDomainObjPtr vm,
dev->data.disk = NULL;
break;
+ case VIR_DOMAIN_DEVICE_HOSTDEV:
+ ret = libxlDomainAttachHostDevice(priv, vm, dev);
+ if (!ret)
+ dev->data.hostdev = NULL;
+ break;
+
default:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("device type '%s' cannot be attached"),
@@ -2976,6 +3093,8 @@ static int
libxlDomainAttachDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev)
{
virDomainDiskDefPtr disk;
+ virDomainHostdevDefPtr hostdev;
+ virDomainHostdevDefPtr found;
switch (dev->type) {
case VIR_DOMAIN_DEVICE_DISK:
@@ -2990,6 +3109,25 @@ libxlDomainAttachDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev)
/* vmdef has the pointer. Generic codes for vmdef will do all jobs */
dev->data.disk = NULL;
break;
+ case VIR_DOMAIN_DEVICE_HOSTDEV:
+ hostdev = dev->data.hostdev;
+
+ if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
+ return -1;
+
+ if (virDomainHostdevFind(vmdef, hostdev, &found) >= 0) {
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ _("target pci device %.4x:%.2x:%.2x.%.1x\
+ already exists"),
+ 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);
+ return -1;
+ }
+
+ virDomainHostdevInsert(vmdef, hostdev);
+ break;
default:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
@@ -3000,6 +3138,124 @@ libxlDomainAttachDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev)
}
static int
+libxlComparePCIDevice(virDomainDefPtr def ATTRIBUTE_UNUSED,
+ virDomainDeviceDefPtr device ATTRIBUTE_UNUSED,
+ virDomainDeviceInfoPtr info1,
+ void *opaque)
+{
+ virDomainDeviceInfoPtr info2 = opaque;
+
+ if (info1->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI ||
+ info2->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)
+ return 0;
+
+ if (info1->addr.pci.domain == info2->addr.pci.domain &&
+ info1->addr.pci.bus == info2->addr.pci.bus &&
+ info1->addr.pci.slot == info2->addr.pci.slot &&
+ info1->addr.pci.function != info2->addr.pci.function)
+ return -1;
+ return 0;
+}
+
+static bool
+libxlIsMultiFunctionDevice(virDomainDefPtr def,
+ virDomainDeviceInfoPtr dev)
+{
+ if (virDomainDeviceInfoIterate(def, libxlComparePCIDevice, dev) < 0)
+ return true;
+ return false;
+}
+
+static int
+libxlDomainDetachHostPciDevice(libxlDomainObjPrivatePtr priv,
+ virDomainObjPtr vm,
+ virDomainHostdevDefPtr hostdev)
+{
+ virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys;
+ libxl_device_pci pcidev;
+ virDomainHostdevDefPtr detach;
+ int idx;
+ virHostdevManagerPtr hostdev_mgr;
+
+ if (subsys->type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
+ return -1;
+
+ idx = virDomainHostdevFind(vm->def, hostdev, &detach);
+ if (idx < 0) {
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ _("host pci device %.4x:%.2x:%.2x.%.1x not found"),
+ subsys->u.pci.addr.domain, subsys->u.pci.addr.bus,
+ subsys->u.pci.addr.slot, subsys->u.pci.addr.function);
+ return -1;
+ }
+
+ if (libxlIsMultiFunctionDevice(vm->def, detach->info)) {
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ _("cannot hot unplug multifunction PCI device: %.4x:%.2x:%.2x.%.1x"),
+ subsys->u.pci.addr.domain, subsys->u.pci.addr.bus,
+ subsys->u.pci.addr.slot, subsys->u.pci.addr.function);
+ goto cleanup;
+ }
+
+
+ libxl_device_pci_init(&pcidev);
+
+ if (libxlMakePci(detach, &pcidev) < 0)
+ goto cleanup;
+
+ if (libxl_device_pci_remove(priv->ctx, vm->def->id, &pcidev, 0) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("libxenlight failed to detach pci device\
+ %.4x:%.2x:%.2x.%.1x"),
+ subsys->u.pci.addr.domain, subsys->u.pci.addr.bus,
+ subsys->u.pci.addr.slot, subsys->u.pci.addr.function);
+ goto cleanup;
+ }
+
+ libxl_device_pci_dispose(&pcidev);
+
+ virDomainHostdevRemove(vm->def, idx);
+
+ hostdev_mgr = virHostdevManagerGetDefault();
+ virHostdevReAttachPciHostdevs(hostdev_mgr, LIBXL_DRIVER_NAME,
+ vm->def->name, &hostdev, 1);
+
+ return 0;
+
+cleanup:
+ virDomainHostdevDefFree(detach);
+ return -1;
+}
+
+static int
+libxlDomainDetachHostDevice(libxlDomainObjPrivatePtr priv,
+ virDomainObjPtr vm,
+ virDomainDeviceDefPtr dev)
+{
+ virDomainHostdevDefPtr hostdev = dev->data.hostdev;
+ virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys;
+
+ if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("hostdev mode '%s' not supported"),
+ virDomainHostdevModeTypeToString(hostdev->mode));
+ return -1;
+ }
+
+ switch (subsys->type) {
+ case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
+ return libxlDomainDetachHostPciDevice(priv, vm, hostdev);
+
+ default:
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unexpected hostdev type %d"), subsys->type);
+ break;
+ }
+
+ return -1;
+}
+
+static int
libxlDomainDetachDeviceLive(libxlDomainObjPrivatePtr priv, virDomainObjPtr vm,
virDomainDeviceDefPtr dev)
{
@@ -3010,6 +3266,10 @@ libxlDomainDetachDeviceLive(libxlDomainObjPrivatePtr priv, virDomainObjPtr vm,
ret = libxlDomainDetachDeviceDiskLive(priv, vm, dev);
break;
+ case VIR_DOMAIN_DEVICE_HOSTDEV:
+ ret = libxlDomainDetachHostDevice(priv, vm, dev);
+ break;
+
default:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("device type '%s' cannot be detached"),
@@ -3020,6 +3280,7 @@ libxlDomainDetachDeviceLive(libxlDomainObjPrivatePtr priv, virDomainObjPtr vm,
return ret;
}
+
static int
libxlDomainDetachDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev)
{
@@ -4180,10 +4441,186 @@ libxlConnectSupportsFeature(virConnectPtr conn, int feature)
}
}
+static int
+libxlNodeDeviceGetPciInfo(virNodeDeviceDefPtr def,
+ unsigned *domain,
+ unsigned *bus,
+ unsigned *slot,
+ unsigned *function)
+{
+ virNodeDevCapsDefPtr cap;
+ int ret = -1;
+
+ cap = def->caps;
+ while (cap) {
+ if (cap->type == VIR_NODE_DEV_CAP_PCI_DEV) {
+ *domain = cap->data.pci_dev.domain;
+ *bus = cap->data.pci_dev.bus;
+ *slot = cap->data.pci_dev.slot;
+ *function = cap->data.pci_dev.function;
+ break;
+ }
+
+ cap = cap->next;
+ }
+
+ if (!cap) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("device %s is not a PCI device"), def->name);
+ goto out;
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
+static int
+libxlNodeDeviceDetachFlags(virNodeDevicePtr dev,
+ const char *driverName,
+ unsigned int flags)
+{
+ virPCIDevicePtr pci = NULL;
+ unsigned domain = 0, bus = 0, slot = 0, function = 0;
+ int ret = -1;
+ virNodeDeviceDefPtr def = NULL;
+ char *xml = NULL;
+ virHostdevManagerPtr hostdev_mgr;
+
+ virCheckFlags(0, -1);
+
+ xml = virNodeDeviceGetXMLDesc(dev, 0);
+ if (!xml)
+ goto cleanup;
+
+ def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE, NULL);
+ if (!def)
+ goto cleanup;
+
+ if (virNodeDeviceDetachFlagsEnsureACL(dev->conn, def) < 0)
+ goto cleanup;
+
+ if (libxlNodeDeviceGetPciInfo(def, &domain, &bus, &slot, &function) < 0)
+ goto cleanup;
+
+ pci = virPCIDeviceNew(domain, bus, slot, function);
+ if (!pci)
+ goto cleanup;
+
+ if (!driverName || STREQ(driverName, "xen")) {
+ if (virPCIDeviceSetStubDriver(pci, "pciback") < 0)
+ goto cleanup;
+ } else {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("unsupported driver name '%s'"), driverName);
+ goto cleanup;
+ }
+
+ hostdev_mgr = virHostdevManagerGetDefault();
+ if (virHostdevPciNodeDeviceDetach(hostdev_mgr, pci) < 0) {
+ goto cleanup;
+ }
+
+ ret = 0;
+cleanup:
+ virPCIDeviceFree(pci);
+ virNodeDeviceDefFree(def);
+ VIR_FREE(xml);
+ return ret;
+}
+
+static int
+libxlNodeDeviceDettach(virNodeDevicePtr dev)
+{
+ return libxlNodeDeviceDetachFlags(dev, NULL, 0);
+}
+
+static int
+libxlNodeDeviceReAttach(virNodeDevicePtr dev)
+{
+ virPCIDevicePtr pci = NULL;
+ unsigned domain = 0, bus = 0, slot = 0, function = 0;
+ int ret = -1;
+ virNodeDeviceDefPtr def = NULL;
+ char *xml = NULL;
+ virHostdevManagerPtr hostdev_mgr;
+
+ xml = virNodeDeviceGetXMLDesc(dev, 0);
+ if (!xml)
+ goto cleanup;
+
+ def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE, NULL);
+ if (!def)
+ goto cleanup;
+
+ if (virNodeDeviceReAttachEnsureACL(dev->conn, def) < 0)
+ goto cleanup;
+
+ if (libxlNodeDeviceGetPciInfo(def, &domain, &bus, &slot, &function) < 0)
+ goto cleanup;
+
+ pci = virPCIDeviceNew(domain, bus, slot, function);
+ if (!pci)
+ goto cleanup;
+
+ hostdev_mgr = virHostdevManagerGetDefault();
+ if (virHostdevPciNodeDeviceReAttach(hostdev_mgr, pci) < 0)
+ goto out;
+
+ ret = 0;
+out:
+ virPCIDeviceFree(pci);
+cleanup:
+ virNodeDeviceDefFree(def);
+ VIR_FREE(xml);
+ return ret;
+}
+
+static int
+libxlNodeDeviceReset(virNodeDevicePtr dev)
+{
+ virPCIDevicePtr pci;
+ unsigned domain = 0, bus = 0, slot = 0, function = 0;
+ int ret = -1;
+ virNodeDeviceDefPtr def = NULL;
+ char *xml = NULL;
+ virHostdevManagerPtr hostdev_mgr;
+
+ xml = virNodeDeviceGetXMLDesc(dev, 0);
+ if (!xml)
+ goto cleanup;
+
+ def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE, NULL);
+ if (!def)
+ goto cleanup;
+
+ if (virNodeDeviceResetEnsureACL(dev->conn, def) < 0)
+ goto cleanup;
+
+ if (libxlNodeDeviceGetPciInfo(def, &domain, &bus, &slot, &function) < 0)
+ goto cleanup;
+
+ pci = virPCIDeviceNew(domain, bus, slot, function);
+ if (!pci)
+ goto cleanup;
+
+ hostdev_mgr = virHostdevManagerGetDefault();
+ if (virHostdevPciNodeDeviceReset(hostdev_mgr, pci) < 0)
+ goto out;
+
+ ret = 0;
+out:
+ virPCIDeviceFree(pci);
+cleanup:
+ virNodeDeviceDefFree(def);
+ VIR_FREE(xml);
+ return ret;
+}
+
static virDriver libxlDriver = {
.no = VIR_DRV_LIBXL,
- .name = "xenlight",
+ .name = LIBXL_DRIVER_NAME,
.connectOpen = libxlConnectOpen, /* 0.9.0 */
.connectClose = libxlConnectClose, /* 0.9.0 */
.connectGetType = libxlConnectGetType, /* 0.9.0 */
@@ -4264,6 +4701,10 @@ static virDriver libxlDriver = {
.connectDomainEventDeregisterAny = libxlConnectDomainEventDeregisterAny, /* 0.9.0 */
.connectIsAlive = libxlConnectIsAlive, /* 0.9.8 */
.connectSupportsFeature = libxlConnectSupportsFeature, /* 1.1.1 */
+ .nodeDeviceDettach = libxlNodeDeviceDettach, /* 1.1.3 */
+ .nodeDeviceDetachFlags = libxlNodeDeviceDetachFlags, /* 1.1.3 */
+ .nodeDeviceReAttach = libxlNodeDeviceReAttach, /* 1.1.3 */
+ .nodeDeviceReset = libxlNodeDeviceReset, /* 1.1.3 */
};
static virStateDriver libxlStateDriver = {
--
1.6.0.2
1
0
12 Sep '13
Add hostdev passthrough common library so that it could be shared by all drivers
and maintain a global hostdev state.
Signed-off-by: Chunyan Liu <cyliu(a)suse.com>
---
docs/schemas/domaincommon.rng | 1 +
po/POTFILES.in | 1 +
src/Makefile.am | 1 +
src/conf/domain_conf.c | 3 +-
src/conf/domain_conf.h | 1 +
src/libvirt_private.syms | 15 +
src/libxl/libxl_domain.c | 9 +
src/qemu/qemu_domain.c | 9 +
src/util/virhostdev.c | 1335 +++++++++++++++++++++++++++++++++++++++++
src/util/virhostdev.h | 104 ++++
src/util/virpci.c | 28 +-
src/util/virpci.h | 9 +-
src/util/virscsi.c | 26 +-
src/util/virscsi.h | 8 +-
src/util/virusb.c | 27 +-
src/util/virusb.h | 8 +-
16 files changed, 1556 insertions(+), 29 deletions(-)
create mode 100644 src/util/virhostdev.c
create mode 100644 src/util/virhostdev.h
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index ecd3a42..c75e96c 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -3312,6 +3312,7 @@
<choice>
<value>kvm</value>
<value>vfio</value>
+ <value>xen</value>
</choice>
</attribute>
<empty/>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 2a0605b..ec205c9 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -196,6 +196,7 @@ src/util/viruri.c
src/util/virusb.c
src/util/virutil.c
src/util/virxml.c
+src/util/virhostdev.c
src/vbox/vbox_MSCOMGlue.c
src/vbox/vbox_XPCOMCGlue.c
src/vbox/vbox_driver.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 711da32..e563960 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -148,6 +148,7 @@ UTIL_SOURCES = \
util/virutil.c util/virutil.h \
util/viruuid.c util/viruuid.h \
util/virxml.c util/virxml.h \
+ util/virhostdev.c util/virhostdev.h \
$(NULL)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index aed2a9d..f75db9a 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -611,7 +611,8 @@ VIR_ENUM_IMPL(virDomainHostdevSubsysPciBackend,
VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST,
"default",
"kvm",
- "vfio")
+ "vfio",
+ "xen")
VIR_ENUM_IMPL(virDomainHostdevCaps, VIR_DOMAIN_HOSTDEV_CAPS_TYPE_LAST,
"storage",
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 539bc1c..be19b12 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -402,6 +402,7 @@ typedef enum {
VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT, /* currently kvm, could change */
VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM, /* force legacy kvm style */
VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO, /* force vfio */
+ VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN, /* force legacy xen style, use pciback */
VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST
} virDomainHostdevSubsysPciBackendType;
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 35f0f1b..5247fed 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1428,6 +1428,21 @@ virHookInitialize;
virHookPresent;
+#util/virhostdev.h
+virHostdevManagerGetDefault;
+virHostdevPciNodeDeviceDetach;
+virHostdevPciNodeDeviceReAttach;
+virHostdevPciNodeDeviceReset;
+virHostdevPrepareDomainHostdevs;
+virHostdevPreparePciHostdevs;
+virHostdevPrepareScsiHostdevs;
+virHostdevPrepareUsbHostdevs;
+virHostdevReAttachDomainHostdevs;
+virHostdevReAttachPciHostdevs;
+virHostdevReAttachScsiHostdevs;
+virHostdevReAttachUsbHostdevs;
+
+
# util/viridentity.h
virIdentityGetAttr;
virIdentityGetCurrent;
diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c
index 0abf80b..4d6d07b 100644
--- a/src/libxl/libxl_domain.c
+++ b/src/libxl/libxl_domain.c
@@ -393,6 +393,15 @@ libxlDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
STRNEQ(def->os.type, "hvm"))
dev->data.chr->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_XEN;
+ if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
+ virDomainHostdevDefPtr hostdev = dev->data.hostdev;
+
+ if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
+ hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI &&
+ hostdev->source.subsys.u.pci.backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT)
+ hostdev->source.subsys.u.pci.backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN;
+ }
+
return 0;
}
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index f2cca70..91365d3 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -904,6 +904,15 @@ qemuDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
dev->data.chr->source.data.nix.listen = true;
}
+ if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
+ virDomainHostdevDefPtr hostdev = dev->data.hostdev;
+
+ if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
+ hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI &&
+ hostdev->source.subsys.u.pci.backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT)
+ hostdev->source.subsys.u.pci.backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM;
+ }
+
ret = 0;
cleanup:
diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c
new file mode 100644
index 0000000..d131160
--- /dev/null
+++ b/src/util/virhostdev.c
@@ -0,0 +1,1335 @@
+/* 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 "virhostdev.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "viralloc.h"
+#include "virstring.h"
+#include "virfile.h"
+#include "virerror.h"
+#include "virlog.h"
+#include "virpci.h"
+#include "virusb.h"
+#include "virscsi.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"
+
+struct _virHostdevManager{
+ char *stateDir;
+
+ virPCIDeviceListPtr activePciHostdevs;
+ virPCIDeviceListPtr inactivePciHostdevs;
+ virUSBDeviceListPtr activeUsbHostdevs;
+ virSCSIDeviceListPtr activeScsiHostdevs;
+};
+
+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 virMacAddrPtr 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;
+}
+
+static int
+virHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev,
+ char *stateDir)
+{
+ char *linkdev = NULL;
+ virNetDevVPortProfilePtr virtPort;
+ int ret = -1;
+ int vf = -1;
+ int port_profile_associate = 0;
+ 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;
+
+ 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);
+
+ 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_XEN :
+ if (virPCIDeviceSetStubDriver(dev, "pciback") < 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;
+}
+
+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;
+ int last_processed_hostdev_vf = -1;
+ size_t i;
+ int ret = -1;
+
+ virObjectLock(mgr->activePciHostdevs);
+ virObjectLock(mgr->inactivePciHostdevs);
+
+ 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)?true:false;
+
+ 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; i < last_processed_hostdev_vf; i++) {
+ virDomainHostdevDefPtr hostdev = hostdevs[i];
+ if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET &&
+ hostdev->parent.data.net) {
+ virHostdevNetConfigRestore(hostdev, mgr->stateDir);
+ }
+ }
+
+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;
+
+ /* 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;
+
+ /* 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 (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)?true:false;
+ 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;
+}
+
+void
+virHostdevReAttachPciHostdevs(virHostdevManagerPtr mgr,
+ const char *drv_name,
+ const char *dom_name,
+ virDomainHostdevDefPtr *hostdevs,
+ int nhostdevs)
+{
+ virPCIDeviceListPtr pcidevs;
+ size_t i;
+
+ virObjectLock(mgr->activePciHostdevs);
+ virObjectLock(mgr->inactivePciHostdevs);
+
+ 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;
+ }
+ }
+
+ /* virObjectUnref() will take care of freeing the dev. */
+ 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++) {
+ 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) {
+ virHostdevNetConfigRestore(hostdev, mgr->stateDir);
+ }
+ }
+
+ 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:
+ 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;
+
+ 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;
+
+ 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)
+ 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;
+
+ 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;
+
+ 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;
+
+ 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..16916d7
--- /dev/null
+++ b/src/util/virhostdev.h
@@ -0,0 +1,104 @@
+/* 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"
+
+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 virHostdevNameList {
+ char **names;
+ size_t nnames;
+};
+typedef struct virHostdevNameList *virHostdevNameListPtr;
+
+virHostdevManagerPtr virHostdevManagerGetDefault(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);
+
+/* 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 92927aa..ee45bea 100644
--- a/src/util/virpci.c
+++ b/src/util/virpci.c
@@ -62,7 +62,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;
@@ -1641,16 +1644,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 0aa6fee..f3f9e08 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 32e438b..211ed0b 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;
};
@@ -265,17 +268,26 @@ virSCSIDeviceFree(virSCSIDevicePtr dev)
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 e901618..6697bd2 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 {
@@ -378,16 +381,26 @@ virUSBDeviceFree(virUSBDevicePtr dev)
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.6.0.2
1
0
On Tue, Sep 10, 2013 at 05:31:23PM +0000, SULLIVAN, Chris (WGK) wrote:
> Hi Itamar,
>
> BZ created: https://bugzilla.redhat.com/show_bug.cgi?id=1006490
>
> Thanks,
Thanks, but we cannot simply require libvirt > 1.1.0, as it does not
ship with F19. We need get a fix backported to F19, so that we can
change our VNC password there.
(Too bad we've been top-posting here. Now that I'm adding libvir-list I'm
going to be cursed.)
>
> Chris
>
> -----Original Message-----
> From: Itamar Heim [mailto:iheim@redhat.com]
> Sent: Monday, September 09, 2013 8:36 PM
> To: SULLIVAN, Chris (WGK)
> Cc: users(a)ovirt.org; Michal Skrivanek
> Subject: Re: [Users] VNC/Spice console connection failure
>
> On 09/09/2013 12:59 PM, SULLIVAN, Chris (WGK) wrote:
> > Hi,
> >
> > Just to follow up on the below - updating to libvirt 1.1.2-1 from ftp://libvirt.org/libvirt/ has appeared to solve the issue. Console connections via noVNC work as expected.
>
> worth opening a bug to require that libvirt version as the minimal version?
>
> >
> > Cheers,
> >
> > Chris
> >
> >
> >
> > PLEASE CONSIDER THE ENVIRONMENT, DON'T PRINT THIS EMAIL UNLESS YOU REALLY NEED TO.
> >
> > This email and its attachments may contain information which is confidential and/or legally privileged. If you are not the intended recipient of this e-mail please notify the sender immediately by e-mail and delete this e-mail and its attachments from your computer and IT systems. You must not copy, re-transmit, use or disclose (other than to the sender) the existence or contents of this email or its attachments or permit anyone else to do so.
> >
> > -----------------------------
> >
> > -----Original Message-----
> > From: SULLIVAN, Chris (WGK)
> > Sent: Monday, September 09, 2013 3:48 PM
> > To: users(a)ovirt.org
> > Subject: RE: VNC/Spice console connection failure
> >
> > Hi,
> >
> > I am currently unable to connect to the console of a running VM through the Ovirt web interface. I get the following error (log extracts below):
> > error : qemuDomainChangeGraphics:1873 : internal error cannot change listen address setting on vnc graphics
> >
> > I’m using Fedora 19, ovirt-engine 3.3.0-1, VDSM 4.12.1, qemu 1.4.2 and libvirt 1.0.5. I get a similar error when trying to use Spice.
> >
> > Has anyone come across this problem before, and if so, how to resolve? Based on some quick googling the versions of libvirt/qemu available in F19 do not allow changes to the listen address for a running VM. Should I rollback to a previous version?
> >
> > Kind regards,
> >
> > Chris Sullivan
> > Senior Pipeline Engineer/Technical Development | J P Kenny
> >
> >
> > ovirt-engine.log
> > 2013-09-09 12:22:46,688 INFO [org.ovirt.engine.core.bll.SetVmTicketCommand] (ajp--127.0.0.1-8702-4) Running command: SetVmTicketCommand internal: false. Entities affected : ID: e69df488-ad50-4c8c-9f37-a63463a81702 Type: VM
> > 2013-09-09 12:22:46,692 INFO [org.ovirt.engine.core.vdsbroker.vdsbroker.SetVmTicketVDSCommand] (ajp--127.0.0.1-8702-4) START, SetVmTicketVDSCommand(HostName = r410-02, HostId = d5df2e2b-509c-4b1c-902a-976b932d930b, vmId=e69df488-ad50-4c8c-9f37-a63463a81702, ticket=igRUBsYsw5ds, validTime=120,m userName=admin@internal, userId=fdfc627c-d875-11e0-90f0-83df133b58cc), log id: 53359174
> > 2013-09-09 12:22:46,715 ERROR [org.ovirt.engine.core.vdsbroker.vdsbroker.SetVmTicketVDSCommand] (ajp--127.0.0.1-8702-4) Failed in SetVmTicketVDS method
> > 2013-09-09 12:22:46,715 ERROR [org.ovirt.engine.core.vdsbroker.vdsbroker.SetVmTicketVDSCommand] (ajp--127.0.0.1-8702-4) Error code unexpected and error message VDSGenericException: VDSErrorException: Failed to SetVmTicketVDS, error = Unexpected exception
> > 2013-09-09 12:22:46,716 INFO [org.ovirt.engine.core.vdsbroker.vdsbroker.SetVmTicketVDSCommand] (ajp--127.0.0.1-8702-4) Command org.ovirt.engine.core.vdsbroker.vdsbroker.SetVmTicketVDSCommand return value
> > 2013-09-09 12:22:46,716 INFO [org.ovirt.engine.core.vdsbroker.vdsbroker.SetVmTicketVDSCommand] (ajp--127.0.0.1-8702-4) HostName = r410-02
> > 2013-09-09 12:22:46,717 ERROR [org.ovirt.engine.core.vdsbroker.vdsbroker.SetVmTicketVDSCommand] (ajp--127.0.0.1-8702-4) Command SetVmTicketVDS execution failed. Exception: VDSErrorException: VDSGenericException: VDSErrorException: Failed to SetVmTicketVDS, error = Unexpected exception
> > 2013-09-09 12:22:46,717 INFO [org.ovirt.engine.core.vdsbroker.vdsbroker.SetVmTicketVDSCommand] (ajp--127.0.0.1-8702-4) FINISH, SetVmTicketVDSCommand, log id: 53359174
> > 2013-09-09 12:22:46,718 ERROR [org.ovirt.engine.core.bll.SetVmTicketCommand] (ajp--127.0.0.1-8702-4) Command org.ovirt.engine.core.bll.SetVmTicketCommand throw Vdc Bll exception. With error message VdcBLLException: org.ovirt.engine.core.vdsbroker.vdsbroker.VDSErrorException: VDSGenericException: VDSErrorException: Failed to SetVmTicketVDS, error = Unexpected exception (Failed with VDSM error unexpected and code 16)
> > 2013-09-09 12:22:46,721 ERROR [org.ovirt.engine.core.bll.SetVmTicketCommand] (ajp--127.0.0.1-8702-4) Transaction rolled-back for command: org.ovirt.engine.core.bll.SetVmTicketCommand.
> >
> > Virt host libvirtd.log
> > 2013-09-09 04:22:46.693+0000: 7413: debug : virDomainFree:2326 : dom=0x7fb920009eb0, (VM: name=rhev-compute-01, uuid=e69df488-ad50-4c8c-9f37-a63463a81702)
> > 2013-09-09 04:22:46.707+0000: 7415: debug : virDomainUpdateDeviceFlags:10057 : dom=0x7fb914055890, (VM: name=rhev-compute-01, uuid=e69df488-ad50-4c8c-9f37-a63463a81702), xml=<graphics autoport="yes" keymap="en-us" passwd="igRUBsYsw5ds" passwdValidTo="2013-09-09T04:24:46" port="5900" type="vnc">
> > <listen address="172.30.18.244" network="vdsm-ovirtmgmt" type="network"/>
> > </graphics>, flags=0
> > 2013-09-09 04:22:46.707+0000: 7415: debug : qemuDomainObjBeginJobInternal:958 : Starting job: modify (async=none)
> > 2013-09-09 04:22:46.707+0000: 7415: error : qemuDomainChangeGraphics:1873 : internal error cannot change listen address setting on vnc graphics
> > 2013-09-09 04:22:46.707+0000: 7415: debug : qemuDomainObjEndJob:1070 : Stopping job: modify (async=none)
3
3
From: "Daniel P. Berrange" <berrange(a)redhat.com>
A v2 of this patch
https://www.redhat.com/archives/libvir-list/2013-September/msg00405.html
Daniel P. Berrange (2):
Move array of mounts out of lxcContainerMountBasicFS
Ensure root filesystem is recursively mounted readonly
src/lxc/lxc_container.c | 169 +++++++++++++++++++++++++++++++++++++-----------
1 file changed, 130 insertions(+), 39 deletions(-)
--
1.8.3.1
3
5
[libvirt] [PATCH] api-docs: Fix description of virConnectGetType() API function
by Michal Novotny 12 Sep '13
by Michal Novotny 12 Sep '13
12 Sep '13
This fixes the description of virConnectGetType() API function in
API documentation to match the real functionality that it can be
used to get driver name.
Signed-off-by: Michal Novotny <minovotn(a)redhat.com>
---
src/libvirt.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/libvirt.c b/src/libvirt.c
index 665b30b..a1d33b6 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -1581,7 +1581,8 @@ virConnectSupportsFeature(virConnectPtr conn, int feature)
* virConnectGetType:
* @conn: pointer to the hypervisor connection
*
- * Get the name of the Hypervisor software used.
+ * Get the name of the Hypervisor driver used. This is merely the driver name so for KVM
+ * it is still returning QEMU as QEMU driver is being used for KVM virtualization as well.
*
* Returns NULL in case of error, a static zero terminated string otherwise.
*
--
1.7.11.7
2
1
Just noticed this on latest rawhide (Fedora 21):
Looks like the bug might not be libvirt's fault (as the assertion
failure is not in our source file), but I'm out of time to investigate
further today.
$ VIR_TEST_DEBUG=1 ./virdrivermoduletest
TEST: virdrivermoduletest
1) Test driver "network" ... OK
2) Test driver "storage" ... OK
3) Test driver "nodedev" ... OK
4) Test driver "secret" ... OK
5) Test driver "nwfilter" ... OK
6) Test driver "interface"
... lt-virdrivermoduletest: route/tc.c:973: rtnl_tc_register: Assertion
`0' failed.
Aborted
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
3
6
These are the patches Debian is currently carrying on 0.9.12. Most are
straight cherry-picks. Since we're maintaining 0.9.12 for our current
stable release I'm happy to push these to v0.9.12-maint.
Ferenc Wágner (1):
Fix race condition when destroying guests
Guido Günther (1):
Include stdint.h for uint32_t
Jiri Denemark (3):
daemon: Fix crash in virTypedParameterArrayClear
Revert "rpc: Discard non-blocking calls only when necessary"
qemu: Add support for -no-user-config
Luca Tettamanti (1):
Make sure regree is called close to it's usage
Martin Kletzander (1):
security: Fix libvirtd crash possibility
Peter Krempa (4):
qemu: Fix off-by-one error while unescaping monitor strings
rpc: Fix crash on error paths of message dispatching
conf: Remove callback from stream when freeing entries in console hash
conf: Remove console stream callback only when freeing console helper
cfg.mk | 3 +-
daemon/remote.c | 16 +-
src/conf/virconsole.c | 13 ++
src/qemu/qemu_capabilities.c | 7 +-
src/qemu/qemu_capabilities.h | 1 +
src/qemu/qemu_command.c | 11 +-
src/qemu/qemu_driver.c | 21 ++-
src/qemu/qemu_monitor.c | 11 +-
src/rpc/virnetclient.c | 21 +--
src/rpc/virnetserverclient.c | 3 +
src/rpc/virnetserverprogram.c | 11 +-
src/storage/storage_backend_logical.c | 5 +-
src/util/virnetlink.h | 2 +
tests/qemuhelpdata/qemu-1.1 | 268 ++++++++++++++++++++++++++++++++++
tests/qemuhelpdata/qemu-1.1-device | 160 ++++++++++++++++++++
tests/qemuhelptest.c | 75 ++++++++++
16 files changed, 586 insertions(+), 42 deletions(-)
create mode 100644 tests/qemuhelpdata/qemu-1.1
create mode 100644 tests/qemuhelpdata/qemu-1.1-device
--
1.8.4.rc3
2
1
[libvirt] [v0.9.12-maint 11/11] Fix race condition when destroying guests
by Ferenc Wágner 11 Sep '13
by Ferenc Wágner 11 Sep '13
11 Sep '13
Backport of 81621f3e6e45e8681cc18ae49404736a0e772a11 and
f1b4021b38f9485c50d386af6f682ecfc8025af5 to fix a race (resulting in a
segfault) when destroying domains.
---
src/qemu/qemu_driver.c | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 0053ed1..c0b4707 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -1827,6 +1827,12 @@ qemuDomainDestroyFlags(virDomainPtr dom,
qemuDomainSetFakeReboot(driver, vm, false);
+
+ /* We need to prevent monitor EOF callback from doing our work (and sending
+ * misleading events) while the vm is unlocked inside BeginJob/ProcessKill API
+ */
+ priv->beingDestroyed = true;
+
/* Although qemuProcessStop does this already, there may
* be an outstanding job active. We want to make sure we
* can kill the process even if a job is active. Killing
@@ -1834,19 +1840,20 @@ qemuDomainDestroyFlags(virDomainPtr dom,
*/
if (flags & VIR_DOMAIN_DESTROY_GRACEFUL) {
if (qemuProcessKill(driver, vm, 0) < 0) {
+ priv->beingDestroyed = false;
qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
_("failed to kill qemu process with SIGTERM"));
goto cleanup;
}
} else {
- ignore_value(qemuProcessKill(driver, vm, VIR_QEMU_PROCESS_KILL_FORCE));
+ if (qemuProcessKill(driver, vm, VIR_QEMU_PROCESS_KILL_FORCE) < 0) {
+ priv->beingDestroyed = false;
+ qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
+ _("failed to kill qemu process with SIGTERM"));
+ goto cleanup;
+ }
}
- /* We need to prevent monitor EOF callback from doing our work (and sending
- * misleading events) while the vm is unlocked inside BeginJob API
- */
- priv->beingDestroyed = true;
-
if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_DESTROY) < 0)
goto cleanup;
--
1.8.4.rc3
2
1
[libvirt] [v0.9.12-maint 10/11] conf: Remove console stream callback only when freeing console helper
by Peter Krempa 11 Sep '13
by Peter Krempa 11 Sep '13
11 Sep '13
Commit ba226d334acbc49f6751b430e0c4e00f69eef6bf tried to fix crash of
the daemon when a domain with an open console was destroyed. The fix was
wrong as it tried to remove the callback also when the stream was
aborted, where at that point the fd stream driver was already freed and
removed.
This patch clears the callbacks with a helper right before the hash is
freed, so that it doesn't interfere with other codepaths where the
stream object is freed.
---
src/conf/virconsole.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/src/conf/virconsole.c b/src/conf/virconsole.c
index e665149..01f1c84 100644
--- a/src/conf/virconsole.c
+++ b/src/conf/virconsole.c
@@ -222,9 +222,6 @@ static void virConsoleHashEntryFree(void *data,
const char *pty = name;
virStreamPtr st = data;
- /* remove callback from stream */
- virFDStreamSetInternalCloseCb(st, NULL, NULL, NULL);
-
/* free stream reference */
virStreamFree(st);
@@ -293,6 +290,18 @@ error:
}
/**
+ * Helper to clear stream callbacks when freeing the hash
+ */
+static void virConsoleFreeClearCallbacks(void *payload,
+ const void *name ATTRIBUTE_UNUSED,
+ void *data ATTRIBUTE_UNUSED)
+{
+ virStreamPtr st = payload;
+
+ virFDStreamSetInternalCloseCb(st, NULL, NULL, NULL);
+}
+
+/**
* Free structures for handling open console streams.
*
* @cons Pointer to the private structure.
@@ -303,6 +312,7 @@ void virConsoleFree(virConsolesPtr cons)
return;
virMutexLock(&cons->lock);
+ virHashForEach(cons->hash, virConsoleFreeClearCallbacks, NULL);
virHashFree(cons->hash);
virMutexUnlock(&cons->lock);
virMutexDestroy(&cons->lock);
--
1.8.4.rc3
2
1
[libvirt] [v0.9.12-maint 09/11] conf: Remove callback from stream when freeing entries in console hash
by Peter Krempa 11 Sep '13
by Peter Krempa 11 Sep '13
11 Sep '13
When a domain has a active console connection and is destroyed the
callback is called on private data that no longer exist causing a
segfault.
---
src/conf/virconsole.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/conf/virconsole.c b/src/conf/virconsole.c
index 443d80d..e665149 100644
--- a/src/conf/virconsole.c
+++ b/src/conf/virconsole.c
@@ -222,6 +222,9 @@ static void virConsoleHashEntryFree(void *data,
const char *pty = name;
virStreamPtr st = data;
+ /* remove callback from stream */
+ virFDStreamSetInternalCloseCb(st, NULL, NULL, NULL);
+
/* free stream reference */
virStreamFree(st);
--
1.8.4.rc3
2
1
11 Sep '13
to fix the build on kFreeBSD.
References: https://buildd.debian.org/status/fetch.php?pkg=libvirt&arch=kfreebsd-amd64&…
---
src/util/virnetlink.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/util/virnetlink.h b/src/util/virnetlink.h
index bafe8ca..acd88b7 100644
--- a/src/util/virnetlink.h
+++ b/src/util/virnetlink.h
@@ -21,8 +21,10 @@
# define __VIR_NETLINK_H__
# include "config.h"
+# include <stdint.h>
# include "internal.h"
+
# if defined(__linux__) && defined(HAVE_LIBNL)
# include <netlink/msg.h>
--
1.8.4.rc3
2
1
[libvirt] [PATCH] Fix polkit permission names for storage pools, vols & node devices
by Daniel P. Berrange 11 Sep '13
by Daniel P. Berrange 11 Sep '13
11 Sep '13
From: "Daniel P. Berrange" <berrange(a)redhat.com>
The polkit access driver used the wrong permission names for checks
on storage pools, volumes and node devices. This led to them always
being denied access.
Signed-off-by: Daniel P. Berrange <berrange(a)redhat.com>
---
src/access/viraccessdriverpolkit.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/access/viraccessdriverpolkit.c b/src/access/viraccessdriverpolkit.c
index 4c76e64..b472bc3 100644
--- a/src/access/viraccessdriverpolkit.c
+++ b/src/access/viraccessdriverpolkit.c
@@ -248,7 +248,7 @@ virAccessDriverPolkitCheckNodeDevice(virAccessManagerPtr manager,
};
return virAccessDriverPolkitCheck(manager,
- "nodedevice",
+ "node-device",
virAccessPermNodeDeviceTypeToString(perm),
attrs);
}
@@ -355,7 +355,7 @@ virAccessDriverPolkitCheckStoragePool(virAccessManagerPtr manager,
virUUIDFormat(pool->uuid, uuidstr);
return virAccessDriverPolkitCheck(manager,
- "pool",
+ "storage-pool",
virAccessPermStoragePoolTypeToString(perm),
attrs);
}
@@ -379,7 +379,7 @@ virAccessDriverPolkitCheckStorageVol(virAccessManagerPtr manager,
virUUIDFormat(pool->uuid, uuidstr);
return virAccessDriverPolkitCheck(manager,
- "vol",
+ "storage-vol",
virAccessPermStorageVolTypeToString(perm),
attrs);
}
--
1.8.3.1
2
3
[libvirt] [PATCH] Fix launching of VMs on when only logind part of systemd is present
by Daniel P. Berrange 11 Sep '13
by Daniel P. Berrange 11 Sep '13
11 Sep '13
From: "Daniel P. Berrange" <berrange(a)redhat.com>
Debian systems may run the 'systemd-logind' daemon, which causes the
/sys/fs/cgroup/systemd mount to be setup, but no other cgroup
controllers are created. While the LXC driver considers cgroups to
be mandatory, the QEMU driver is supposed to accept them as optional.
We detect whether they are present by looking in /proc/mounts for
any mounts of type 'cgroups', but this is not sufficient. We need to
skip any named mounts (as seen by a name=XXX string in the mount
options), so that we only detect actual resource controllers.
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=721979
Signed-off-by: Daniel P. Berrange <berrange(a)redhat.com>
---
src/util/vircgroup.c | 5 +++-
tests/vircgroupmock.c | 40 ++++++++++++++++++++++++---
tests/vircgrouptest.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 116 insertions(+), 4 deletions(-)
diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c
index a260356..626bbc6 100644
--- a/src/util/vircgroup.c
+++ b/src/util/vircgroup.c
@@ -91,7 +91,10 @@ virCgroupAvailable(void)
return false;
while (getmntent_r(mounts, &entry, buf, sizeof(buf)) != NULL) {
- if (STREQ(entry.mnt_type, "cgroup")) {
+ /* We're looking for at least one 'cgroup' fs mount,
+ * which is *not* a named mount. */
+ if (STREQ(entry.mnt_type, "cgroup") &&
+ !strstr(entry.mnt_opts, "name=")) {
ret = true;
break;
}
diff --git a/tests/vircgroupmock.c b/tests/vircgroupmock.c
index d83496c..adc1718 100644
--- a/tests/vircgroupmock.c
+++ b/tests/vircgroupmock.c
@@ -124,6 +124,27 @@ const char *proccgroupsallinone =
"devices 6 1 1\n"
"blkio 6 1 1\n";
+const char *procmountslogind =
+ "none /not/really/sys/fs/cgroup tmpfs rw,rootcontext=system_u:object_r:sysfs_t:s0,seclabel,relatime,size=4k,mode=755 0 0\n"
+ "systemd /not/really/sys/fs/cgroup/systemd cgroup rw,nosuid,nodev,noexec,relatime,name=systemd 0 0\n";
+
+const char *procselfcgroupslogind =
+ "1:name=systemd:/\n";
+
+const char *proccgroupslogind =
+ "#subsys_name hierarchy num_cgroups enabled\n"
+ "cpuset 0 1 1\n"
+ "cpu 0 1 1\n"
+ "cpuacct 0 1 1\n"
+ "memory 0 1 0\n"
+ "devices 0 1 1\n"
+ "freezer 0 1 1\n"
+ "net_cls 0 1 1\n"
+ "blkio 0 1 1\n"
+ "perf_event 0 1 1\n";
+
+
+
static int make_file(const char *path,
const char *name,
const char *value)
@@ -400,18 +421,25 @@ static void init_sysfs(void)
FILE *fopen(const char *path, const char *mode)
{
const char *mock;
- bool allinone = false;
+ bool allinone = false, logind = false;
init_syms();
mock = getenv("VIR_CGROUP_MOCK_MODE");
- if (mock && STREQ(mock, "allinone"))
- allinone = true;
+ if (mock) {
+ if (STREQ(mock, "allinone"))
+ allinone = true;
+ else if (STREQ(mock, "logind"))
+ logind = true;
+ }
if (STREQ(path, "/proc/mounts")) {
if (STREQ(mode, "r")) {
if (allinone)
return fmemopen((void *)procmountsallinone,
strlen(procmountsallinone), mode);
+ else if (logind)
+ return fmemopen((void *)procmountslogind,
+ strlen(procmountslogind), mode);
else
return fmemopen((void *)procmounts, strlen(procmounts), mode);
} else {
@@ -424,6 +452,9 @@ FILE *fopen(const char *path, const char *mode)
if (allinone)
return fmemopen((void *)proccgroupsallinone,
strlen(proccgroupsallinone), mode);
+ else if (logind)
+ return fmemopen((void *)proccgroupslogind,
+ strlen(proccgroupslogind), mode);
else
return fmemopen((void *)proccgroups, strlen(proccgroups), mode);
} else {
@@ -436,6 +467,9 @@ FILE *fopen(const char *path, const char *mode)
if (allinone)
return fmemopen((void *)procselfcgroupsallinone,
strlen(procselfcgroupsallinone), mode);
+ else if (logind)
+ return fmemopen((void *)procselfcgroupslogind,
+ strlen(procselfcgroupslogind), mode);
else
return fmemopen((void *)procselfcgroups, strlen(procselfcgroups), mode);
} else {
diff --git a/tests/vircgrouptest.c b/tests/vircgrouptest.c
index f12587c..570e061 100644
--- a/tests/vircgrouptest.c
+++ b/tests/vircgrouptest.c
@@ -109,6 +109,16 @@ const char *mountsAllInOne[VIR_CGROUP_CONTROLLER_LAST] = {
[VIR_CGROUP_CONTROLLER_BLKIO] = "/not/really/sys/fs/cgroup",
[VIR_CGROUP_CONTROLLER_SYSTEMD] = NULL,
};
+const char *mountsLogind[VIR_CGROUP_CONTROLLER_LAST] = {
+ [VIR_CGROUP_CONTROLLER_CPU] = NULL,
+ [VIR_CGROUP_CONTROLLER_CPUACCT] = NULL,
+ [VIR_CGROUP_CONTROLLER_CPUSET] = NULL,
+ [VIR_CGROUP_CONTROLLER_MEMORY] = NULL,
+ [VIR_CGROUP_CONTROLLER_DEVICES] = NULL,
+ [VIR_CGROUP_CONTROLLER_FREEZER] = NULL,
+ [VIR_CGROUP_CONTROLLER_BLKIO] = NULL,
+ [VIR_CGROUP_CONTROLLER_SYSTEMD] = "/not/really/sys/fs/cgroup/systemd",
+};
const char *links[VIR_CGROUP_CONTROLLER_LAST] = {
[VIR_CGROUP_CONTROLLER_CPU] = "/not/really/sys/fs/cgroup/cpu",
@@ -132,6 +142,17 @@ const char *linksAllInOne[VIR_CGROUP_CONTROLLER_LAST] = {
[VIR_CGROUP_CONTROLLER_SYSTEMD] = NULL,
};
+const char *linksLogind[VIR_CGROUP_CONTROLLER_LAST] = {
+ [VIR_CGROUP_CONTROLLER_CPU] = NULL,
+ [VIR_CGROUP_CONTROLLER_CPUACCT] = NULL,
+ [VIR_CGROUP_CONTROLLER_CPUSET] = NULL,
+ [VIR_CGROUP_CONTROLLER_MEMORY] = NULL,
+ [VIR_CGROUP_CONTROLLER_DEVICES] = NULL,
+ [VIR_CGROUP_CONTROLLER_FREEZER] = NULL,
+ [VIR_CGROUP_CONTROLLER_BLKIO] = NULL,
+ [VIR_CGROUP_CONTROLLER_SYSTEMD] = NULL,
+};
+
static int testCgroupNewForSelf(const void *args ATTRIBUTE_UNUSED)
{
@@ -466,6 +487,48 @@ cleanup:
}
+static int testCgroupNewForSelfLogind(const void *args ATTRIBUTE_UNUSED)
+{
+ virCgroupPtr cgroup = NULL;
+ int ret = -1;
+ const char *placement[VIR_CGROUP_CONTROLLER_LAST] = {
+ [VIR_CGROUP_CONTROLLER_CPU] = NULL,
+ [VIR_CGROUP_CONTROLLER_CPUACCT] = NULL,
+ [VIR_CGROUP_CONTROLLER_CPUSET] = NULL,
+ [VIR_CGROUP_CONTROLLER_MEMORY] = NULL,
+ [VIR_CGROUP_CONTROLLER_DEVICES] = NULL,
+ [VIR_CGROUP_CONTROLLER_FREEZER] = NULL,
+ [VIR_CGROUP_CONTROLLER_BLKIO] = NULL,
+ [VIR_CGROUP_CONTROLLER_SYSTEMD] = "/",
+ };
+
+ if (virCgroupNewSelf(&cgroup) < 0) {
+ fprintf(stderr, "Cannot create cgroup for self\n");
+ goto cleanup;
+ }
+
+ ret = validateCgroup(cgroup, "", mountsLogind, linksLogind, placement);
+
+cleanup:
+ virCgroupFree(&cgroup);
+ return ret;
+}
+
+
+static int testCgroupAvailable(const void *args)
+{
+ bool got = virCgroupAvailable();
+ bool want = args == (void*)0x1;
+
+ if (got != want) {
+ fprintf(stderr, "Expected cgroup %savailable, but state was wrong\n",
+ want ? "" : "not ");
+ return -1;
+ }
+
+ return 0;
+}
+
# define FAKESYSFSDIRTEMPLATE abs_builddir "/fakesysfsdir-XXXXXX"
@@ -505,9 +568,21 @@ mymain(void)
if (virtTestRun("New cgroup for domain partition escaped", 1, testCgroupNewForPartitionDomainEscaped, NULL) < 0)
ret = -1;
+ if (virtTestRun("Cgroup available", 1, testCgroupAvailable, (void*)0x1) < 0)
+ ret = -1;
+
setenv("VIR_CGROUP_MOCK_MODE", "allinone", 1);
if (virtTestRun("New cgroup for self (allinone)", 1, testCgroupNewForSelfAllInOne, NULL) < 0)
ret = -1;
+ if (virtTestRun("Cgroup available", 1, testCgroupAvailable, (void*)0x1) < 0)
+ ret = -1;
+ unsetenv("VIR_CGROUP_MOCK_MODE");
+
+ setenv("VIR_CGROUP_MOCK_MODE", "logind", 1);
+ if (virtTestRun("New cgroup for self (logind)", 1, testCgroupNewForSelfLogind, NULL) < 0)
+ ret = -1;
+ if (virtTestRun("Cgroup available", 1, testCgroupAvailable, (void*)0x0) < 0)
+ ret = -1;
unsetenv("VIR_CGROUP_MOCK_MODE");
if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL)
--
1.8.3.1
3
2