diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 7d2ba8a09d..f46771df0f 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -904,7 +904,7 @@
</disk>
...
<disk type='network'>
- <driver name="qemu" type="raw" io="threads" ioeventfd="on"/>
+ <driver name="qemu" type="raw" io="threads" ioeventfd="on" event_idx="off"/>
<source protocol="sheepdog" name="image_name">
<host name="hostname" port="7000"/>
</source>
@@ -1004,6 +1004,19 @@
In general you should leave this option alone, unless you
are very certain you know what you are doing.
+
+ The optional event_idx
attribute controls
+ some aspects of device event processing. The value can be
+ either 'on' or 'off' - if it is on, it will reduce the
+ number of interupts and exits for the guest. The default
+ is determined by QEMU; usually if the feature is
+ supported, default is on. In case there is a situation
+ where this behavior is suboptimal, this attribute provides
+ a way to force the feature off.
+ Since 0.9.5 (QEMU and KVM only)
+ In general you should leave this option alone, unless you
+ are very certain you know what you are doing.
+
boot
@@ -1850,7 +1863,7 @@ qemu-kvm -net nic,model=? /dev/null
<source network='default'/>
<target dev='vnet1'/>
<model type='virtio'/>
- <driver name='vhost' txmode='iothread' ioeventfd='on'/>
+ <driver name='vhost' txmode='iothread' ioeventfd='on' event_idx='off'/>
</interface>
</devices>
...
@@ -1914,6 +1927,20 @@ qemu-kvm -net nic,model=? /dev/null
on overloaded host it could increase guest I/O latency.
Since 0.9.3 (QEMU and KVM only)
+ In general you should leave this option alone, unless you
+ are very certain you know what you are doing.
+
+ event_idx
+
+ The event_idx
attribute controls some aspects of
+ device event processing. The value can be either 'on' or 'off'
+ - if it is on, it will reduce the number of interupts and
+ exits for the guest. The default is determined by QEMU;
+ usually if the feature is supported, default is on. In case
+ there is a situation where this behavior is suboptimal, this
+ attribute provides a way to force the feature off.
+ Since 0.9.5 (QEMU and KVM only)
+
In general you should leave this option alone, unless you
are very certain you know what you are doing.
diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng
index 6ccbeed271..dd8c41ae0c 100644
--- a/docs/schemas/domain.rng
+++ b/docs/schemas/domain.rng
@@ -807,6 +807,9 @@
+
+
+
@@ -854,6 +857,14 @@
+
+
+
+ on
+ off
+
+
+
@@ -1165,6 +1176,9 @@
+
+
+
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 010ce571c0..ce1f3c552f 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -182,6 +182,10 @@ VIR_ENUM_IMPL(virDomainIoEventFd, VIR_DOMAIN_IO_EVENT_FD_LAST,
"on",
"off")
+VIR_ENUM_IMPL(virDomainVirtioEventIdx, VIR_DOMAIN_VIRTIO_EVENT_IDX_LAST,
+ "default",
+ "on",
+ "off")
VIR_ENUM_IMPL(virDomainController, VIR_DOMAIN_CONTROLLER_TYPE_LAST,
"ide",
@@ -2081,6 +2085,7 @@ virDomainDiskDefParseXML(virCapsPtr caps,
char *error_policy = NULL;
char *iotag = NULL;
char *ioeventfd = NULL;
+ char *event_idx = NULL;
char *devaddr = NULL;
virStorageEncryptionPtr encryption = NULL;
char *serial = NULL;
@@ -2197,6 +2202,7 @@ virDomainDiskDefParseXML(virCapsPtr caps,
error_policy = virXMLPropString(cur, "error_policy");
iotag = virXMLPropString(cur, "io");
ioeventfd = virXMLPropString(cur, "ioeventfd");
+ event_idx = virXMLPropString(cur, "event_idx");
} else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
def->readonly = 1;
} else if (xmlStrEqual(cur->name, BAD_CAST "shareable")) {
@@ -2351,6 +2357,24 @@ virDomainDiskDefParseXML(virCapsPtr caps,
def->ioeventfd=i;
}
+ if (event_idx) {
+ if (def->bus != VIR_DOMAIN_DISK_BUS_VIRTIO) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("disk event_idx mode supported "
+ "only for virtio bus"));
+ goto error;
+ }
+
+ int idx;
+ if ((idx = virDomainVirtioEventIdxTypeFromString(event_idx)) <= 0) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unknown disk event_idx mode '%s'"),
+ event_idx);
+ goto error;
+ }
+ def->event_idx = idx;
+ }
+
if (devaddr) {
if (virDomainParseLegacyDeviceAddress(devaddr,
&def->info.addr.pci) < 0) {
@@ -2414,6 +2438,7 @@ cleanup:
VIR_FREE(error_policy);
VIR_FREE(iotag);
VIR_FREE(ioeventfd);
+ VIR_FREE(event_idx);
VIR_FREE(devaddr);
VIR_FREE(serial);
virStorageEncryptionFree(encryption);
@@ -2744,6 +2769,7 @@ virDomainNetDefParseXML(virCapsPtr caps,
char *backend = NULL;
char *txmode = NULL;
char *ioeventfd = NULL;
+ char *event_idx = NULL;
char *filter = NULL;
char *internal = NULL;
char *devaddr = NULL;
@@ -2835,6 +2861,7 @@ virDomainNetDefParseXML(virCapsPtr caps,
backend = virXMLPropString(cur, "name");
txmode = virXMLPropString(cur, "txmode");
ioeventfd = virXMLPropString(cur, "ioeventfd");
+ event_idx = virXMLPropString(cur, "event_idx");
} else if (xmlStrEqual (cur->name, BAD_CAST "filterref")) {
filter = virXMLPropString(cur, "filter");
VIR_FREE(filterparams);
@@ -3075,6 +3102,16 @@ virDomainNetDefParseXML(virCapsPtr caps,
}
def->driver.virtio.ioeventfd = i;
}
+ if (event_idx) {
+ int idx;
+ if ((idx = virDomainVirtioEventIdxTypeFromString(event_idx)) <= 0) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unknown interface event_idx mode '%s'"),
+ event_idx);
+ goto error;
+ }
+ def->driver.virtio.event_idx = idx;
+ }
}
if (filter != NULL) {
@@ -3118,6 +3155,7 @@ cleanup:
VIR_FREE(backend);
VIR_FREE(txmode);
VIR_FREE(ioeventfd);
+ VIR_FREE(event_idx);
VIR_FREE(filter);
VIR_FREE(type);
VIR_FREE(internal);
@@ -8576,6 +8614,7 @@ virDomainDiskDefFormat(virBufferPtr buf,
const char *error_policy = virDomainDiskErrorPolicyTypeToString(def->error_policy);
const char *iomode = virDomainDiskIoTypeToString(def->iomode);
const char *ioeventfd = virDomainIoEventFdTypeToString(def->ioeventfd);
+ const char *event_idx = virDomainVirtioEventIdxTypeToString(def->event_idx);
if (!type) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
@@ -8608,7 +8647,7 @@ virDomainDiskDefFormat(virBufferPtr buf,
type, device);
if (def->driverName || def->driverType || def->cachemode ||
- def->ioeventfd) {
+ def->ioeventfd || def->event_idx) {
virBufferAsprintf(buf, " driverName)
virBufferAsprintf(buf, " name='%s'", def->driverName);
@@ -8622,6 +8661,8 @@ virDomainDiskDefFormat(virBufferPtr buf,
virBufferAsprintf(buf, " io='%s'", iomode);
if (def->ioeventfd)
virBufferAsprintf(buf, " ioeventfd='%s'", ioeventfd);
+ if (def->event_idx)
+ virBufferAsprintf(buf, " event_idx='%s'", event_idx);
virBufferAsprintf(buf, "/>\n");
}
@@ -8996,6 +9037,10 @@ virDomainNetDefFormat(virBufferPtr buf,
virBufferAsprintf(buf, " ioeventfd='%s'",
virDomainIoEventFdTypeToString(def->driver.virtio.ioeventfd));
}
+ if (def->driver.virtio.event_idx) {
+ virBufferAsprintf(buf, " event_idx='%s'",
+ virDomainVirtioEventIdxTypeToString(def->driver.virtio.event_idx));
+ }
virBufferAddLit(buf, "/>\n");
}
}
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 1d5af95b41..2cc9b0653f 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -209,6 +209,14 @@ enum virDomainIoEventFd {
VIR_DOMAIN_IO_EVENT_FD_LAST
};
+enum virDomainVirtioEventIdx {
+ VIR_DOMAIN_VIRTIO_EVENT_IDX_DEFAULT = 0,
+ VIR_DOMAIN_VIRTIO_EVENT_IDX_ON,
+ VIR_DOMAIN_VIRTIO_EVENT_IDX_OFF,
+
+ VIR_DOMAIN_VIRTIO_EVENT_IDX_LAST
+};
+
/* Stores the virtual disk configuration */
typedef struct _virDomainDiskDef virDomainDiskDef;
typedef virDomainDiskDef *virDomainDiskDefPtr;
@@ -229,6 +237,7 @@ struct _virDomainDiskDef {
int bootIndex;
int iomode;
int ioeventfd;
+ int event_idx;
unsigned int readonly : 1;
unsigned int shared : 1;
virDomainDeviceInfo info;
@@ -377,6 +386,7 @@ struct _virDomainNetDef {
enum virDomainNetBackendType name; /* which driver backend to use */
enum virDomainNetVirtioTxModeType txmode;
enum virDomainIoEventFd ioeventfd;
+ enum virDomainVirtioEventIdx event_idx;
} virtio;
} driver;
union {
@@ -1661,6 +1671,7 @@ VIR_ENUM_DECL(virDomainDiskErrorPolicy)
VIR_ENUM_DECL(virDomainDiskProtocol)
VIR_ENUM_DECL(virDomainDiskIo)
VIR_ENUM_DECL(virDomainIoEventFd)
+VIR_ENUM_DECL(virDomainVirtioEventIdx)
VIR_ENUM_DECL(virDomainController)
VIR_ENUM_DECL(virDomainControllerModel)
VIR_ENUM_DECL(virDomainFS)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 64b91eea3b..4286fbdf16 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -414,6 +414,8 @@ virDomainVideoDefaultRAM;
virDomainVideoDefaultType;
virDomainVideoTypeFromString;
virDomainVideoTypeToString;
+virDomainVirtioEventIdxTypeFromString;
+virDomainVirtioEventIdxTypeToString;
virDomainVirtTypeToString;
virDomainWatchdogActionTypeFromString;
virDomainWatchdogActionTypeToString;
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 3f36212597..f665de4c09 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -123,6 +123,8 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST,
"pci-multifunction", /* 60 */
"virtio-blk-pci.ioeventfd",
"sga",
+ "virtio-blk-pci.event_idx",
+ "virtio-net-pci.event_idx",
);
struct qemu_feature_flags {
@@ -1215,6 +1217,10 @@ qemuCapsParseDeviceStr(const char *str, virBitmapPtr flags)
qemuCapsSet(flags, QEMU_CAPS_VIRTIO_IOEVENTFD);
if (strstr(str, "name \"sga\""))
qemuCapsSet(flags, QEMU_CAPS_SGA);
+ if (strstr(str, "virtio-blk-pci.event_idx"))
+ qemuCapsSet(flags, QEMU_CAPS_VIRTIO_BLK_EVENT_IDX);
+ if (strstr(str, "virtio-net-pci.event_idx"))
+ qemuCapsSet(flags, QEMU_CAPS_VIRTIO_NET_EVENT_IDX);
return 0;
}
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index d251262362..13af0b9d7b 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -98,6 +98,8 @@ enum qemuCapsFlags {
QEMU_CAPS_PCI_MULTIFUNCTION = 60, /* -device multifunction=on|off */
QEMU_CAPS_VIRTIO_IOEVENTFD = 61, /* IOeventFD feature: virtio-{net|blk}-pci.ioeventfd=on/off */
QEMU_CAPS_SGA = 62, /* Serial Graphics Adapter */
+ QEMU_CAPS_VIRTIO_BLK_EVENT_IDX = 63, /* virtio-blk-pci.event_idx */
+ QEMU_CAPS_VIRTIO_NET_EVENT_IDX = 64, /* virtio-net-pci.event_idx */
QEMU_CAPS_LAST, /* this must always be the last item */
};
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 2a4882691c..dbfc7d973c 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -1585,6 +1585,11 @@ qemuBuildDriveDevStr(virDomainDiskDefPtr disk,
case VIR_DOMAIN_DISK_BUS_VIRTIO:
virBufferAddLit(&opt, "virtio-blk-pci");
qemuBuildIoEventFdStr(&opt, disk->ioeventfd, qemuCaps);
+ if (disk->event_idx &&
+ qemuCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_BLK_EVENT_IDX)) {
+ virBufferAsprintf(&opt, ",event_idx=%s",
+ virDomainVirtioEventIdxTypeToString(disk->event_idx));
+ }
qemuBuildDeviceAddressStr(&opt, &disk->info, qemuCaps);
break;
case VIR_DOMAIN_DISK_BUS_USB:
@@ -1808,8 +1813,14 @@ qemuBuildNicDevStr(virDomainNetDefPtr net,
goto error;
}
}
- if (usingVirtio)
+ if (usingVirtio) {
qemuBuildIoEventFdStr(&buf, net->driver.virtio.ioeventfd, qemuCaps);
+ if (net->driver.virtio.event_idx &&
+ qemuCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_NET_EVENT_IDX)) {
+ virBufferAsprintf(&buf, ",event_idx=%s",
+ virDomainVirtioEventIdxTypeToString(net->driver.virtio.event_idx));
+ }
+ }
if (vlan == -1)
virBufferAsprintf(&buf, ",netdev=host%s", net->info.alias);
else
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-event_idx.args b/tests/qemuxml2argvdata/qemuxml2argv-event_idx.args
new file mode 100644
index 0000000000..f6ebb60da0
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-event_idx.args
@@ -0,0 +1,11 @@
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test QEMU_AUDIO_DRV=none \
+/usr/bin/qemu -S -M pc-0.13 -m 1024 -smp 1 -nodefaults \
+-monitor unix:/tmp/test-monitor,server,nowait -no-acpi \
+-boot dc -device virtio-serial-pci,id=virtio-serial0,bus=pci.0,addr=0x6 \
+-drive file=/var/lib/libvirt/images/f14.img,if=none,id=drive-virtio-disk0 \
+-device virtio-blk-pci,event_idx=on,bus=pci.0,addr=0x4,drive=drive-virtio-disk0,id=virtio-disk0 \
+-drive file=/var/lib/libvirt/Fedora-14-x86_64-Live-KDE.iso,if=none,media=cdrom,id=drive-ide0-1-0 \
+-device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0 \
+-device virtio-net-pci,event_idx=off,vlan=0,id=net0,mac=52:54:00:e5:48:58,bus=pci.0,addr=0x3 \
+-net user,vlan=0,name=hostnet0 -serial pty -usb -vnc 127.0.0.1:-809 -std-vga \
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x5
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-event_idx.xml b/tests/qemuxml2argvdata/qemuxml2argv-event_idx.xml
new file mode 100644
index 0000000000..81f2200299
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-event_idx.xml
@@ -0,0 +1,57 @@
+
+ test
+ bba65c0e-c049-934f-b6aa-4e2c0582acdf
+ 1048576
+ 1048576
+ 1
+
+ hvm
+
+
+
+
+
+ destroy
+ restart
+ restart
+
+ /usr/bin/qemu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index 434264a428..6e8da5e756 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -359,6 +359,11 @@ mymain(void)
DO_TEST("disk-ioeventfd", false,
QEMU_CAPS_DRIVE, QEMU_CAPS_VIRTIO_IOEVENTFD,
QEMU_CAPS_VIRTIO_TX_ALG, QEMU_CAPS_DEVICE);
+ DO_TEST("event_idx", false,
+ QEMU_CAPS_DRIVE,
+ QEMU_CAPS_VIRTIO_BLK_EVENT_IDX,
+ QEMU_CAPS_VIRTIO_NET_EVENT_IDX,
+ QEMU_CAPS_DEVICE);
DO_TEST("graphics-vnc", false, NONE);
DO_TEST("graphics-vnc-socket", false, NONE);
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index c74f96c7b5..4e109d5294 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -187,6 +187,7 @@ mymain(void)
DO_TEST("smp");
DO_TEST("lease");
+ DO_TEST("event_idx");
/* These tests generate different XML */
DO_TEST_DIFFERENT("balloon-device-auto");