[libvirt] RFC: managing "pci passthrough" usage of sriov VFs via a new network forward type
by Laine Stump
For some reason beyond my comprehension, the designers of SRIOV ethernet
cards decided that the virtual functions (VF) of the card (each VF
corresponds to an ethernet device, e.g. "eth10") should each be given a
new+different+random MAC address each time the hardware is rebooted.
Normally, udev keeps a persistent table that associates each known MAC
address with an ethernet device name - any time an ethernet device with
a previously-unknown MAC address is found, a new device name is
allocated ("eth11", etc) and the newly found MAC address is associated
with that device name. When an ethernet device is an SRIOV VF, though,
udev doesn't persist the MAC address, so at each boot a device is found
with a new MAC addres, but the device name from the previous boot is
"unused" so magically the device ends up with the same name even though
the MAC address has changed.
When this device is assigned to a guest via PCI passthrough, though, the
guest doesn't have the necessary information to realize that it's
actually an SRIOV VF, so the guest's udev persists the MAC address - on
the first boot of host+guest, the guest will see it has, e.g., mac
address 11:22:33:44:55:66 and udev will add an entry to its persistent
table remembering that 11:22:33:44:55:66="eth0". If the host reboots,
though, the VF will get a new MAC address, and when the guest boots, it
will see a new MAC address (e.g. "66:55:44:33:22:11") and think that
there's a different card, so it will create a new device (and a new udev
entry - 66:55:44:33:22:11="eth1"). This will repeat each time the host
reboots, with the obvious undesired consequences.
This makes using SRIOV VFs via PCI passthrough very unpalatable. The
problem can be solved by setting the MAC address of the ethernet device
prior to assigning it to the guest, but of course the <hostdev> element
used to assign PCI devices to guests has no place to specify a MAC
address (and I'm not sure it would be appropriate to add something that
function-specific to <hostdev>). Dave Allan and I have discussed a
different possible method of eliminating this problem (using a new
forward type for libvirt networks) that I've outlined below. Please let
me know what you think - is this reasonable in general? If so, what
about the details? If not, any counter-proposals to solve the problem?
Providing Predictable/Configurable MAC Addresses for SRIOV VFs used via
PCI Passthrough:
1) <network> will have a new forward type='hardware'. When forward
type='hardware', a pool of ethernet interfaces can be specified, just as
for the forward types "bridge", "vepa", "private", and "passthrough". At
this point, that's the only thing that I've determined is needed in the
network definition.
2) In a domain's <interface> definition, when type='network', if the
network has a forward type='hardware', the domain code will request an
unused ethernet device from the network driver, then do the following:
3) save the ethernet device name in interface/actual so that it can be
easily retrieved if libvirtd is restarted
4) Set the MAC address of the given ethernet device according to the
domain <interface> config.
5) Use the NodeDevice API to learn all the necessary PCI
domain/slot/bus/function and add a (non-persisting) <hostdev> element to
the guest's config before starting it up.
6) When the guest is eventually destroyed, the ethernet device will be
free'd back to the network pool for use by another guest.
One problem this doesn't solve is that when a guest is migrated, the PCI
info for the allocated ethernet device on the destination host will
almost surely be different. Is there any provision for dealing with this
in the device passthrough code? If not, then migration will still not be
possible.
Although I realize that many people are predisposed to not like the idea
of PCI passthrough of ethernet devices (including me), it seems that
it's going to be used, so we may as well provide the management tools to
do it in a sane manner.
13 years, 4 months
[libvirt] [PATCH] libvirt: log all flags parameters
by Eric Blake
I was testing a virsh patch, and wanted to see if I had passed the
flags I thought. But with LIBVIRT_DEBUG in the environment, I just
saw:
14:24:52.359: 15022: debug : virDomainSnapshotNum:15586 : dom=0xc9c180, (VM: name=rhel_6-64, uuid=48f8e8e7-e14f-0e14-02f0-ce71997bdcab),
including a trailing space. This fixes the issues.
* src/libvirt.c: Log flag parameters, even if currently unused.
(VIR_DOMAIN_DEBUG_0): Drop trailing comma in log.
(VIR_DOMAIN_DEBUG_1): Split guts into...
(VIR_DOMAIN_DEBUG_2): ...new macro.
---
src/libvirt.c | 58 +++++++++++++++++++++++++++++++-------------------------
1 files changed, 32 insertions(+), 26 deletions(-)
diff --git a/src/libvirt.c b/src/libvirt.c
index c8af3e1..a1197e0 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -333,10 +333,14 @@ static struct gcry_thread_cbs virTLSThreadImpl = {
/* Internal use only, when VIR_DOMAIN_DEBUG has one argument. */
#define VIR_DOMAIN_DEBUG_0(dom) \
- VIR_DOMAIN_DEBUG_1(dom, "%s", "")
+ VIR_DOMAIN_DEBUG_2(dom, "%s", "")
/* Internal use only, when VIR_DOMAIN_DEBUG has three or more arguments. */
-#define VIR_DOMAIN_DEBUG_1(dom, fmt, ...) \
+#define VIR_DOMAIN_DEBUG_1(dom, fmt, ...) \
+ VIR_DOMAIN_DEBUG_2(dom, ", " fmt, __VA_ARGS__)
+
+/* Internal use only, with final format. */
+#define VIR_DOMAIN_DEBUG_2(dom, fmt, ...) \
do { \
char _uuidstr[VIR_UUID_STRING_BUFLEN]; \
const char *_domname = NULL; \
@@ -348,7 +352,7 @@ static struct gcry_thread_cbs virTLSThreadImpl = {
_domname = (dom)->name; \
} \
\
- VIR_DEBUG("dom=%p, (VM: name=%s, uuid=%s), " fmt, \
+ VIR_DEBUG("dom=%p, (VM: name=%s, uuid=%s)" fmt, \
dom, NULLSTR(_domname), _uuidstr, __VA_ARGS__); \
} while (0)
@@ -1615,7 +1619,7 @@ error:
char *
virConnectGetSysinfo (virConnectPtr conn, unsigned int flags)
{
- VIR_DEBUG("conn=%p", conn);
+ VIR_DEBUG("conn=%p, flags=%x", conn, flags);
virResetLastError();
@@ -2098,7 +2102,7 @@ virDomainDestroyFlags(virDomainPtr domain,
{
virConnectPtr conn;
- VIR_DOMAIN_DEBUG(domain);
+ VIR_DOMAIN_DEBUG(domain, "flags=%x", flags);
virResetLastError();
@@ -2386,7 +2390,7 @@ virDomainSaveFlags(virDomainPtr domain, const char *to,
{
virConnectPtr conn;
- VIR_DOMAIN_DEBUG(domain, "to=%s dxml=%s flags=%x",
+ VIR_DOMAIN_DEBUG(domain, "to=%s, dxml=%s, flags=%x",
to, NULLSTR(dxml), flags);
virResetLastError();
@@ -2816,7 +2820,7 @@ virDomainScreenshot(virDomainPtr domain,
unsigned int screen,
unsigned int flags)
{
- VIR_DOMAIN_DEBUG(domain, "stream=%p flags=%x", stream, flags);
+ VIR_DOMAIN_DEBUG(domain, "stream=%p, flags=%x", stream, flags);
virResetLastError();
@@ -3292,7 +3296,7 @@ virDomainSetMemoryFlags(virDomainPtr domain, unsigned long memory,
{
virConnectPtr conn;
- VIR_DOMAIN_DEBUG(domain, "memory=%lu flags=%x", memory, flags);
+ VIR_DOMAIN_DEBUG(domain, "memory=%lu, flags=%x", memory, flags);
virResetLastError();
@@ -3635,7 +3639,8 @@ virDomainGetState(virDomainPtr domain,
{
virConnectPtr conn;
- VIR_DOMAIN_DEBUG(domain, "state=%p, reason=%p", state, reason);
+ VIR_DOMAIN_DEBUG(domain, "state=%p, reason=%p, flags=%x",
+ state, reason, flags);
virResetLastError();
@@ -3682,7 +3687,7 @@ virDomainGetControlInfo(virDomainPtr domain,
{
virConnectPtr conn;
- VIR_DOMAIN_DEBUG(domain, "info=%p", info);
+ VIR_DOMAIN_DEBUG(domain, "info=%p, flags=%x", info, flags);
virResetLastError();
@@ -3791,7 +3796,7 @@ char *virConnectDomainXMLFromNative(virConnectPtr conn,
const char *nativeConfig,
unsigned int flags)
{
- VIR_DEBUG("conn=%p, format=%s config=%s flags=%x",
+ VIR_DEBUG("conn=%p, format=%s, config=%s, flags=%x",
conn, nativeFormat, nativeConfig, flags);
virResetLastError();
@@ -3844,7 +3849,7 @@ char *virConnectDomainXMLToNative(virConnectPtr conn,
const char *domainXml,
unsigned int flags)
{
- VIR_DEBUG("conn=%p, format=%s xml=%s flags=%x",
+ VIR_DEBUG("conn=%p, format=%s, xml=%s, flags=%x",
conn, nativeFormat, domainXml, flags);
virResetLastError();
@@ -3913,7 +3918,7 @@ virDomainMigrateVersion1 (virDomainPtr domain,
int cookielen = 0, ret;
virDomainInfo info;
VIR_DOMAIN_DEBUG(domain,
- "dconn=%p flags=%lx, dname=%s, uri=%s, bandwidth=%lu",
+ "dconn=%p, flags=%lx, dname=%s, uri=%s, bandwidth=%lu",
dconn, flags, NULLSTR(dname), NULLSTR(uri), bandwidth);
ret = virDomainGetInfo (domain, &info);
@@ -4006,7 +4011,7 @@ virDomainMigrateVersion2 (virDomainPtr domain,
virErrorPtr orig_err = NULL;
int cancelled;
VIR_DOMAIN_DEBUG(domain,
- "dconn=%p flags=%lx, dname=%s, uri=%s, bandwidth=%lu",
+ "dconn=%p, flags=%lx, dname=%s, uri=%s, bandwidth=%lu",
dconn, flags, NULLSTR(dname), NULLSTR(uri), bandwidth);
/* Prepare the migration.
@@ -6458,7 +6463,8 @@ int virDomainMemoryStats (virDomainPtr dom, virDomainMemoryStatPtr stats,
virConnectPtr conn;
unsigned long nr_stats_ret = 0;
- VIR_DOMAIN_DEBUG(dom, "stats=%p, nr_stats=%u", stats, nr_stats);
+ VIR_DOMAIN_DEBUG(dom, "stats=%p, nr_stats=%u, flags=%x",
+ stats, nr_stats, flags);
virResetLastError();
@@ -6539,8 +6545,8 @@ virDomainBlockPeek (virDomainPtr dom,
{
virConnectPtr conn;
- VIR_DOMAIN_DEBUG(dom, "path=%s, offset=%lld, size=%zi, buffer=%p",
- path, offset, size, buffer);
+ VIR_DOMAIN_DEBUG(dom, "path=%s, offset=%lld, size=%zi, buffer=%p, flags=%x",
+ path, offset, size, buffer, flags);
virResetLastError();
@@ -6712,7 +6718,7 @@ virDomainGetBlockInfo(virDomainPtr domain, const char *path, virDomainBlockInfoP
{
virConnectPtr conn;
- VIR_DOMAIN_DEBUG(domain, "info=%p flags=%x", info, flags);
+ VIR_DOMAIN_DEBUG(domain, "info=%p, flags=%x", info, flags);
virResetLastError();
@@ -10343,7 +10349,7 @@ virStoragePoolCreateXML(virConnectPtr conn,
const char *xmlDesc,
unsigned int flags)
{
- VIR_DEBUG("conn=%p, xmlDesc=%s", conn, xmlDesc);
+ VIR_DEBUG("conn=%p, xmlDesc=%s, flags=%x", conn, xmlDesc, flags);
virResetLastError();
@@ -10392,7 +10398,7 @@ virStoragePoolDefineXML(virConnectPtr conn,
const char *xml,
unsigned int flags)
{
- VIR_DEBUG("conn=%p, xml=%s", conn, xml);
+ VIR_DEBUG("conn=%p, xml=%s, flags=%x", conn, xml, flags);
virResetLastError();
@@ -10527,7 +10533,7 @@ virStoragePoolCreate(virStoragePoolPtr pool,
unsigned int flags)
{
virConnectPtr conn;
- VIR_DEBUG("pool=%p", pool);
+ VIR_DEBUG("pool=%p, flags=%x", pool, flags);
virResetLastError();
@@ -10731,7 +10737,7 @@ virStoragePoolRefresh(virStoragePoolPtr pool,
unsigned int flags)
{
virConnectPtr conn;
- VIR_DEBUG("pool=%p flags=%x", pool, flags);
+ VIR_DEBUG("pool=%p, flags=%x", pool, flags);
virResetLastError();
@@ -11491,7 +11497,7 @@ virStorageVolDownload(virStorageVolPtr vol,
unsigned long long length,
unsigned int flags)
{
- VIR_DEBUG("vol=%p stream=%p offset=%llu length=%llu flags=%x",
+ VIR_DEBUG("vol=%p, stream=%p, offset=%llu, length=%llu, flags=%x",
vol, stream, offset, length, flags);
virResetLastError();
@@ -11562,7 +11568,7 @@ virStorageVolUpload(virStorageVolPtr vol,
unsigned long long length,
unsigned int flags)
{
- VIR_DEBUG("vol=%p stream=%p offset=%llu length=%llu flags=%x",
+ VIR_DEBUG("vol=%p, stream=%p, offset=%llu, length=%llu, flags=%x",
vol, stream, offset, length, flags);
virResetLastError();
@@ -12043,7 +12049,7 @@ error:
*/
char *virNodeDeviceGetXMLDesc(virNodeDevicePtr dev, unsigned int flags)
{
- VIR_DEBUG("dev=%p, conn=%p", dev, dev ? dev->conn : NULL);
+ VIR_DEBUG("dev=%p, conn=%p, flags=%x", dev, dev ? dev->conn : NULL, flags);
virResetLastError();
@@ -15537,7 +15543,7 @@ virDomainSnapshotNum(virDomainPtr domain, unsigned int flags)
{
virConnectPtr conn;
- VIR_DOMAIN_DEBUG(domain);
+ VIR_DOMAIN_DEBUG(domain, "flags=%x", flags);
virResetLastError();
--
1.7.4.4
13 years, 4 months
Re: [libvirt] [virt-tools-list] [PATCH] virt-manager: Show if the shut off vm has a saved image
by Eric Blake
[adding libvirt, for a virsh idea]
On 08/01/2011 02:19 PM, Cole Robinson wrote:
> On 07/30/2011 04:15 PM, Miklos Vajna wrote:
>> Hi,
>>
>> So far in virt-manager one had to click on a shut off vm in the
>> "Shutoff" state to see if it has a saved image: once the item is
>> selected then the "play" icon will be "Run" or "Restore". This means
>> that in case one has a lot of VMs, it's hard to get an overview of what
>> VM has a saved image and what not.
>>
>> The attached patch changes the "Shutoff" status message to "Saved" in
>> case the vm has a saved image.
>>
>
> Good idea, I've pushed your patch:
Awesome idea; in fact, I think 'virsh list --all' should probably also
be enhanced to do something similar (show "saved" instead of "shutoff",
and perhaps requiring a new --managed-save flag so as not to break
back-compat). Note that virsh 0.9.4 is gaining 'virsh dominfo' as a way
of querying whether a managed save image exists (previously virsh had no
way to expose that information), but 'virsh dominfo' on a single domain
at a time is much slower than doing it in bulk in 'virsh list'.
Alas, we've missed the deadline for getting a patch like that into
libvirt 0.9.4.
--
Eric Blake eblake(a)redhat.com +1-801-349-2682
Libvirt virtualization library http://libvirt.org
13 years, 4 months
[libvirt] [PATCH] qemu: Allow graceful domain destroy
by Michal Privoznik
This patch introduces support for domain destroying via 'quit' monitor
command which gives qemu time to flush caches and therefore prevent
disks corruption. However, qemu can be unresponsive and to prevent
waiting indefinitely, execute command in a separate thread and wait
reasonable time (QEMU_QUIT_WAIT_SECONDS) on a condition. If we hit
timeout, qemu is qemuProcessKill'ed which causes monitor close and
therefore also thread being terminable.
The synchronization between qemu driver and monitor-quit thread is done
through mutex and condition. However, this alone is not enough. If a
condition is signalized but without anybody listening signal is lost. To
prevent this a boolean variable is used that is set iff nobody is
listening but condition would be signalized, or iff driver is waiting on
given condition.
---
include/libvirt/libvirt.h.in | 11 ++-
src/qemu/qemu_driver.c | 132 +++++++++++++++++++++++++++++++++++++++--
src/qemu/qemu_monitor.c | 13 ++++
src/qemu/qemu_monitor.h | 2 +
src/qemu/qemu_monitor_json.c | 22 +++++++
src/qemu/qemu_monitor_json.h | 1 +
src/qemu/qemu_monitor_text.c | 20 ++++++
src/qemu/qemu_monitor_text.h | 1 +
tools/virsh.c | 8 ++-
9 files changed, 198 insertions(+), 12 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index aa29fb6..fa98b8d 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -919,10 +919,13 @@ virConnectPtr virDomainGetConnect (virDomainPtr domain);
* Domain creation and destruction
*/
-/*
- * typedef enum {
- * } virDomainDestroyFlagsValues;
- */
+
+typedef enum {
+ VIR_DOMAIN_DESTROY_MONITOR = 1 << 0, /* In hypervisors supporting this,
+ try to send 'quit' command prior
+ to killing hypervisor */
+} virDomainDestroyFlagsValues;
+
virDomainPtr virDomainCreateXML (virConnectPtr conn,
const char *xmlDesc,
unsigned int flags);
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 421a98e..6585cb4 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -1564,6 +1564,42 @@ cleanup:
return ret;
}
+struct qemuDomainDestroyHelperData {
+ struct qemud_driver *driver;
+ virDomainObjPtr vm;
+ qemuDomainObjPrivatePtr priv;
+ virMutex lock;
+ virCond cond;
+ bool guard;
+};
+
+static void
+qemuDomainDestroyHelper(void *opaque)
+{
+ struct qemuDomainDestroyHelperData *data = opaque;
+ struct qemud_driver *driver = data->driver;
+ virDomainObjPtr vm = data->vm;
+ qemuDomainObjPrivatePtr priv = data->priv;
+
+ /* Job was already obtained by caller */
+ qemuDomainObjEnterMonitorWithDriver(driver, vm);
+ qemuMonitorQuit(priv->mon);
+ qemuDomainObjExitMonitorWithDriver(driver, vm);
+
+ /* To avoid loosing signal, we need to remember
+ * we tried to send one, but nobody was waiting
+ * for it.
+ */
+ virMutexLock(&data->lock);
+ if (data->guard) {
+ virCondSignal(&data->cond);
+ } else {
+ data->guard = true;
+ }
+ virMutexUnlock(&data->lock);
+}
+
+#define QEMU_QUIT_WAIT_SECONDS 5
static int
qemuDomainDestroyFlags(virDomainPtr dom,
@@ -1574,8 +1610,13 @@ qemuDomainDestroyFlags(virDomainPtr dom,
int ret = -1;
virDomainEventPtr event = NULL;
qemuDomainObjPrivatePtr priv;
+ bool use_thread = false;
+ bool use_kill = false;
+ virThread destroy_thread;
+ struct qemuDomainDestroyHelperData data;
+ unsigned long long then;
- virCheckFlags(0, -1);
+ virCheckFlags(VIR_DOMAIN_DESTROY_MONITOR, -1);
qemuDriverLock(driver);
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
@@ -1590,12 +1631,14 @@ qemuDomainDestroyFlags(virDomainPtr dom,
priv = vm->privateData;
priv->fakeReboot = false;
- /* 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
- * it now means the job will be released
- */
- qemuProcessKill(vm);
+ if (!flags) {
+ /* 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
+ * it now means the job will be released
+ */
+ qemuProcessKill(vm);
+ }
if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_DESTROY) < 0)
goto cleanup;
@@ -1606,6 +1649,70 @@ qemuDomainDestroyFlags(virDomainPtr dom,
goto endjob;
}
+ if (flags & VIR_DOMAIN_DESTROY_MONITOR) {
+ /* Try to shutdown domain gracefully.
+ * Send 'quit' to qemu. However, qemu can be unresponsive.
+ * Therefore create a separate thread in which we execute
+ * that monitor comand. Wait max QEMU_QUIT_WAIT_SECONDS.
+ */
+ if (virMutexInit(&data.lock) < 0) {
+ virReportOOMError();
+ goto endjob;
+ }
+
+ if (virCondInit(&data.cond) < 0) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("cannot initialize thread condition"));
+ virMutexDestroy(&data.lock);
+ goto endjob;
+ }
+
+ data.driver = driver;
+ data.vm = vm;
+ data.priv = priv;
+ data.guard = false;
+
+ if (virThreadCreate(&destroy_thread, true,
+ qemuDomainDestroyHelper, &data) < 0) {
+ virReportSystemError(errno, "%s",
+ _("unable to create destroy thread"));
+ ignore_value(virCondDestroy(&data.cond));
+ virMutexDestroy(&data.lock);
+ goto endjob;
+ }
+ use_thread = true;
+
+ if (virTimeMs(&then) < 0)
+ goto endjob;
+
+ then += QEMU_QUIT_WAIT_SECONDS * 1000;
+
+ /* How synchronization with destroy thread works:
+ * Basically wait on data.cond. But because conditions
+ * does not 'remember' that they have been signalized
+ * data.guard is used. Practically, data.guard says
+ * to destroy thread if we are waiting on condition
+ * and to us whether we should even try.
+ */
+ virMutexLock(&data.lock);
+ if (!data.guard) {
+ data.guard = true;
+ if (virCondWaitUntil(&data.cond, &data.lock, then) < 0) {
+ if (errno == ETIMEDOUT) {
+ use_kill = true;
+ data.guard = false;
+ } else {
+ virMutexUnlock(&data.lock);
+ goto endjob;
+ }
+ }
+ }
+ virMutexUnlock(&data.lock);
+
+ if (use_kill)
+ qemuProcessKill(vm);
+ }
+
qemuProcessStop(driver, vm, 0, VIR_DOMAIN_SHUTOFF_DESTROYED);
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_STOPPED,
@@ -1626,6 +1733,17 @@ endjob:
vm = NULL;
cleanup:
+ if (use_thread) {
+ virMutexLock(&data.lock);
+ if (!data.guard) {
+ data.guard = true;
+ ignore_value(virCondWait(&data.cond, &data.lock));
+ }
+ virMutexUnlock(&data.lock);
+ ignore_value(virCondDestroy(&data.cond));
+ virMutexDestroy(&data.lock);
+ virThreadJoin(&destroy_thread);
+ }
if (vm)
virDomainObjUnlock(vm);
if (event)
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index db6107c..41b9c5c 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -2475,3 +2475,16 @@ int qemuMonitorBlockJob(qemuMonitorPtr mon,
ret = qemuMonitorTextBlockJob(mon, device, bandwidth, info, mode);
return ret;
}
+
+int qemuMonitorQuit(qemuMonitorPtr mon)
+{
+ int ret;
+
+ VIR_DEBUG("mon=%p", mon);
+
+ if (mon->json)
+ ret = qemuMonitorJSONQuit(mon);
+ else
+ ret = qemuMonitorTextQuit(mon);
+ return ret;
+}
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index f241c9e..3fe6bb9 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -475,6 +475,8 @@ int qemuMonitorBlockJob(qemuMonitorPtr mon,
virDomainBlockJobInfoPtr info,
int mode);
+int qemuMonitorQuit(qemuMonitorPtr mon);
+
/**
* When running two dd process and using <> redirection, we need a
* shell that will not truncate files. These two strings serve that
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 7adfb26..1f078cd 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -2956,3 +2956,25 @@ int qemuMonitorJSONBlockJob(qemuMonitorPtr mon,
virJSONValueFree(reply);
return ret;
}
+
+
+int qemuMonitorJSONQuit(qemuMonitorPtr mon)
+{
+ int ret = -1;
+ virJSONValuePtr cmd = NULL;
+ virJSONValuePtr reply = NULL;
+
+ cmd = qemuMonitorJSONMakeCommand("quit", NULL);
+
+ if (!cmd)
+ return -1;
+
+ ret =qemuMonitorJSONCommand(mon, cmd, &reply);
+
+ if (ret == 0)
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 9512793..2a7df76 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -231,4 +231,5 @@ int qemuMonitorJSONBlockJob(qemuMonitorPtr mon,
virDomainBlockJobInfoPtr info,
int mode);
+int qemuMonitorJSONQuit(qemuMonitorPtr mon);
#endif /* QEMU_MONITOR_JSON_H */
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
index 335e39e..19c2690 100644
--- a/src/qemu/qemu_monitor_text.c
+++ b/src/qemu/qemu_monitor_text.c
@@ -3046,3 +3046,23 @@ cleanup:
VIR_FREE(reply);
return ret;
}
+
+
+int qemuMonitorTextQuit(qemuMonitorPtr mon)
+{
+ const char *cmd = "quit";
+ char *reply = NULL;
+ int ret = -1;
+
+ if (qemuMonitorHMPCommand(mon, cmd, &reply) < 0) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot run monitor command"));
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(reply);
+ return ret;
+}
diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h
index b250738..9ade938 100644
--- a/src/qemu/qemu_monitor_text.h
+++ b/src/qemu/qemu_monitor_text.h
@@ -224,4 +224,5 @@ int qemuMonitorTextBlockJob(qemuMonitorPtr mon,
virDomainBlockJobInfoPtr info,
int mode);
+int qemuMonitorTextQuit(qemuMonitorPtr mon);
#endif /* QEMU_MONITOR_TEXT_H */
diff --git a/tools/virsh.c b/tools/virsh.c
index f1eb4ca..0c18d8b 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -2565,6 +2565,7 @@ static const vshCmdInfo info_destroy[] = {
static const vshCmdOptDef opts_destroy[] = {
{"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
+ {"monitor", VSH_OT_BOOL, 0, N_("try graceful destroy via monitor first")},
{NULL, 0, 0, NULL}
};
@@ -2574,6 +2575,7 @@ cmdDestroy(vshControl *ctl, const vshCmd *cmd)
virDomainPtr dom;
bool ret = true;
const char *name;
+ int flags = 0;
if (!vshConnectionUsability(ctl, ctl->conn))
return false;
@@ -2581,7 +2583,11 @@ cmdDestroy(vshControl *ctl, const vshCmd *cmd)
if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
return false;
- if (virDomainDestroy(dom) == 0) {
+ if (vshCommandOptBool(cmd, "monitor"))
+ flags |= VIR_DOMAIN_DESTROY_MONITOR;
+
+ if ((!flags && virDomainDestroy(dom) == 0) ||
+ virDomainDestroyFlags(dom, flags) == 0) {
vshPrint(ctl, _("Domain %s destroyed\n"), name);
} else {
vshError(ctl, _("Failed to destroy domain %s"), name);
--
1.7.3.4
13 years, 4 months
[libvirt] [PATCH] esx: Use $(PYTHON) instead of the shebang to run the generator
by Matthias Bolte
---
src/Makefile.am | 5 +++--
1 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/Makefile.am b/src/Makefile.am
index 8fe7120..5ba189c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -812,8 +812,9 @@ endif
BUILT_SOURCES += $(ESX_DRIVER_GENERATED)
-$(ESX_DRIVER_GENERATED): $(srcdir)/esx/esx_vi_generator.input $(srcdir)/esx/esx_vi_generator.py
- $(AM_V_GEN)srcdir=$(srcdir) $(srcdir)/esx/esx_vi_generator.py
+$(ESX_DRIVER_GENERATED): $(srcdir)/esx/esx_vi_generator.input \
+ $(srcdir)/esx/esx_vi_generator.py
+ $(AM_V_GEN)srcdir=$(srcdir) $(PYTHON) $(srcdir)/esx/esx_vi_generator.py
if WITH_ESX
if WITH_DRIVER_MODULES
--
1.7.4.1
13 years, 4 months
[libvirt] [PATCH] qemu: Report error if qemu monitor command not found for BlockJob
by Adam Litke
From: Osier Yang <jyang(a)redhat.com>
* src/qemu/qemu_monitor_json.c: Handle error "CommandNotFound" and
report the error.
* src/qemu/qemu_monitor_text.c: If a sub info command is not found,
it prints the output of "help info", for other commands,
"unknown command" is printed.
Without this patch, libvirt always report:
An error occurred, but the cause is unknown
This patch was adapted from a patch by Osier Yang <jyang(a)redhat.com> to break
out detection of unrecognized text monitor commands into a separate function.
Signed-off-by: Adam Litke <agl(a)us.ibm.com>
---
src/qemu/qemu_monitor_json.c | 34 ++++++++++++++++++-----------
src/qemu/qemu_monitor_text.c | 47 +++++++++++++++++++++++++++++++++---------
2 files changed, 58 insertions(+), 23 deletions(-)
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 7adfb26..715b26e 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -2909,20 +2909,25 @@ int qemuMonitorJSONBlockJob(qemuMonitorPtr mon,
int ret = -1;
virJSONValuePtr cmd = NULL;
virJSONValuePtr reply = NULL;
-
- if (mode == BLOCK_JOB_ABORT)
- cmd = qemuMonitorJSONMakeCommand("block_job_cancel",
- "s:device", device, NULL);
- else if (mode == BLOCK_JOB_INFO)
- cmd = qemuMonitorJSONMakeCommand("query-block-jobs", NULL);
- else if (mode == BLOCK_JOB_SPEED)
- cmd = qemuMonitorJSONMakeCommand("block_job_set_speed",
- "s:device", device,
- "U:value", bandwidth * 1024ULL * 1024ULL,
+ const char *cmd_name = NULL;
+
+ if (mode == BLOCK_JOB_ABORT) {
+ cmd_name = "block_job_cancel";
+ cmd = qemuMonitorJSONMakeCommand(cmd_name, "s:device", device, NULL);
+ } else if (mode == BLOCK_JOB_INFO) {
+ cmd_name = "query-block-jobs";
+ cmd = qemuMonitorJSONMakeCommand(cmd_name, NULL);
+ } else if (mode == BLOCK_JOB_SPEED) {
+ cmd_name = "block_job_set_speed";
+ cmd = qemuMonitorJSONMakeCommand(cmd_name, "s:device",
+ device, "U:value",
+ bandwidth * 1024ULL * 1024ULL,
NULL);
- else if (mode == BLOCK_JOB_PULL)
- cmd = qemuMonitorJSONMakeCommand("block_stream",
- "s:device", device, NULL);
+ } else if (mode == BLOCK_JOB_PULL) {
+ cmd_name = "block_stream";
+ cmd = qemuMonitorJSONMakeCommand(cmd_name, "s:device",
+ device, NULL);
+ }
if (!cmd)
return -1;
@@ -2939,6 +2944,9 @@ int qemuMonitorJSONBlockJob(qemuMonitorPtr mon,
else if (qemuMonitorJSONHasError(reply, "NotSupported"))
qemuReportError(VIR_ERR_OPERATION_INVALID,
_("Operation is not supported for device: %s"), device);
+ else if (qemuMonitorJSONHasError(reply, "CommandNotFound"))
+ qemuReportError(VIR_ERR_OPERATION_INVALID,
+ _("Command '%s' is not found"), cmd_name);
else
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Unexpected error"));
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
index 52d924a..9119f06 100644
--- a/src/qemu/qemu_monitor_text.c
+++ b/src/qemu/qemu_monitor_text.c
@@ -271,6 +271,20 @@ qemuMonitorTextCommandWithFd(qemuMonitorPtr mon,
scm_fd, reply);
}
+/* Check monitor output for evidence that the command was not recognized.
+ * For 'info' commands, qemu returns help text. For other commands, qemu
+ * returns 'unknown command:'.
+ */
+static int
+qemuMonitorTextCommandNotFound(const char *reply)
+{
+ if (strstr(reply, "unknown command:"))
+ return 1;
+ if (strstr(reply, "info version"))
+ return 1;
+ return 0;
+}
+
static int
qemuMonitorSendDiskPassphrase(qemuMonitorPtr mon,
@@ -3031,18 +3045,24 @@ int qemuMonitorTextBlockJob(qemuMonitorPtr mon,
char *cmd = NULL;
char *reply = NULL;
int ret;
-
- if (mode == BLOCK_JOB_ABORT)
- ret = virAsprintf(&cmd, "block_job_cancel %s", device);
- else if (mode == BLOCK_JOB_INFO)
- ret = virAsprintf(&cmd, "info block-jobs");
- else if (mode == BLOCK_JOB_SPEED)
- ret = virAsprintf(&cmd, "block_job_set_speed %s %llu", device,
+ const char *cmd_name = NULL;
+
+ if (mode == BLOCK_JOB_ABORT) {
+ cmd_name = "block_job_cancel";
+ ret = virAsprintf(&cmd, "%s %s", cmd_name, device);
+ } else if (mode == BLOCK_JOB_INFO) {
+ cmd_name = "info block-jobs";
+ ret = virAsprintf(&cmd, "%s", cmd_name);
+ } else if (mode == BLOCK_JOB_SPEED) {
+ cmd_name = "block_job_set_speed";
+ ret = virAsprintf(&cmd, "%s %s %llu", cmd_name, device,
bandwidth * 1024ULL * 1024ULL);
- else if (mode == BLOCK_JOB_PULL)
- ret = virAsprintf(&cmd, "block_stream %s", device);
- else
+ } else if (mode == BLOCK_JOB_PULL) {
+ cmd_name = "block_stream";
+ ret = virAsprintf(&cmd, "%s %s", cmd_name, device);
+ } else {
return -1;
+ }
if (ret < 0) {
virReportOOMError();
@@ -3056,6 +3076,13 @@ int qemuMonitorTextBlockJob(qemuMonitorPtr mon,
goto cleanup;
}
+ if (qemuMonitorTextCommandNotFound(reply)) {
+ qemuReportError(VIR_ERR_OPERATION_INVALID,
+ _("Command '%s' is not found"), cmd_name);
+ ret = -1;
+ goto cleanup;
+ }
+
ret = qemuMonitorTextParseBlockJob(reply, device, info);
cleanup:
--
1.7.3
13 years, 4 months
[libvirt] [RFC 00/12] add support for new USB2 emulation / EHCI device
by Marc-André Lureau
Hi,
The following patch intents to implement support for new USB2 and USB
redirection added in QEMU 0.15.
It follows somewhat Daniel's plan send earlier on this ML:
https://www.redhat.com/archives/libvir-list/2011-August/msg00816.html
There are some parts that I don't really know what they should be like:
the "autoassign" or the default values at the domain XML level.
Related RHBZ https://bugzilla.redhat.com/show_bug.cgi?id=725670
cheers
Marc-André Lureau (12):
Add various USB devices QEMU_CAPS
Add USB controller models
Add a new controller type 'usb' with optionnal 'model'
USB controller can have a PCI address child element
USB devices gain a new USB address child element
Add USB companion controllers support
Add USB hub device
Modify USB port to be defined as a port path
RFC: Don't reserve slot 1 if a USB controller is defined there
RFC: Don't append 0 at usb id, so that it is compatible with legacy
-usb
Add a usb1 & usb2 qemuxml2argv test
Add usb-redir device
docs/formatdomain.html.in | 79 +++++-
docs/schemas/domain.rng | 124 ++++++--
src/conf/domain_conf.c | 333 +++++++++++++++++++-
src/conf/domain_conf.h | 59 ++++
src/libvirt_private.syms | 2 +
src/qemu/qemu_capabilities.c | 34 ++
src/qemu/qemu_capabilities.h | 11 +
src/qemu/qemu_command.c | 262 ++++++++++++++--
src/qemu/qemu_command.h | 10 +-
src/qemu/qemu_hotplug.c | 12 +-
src/vmx/vmx.c | 12 +-
tests/qemuhelptest.c | 16 +-
.../qemuxml2argv-input-usbmouse-addr.args | 1 +
.../qemuxml2argv-input-usbmouse-addr.xml | 27 ++
.../qemuxml2argv-usb-controller.args | 1 +
.../qemuxml2argv-usb-controller.xml | 16 +
tests/qemuxml2argvdata/qemuxml2argv-usb-hub.args | 1 +
tests/qemuxml2argvdata/qemuxml2argv-usb-hub.xml | 19 ++
.../qemuxml2argv-usb-ich9-companion.args | 6 +
.../qemuxml2argv-usb-ich9-companion.xml | 30 ++
.../qemuxml2argv-usb-ich9-ehci-addr.args | 1 +
.../qemuxml2argv-usb-ich9-ehci-addr.xml | 18 +
.../qemuxml2argv-usb-piix3-controller.args | 1 +
.../qemuxml2argv-usb-piix3-controller.xml | 16 +
tests/qemuxml2argvdata/qemuxml2argv-usb-ports.args | 1 +
tests/qemuxml2argvdata/qemuxml2argv-usb-ports.xml | 31 ++
tests/qemuxml2argvdata/qemuxml2argv-usb-redir.args | 8 +
tests/qemuxml2argvdata/qemuxml2argv-usb-redir.xml | 33 ++
tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.args | 1 +
tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.xml | 74 +++++
tests/qemuxml2argvtest.c | 34 ++
31 files changed, 1196 insertions(+), 77 deletions(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse-addr.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-input-usbmouse-addr.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-controller.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-controller.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-hub.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-hub.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-companion.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-companion.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-ehci-addr.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-ehci-addr.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-piix3-controller.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-piix3-controller.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-ports.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-ports.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-redir.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-redir.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb1-usb2.xml
--
1.7.6
13 years, 4 months
[libvirt] [PATCH] esx: Refactor a repeated string in the generator
by Matthias Bolte
---
src/esx/esx_vi_generator.py | 24 +++++++++++++-----------
1 files changed, 13 insertions(+), 11 deletions(-)
diff --git a/src/esx/esx_vi_generator.py b/src/esx/esx_vi_generator.py
index 239ec73..8a128df 100755
--- a/src/esx/esx_vi_generator.py
+++ b/src/esx/esx_vi_generator.py
@@ -1817,17 +1817,19 @@ for obj in managed_objects_by_name.values():
-types_typedef.write("/* Generated by esx_vi_generator.py */\n\n\n\n")
-types_typeenum.write("/* Generated by esx_vi_generator.py */\n\n")
-types_typetostring.write("/* Generated by esx_vi_generator.py */\n\n")
-types_typefromstring.write("/* Generated by esx_vi_generator.py */\n\n")
-types_header.write("/* Generated by esx_vi_generator.py */\n\n\n\n")
-types_source.write("/* Generated by esx_vi_generator.py */\n\n\n\n")
-methods_header.write("/* Generated by esx_vi_generator.py */\n\n\n\n")
-methods_source.write("/* Generated by esx_vi_generator.py */\n\n\n\n")
-methods_macro.write("/* Generated by esx_vi_generator.py */\n\n\n\n")
-helpers_header.write("/* Generated by esx_vi_generator.py */\n\n\n\n")
-helpers_source.write("/* Generated by esx_vi_generator.py */\n\n\n\n")
+notice = "/* Generated by esx_vi_generator.py */\n\n\n\n"
+
+types_typedef.write(notice)
+types_typeenum.write(notice)
+types_typetostring.write(notice)
+types_typefromstring.write(notice)
+types_header.write(notice)
+types_source.write(notice)
+methods_header.write(notice)
+methods_source.write(notice)
+methods_macro.write(notice)
+helpers_header.write(notice)
+helpers_source.write(notice)
--
1.7.4.1
13 years, 4 months
[libvirt] Curl/HTTP block device
by Radek Hladik
Hi,
I've noticed newer version of curl in last qemu changelog. It seems
that its needed for curl block device. Unfortunatelly, I was not able to
find out more. I tried to look into qemu source code and to some patches
but I am not much wiser.
As I understand it, qemu could be able to use a curl compatible URL as
block device. Probably only in readonly mode but it still would be very
usefull for i.e. ISO images.
Can anyone point me in the right direction and more importantly, is
this feature available via Libvirt?
I checked the documentation on libvirt.org and it seems that remode
disk can be only nbd/rbd/sheepdog.
Radek
13 years, 4 months
[libvirt] [PATCH] maint: fix comment typos
by Eric Blake
* src/qemu/qemu_driver.c (qemuDomainSaveInternal): Fix typo.
* src/conf/domain_event.c (virDomainEventDispatchMatchCallback):
Likewise.
* daemon/libvirtd.c (daemonRunStateInit): Likewise.
* src/lxc/lxc_container.c (lxcContainerChildMountSort): Likewise.
* src/util/virterror.c (virCopyError, virRaiseErrorFull): Likewise.
* src/xenxs/xen_sxpr.c (xenParseSxprSound): Likewise.
---
Pushing under the trivial rule.
daemon/libvirtd.c | 2 +-
src/conf/domain_event.c | 4 ++--
src/lxc/lxc_container.c | 2 +-
src/qemu/qemu_driver.c | 2 +-
src/util/virterror.c | 4 ++--
src/xenxs/xen_sxpr.c | 2 +-
6 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c
index 0530ba5..5969a82 100644
--- a/daemon/libvirtd.c
+++ b/daemon/libvirtd.c
@@ -1131,7 +1131,7 @@ static void daemonRunStateInit(void *opaque)
virNetServerPtr srv = opaque;
/* Start the stateful HV drivers
- * This is delibrately done after telling the parent process
+ * This is deliberately done after telling the parent process
* we're ready, since it can take a long time and this will
* seriously delay OS bootup process */
if (virStateInitialize(virNetServerIsPrivileged(srv)) < 0) {
diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c
index 2e0524b..3189346 100644
--- a/src/conf/domain_event.c
+++ b/src/conf/domain_event.c
@@ -1103,11 +1103,11 @@ static int virDomainEventDispatchMatchCallback(virDomainEventPtr event,
return 0;
if (cb->dom) {
- /* Delibrately ignoring 'id' for matching, since that
+ /* Deliberately ignoring 'id' for matching, since that
* will cause problems when a domain switches between
* running & shutoff states & ignoring 'name' since
* Xen sometimes renames guests during migration, thus
- * leaving 'uuid' as the only truely reliable ID we can use*/
+ * leaving 'uuid' as the only truly reliable ID we can use*/
if (memcmp(event->dom.uuid, cb->dom->uuid, VIR_UUID_BUFLEN) == 0)
return 1;
diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
index 895ef09..e425328 100644
--- a/src/lxc/lxc_container.c
+++ b/src/lxc/lxc_container.c
@@ -287,7 +287,7 @@ static int lxcContainerChildMountSort(const void *a, const void *b)
const char **sa = (const char**)a;
const char **sb = (const char**)b;
- /* Delibrately reversed args - we need to unmount deepest
+ /* Deliberately reversed args - we need to unmount deepest
children first */
return strcmp(*sb, *sa);
}
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 035ddb4..2c677b0 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -2564,7 +2564,7 @@ qemuDomainSaveInternal(struct qemud_driver *driver, virDomainPtr dom,
/* Avoid throwing an error here, since it is possible
* that with NFS we can't actually stat() the file.
* The subsequent codepaths will still raise an error
- * if a truely fatal problem is hit */
+ * if a truly fatal problem is hit */
is_reg = true;
} else {
is_reg = !!S_ISREG(sb.st_mode);
diff --git a/src/util/virterror.c b/src/util/virterror.c
index 9a27feb..c5babb1 100644
--- a/src/util/virterror.c
+++ b/src/util/virterror.c
@@ -248,7 +248,7 @@ virCopyError(virErrorPtr from,
to->int1 = from->int1;
to->int2 = from->int2;
/*
- * Delibrately not setting 'conn', 'dom', 'net' references
+ * Deliberately not setting 'conn', 'dom', 'net' references
*/
return ret;
}
@@ -708,7 +708,7 @@ virRaiseErrorFull(const char *filename ATTRIBUTE_UNUSED,
* Save the information about the error
*/
/*
- * Delibrately not setting conn, dom & net fields since
+ * Deliberately not setting conn, dom & net fields since
* they're utterly unsafe
*/
to->domain = domain;
diff --git a/src/xenxs/xen_sxpr.c b/src/xenxs/xen_sxpr.c
index 7b292bc..5e278ae 100644
--- a/src/xenxs/xen_sxpr.c
+++ b/src/xenxs/xen_sxpr.c
@@ -604,7 +604,7 @@ xenParseSxprSound(virDomainDefPtr def,
* Special compatability code for Xen with a bogus
* sound=all in config.
*
- * NB delibrately, don't include all possible
+ * NB deliberately, don't include all possible
* sound models anymore, just the 2 that were
* historically present in Xen's QEMU.
*
--
1.7.4.4
13 years, 4 months