]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
qemu: support event_idx parameter for virtio disk and net devices
authorLaine Stump <laine@laine.org>
Sat, 13 Aug 2011 06:32:45 +0000 (02:32 -0400)
committerLaine Stump <laine@laine.org>
Mon, 15 Aug 2011 13:35:42 +0000 (09:35 -0400)
In some versions of qemu, both virtio-blk-pci and virtio-net-pci
devices can have an event_idx setting that determines some details of
event processing. When it is enabled, it "reduces the number of
interrupts and exits for the guest". qemu will automatically enable
this feature when it is available, but there may be cases where this
new feature could actually make performance worse (NB: no such case
has been found so far).

As a safety switch in case such a situation is encountered in the
field, this patch adds a new attribute "event_idx" to the <driver>
element of both disk and interface devices. event_idx can be set to
"on" (to force event_idx on in case qemu has it disabled by default)
or "off" (for force event_idx off). In the case that event_idx support
isn't present in qemu, the attribute is ignored (this on the advice of
the qemu developer).

docs/formatdomain.html.in: document the new flag (marking it as
   "don't mess with this!"
docs/schemas/domain.rng: add event_idx in appropriate places
src/conf/domain_conf.[ch]: add event_idx to parser and formatter
src/libvirt_private.syms: export
   virDomainVirtioEventIdx(From|To)String
src/qemu/qemu_capabilities.[ch]: detect and report event_idx in
   disk/net
src/qemu/qemu_command.c: add event_idx parameter to qemu commandline
    when appropriate.
tests/qemuxml2argvdata/qemuxml2argv-event_idx.args,
tests/qemuxml2argvdata/qemuxml2argv-event_idx.xml,
tests/qemuxml2argvtest.c,
tests/qemuxml2xmltest.c: test cases for event_idx.

12 files changed:
docs/formatdomain.html.in
docs/schemas/domain.rng
src/conf/domain_conf.c
src/conf/domain_conf.h
src/libvirt_private.syms
src/qemu/qemu_capabilities.c
src/qemu/qemu_capabilities.h
src/qemu/qemu_command.c
tests/qemuxml2argvdata/qemuxml2argv-event_idx.args [new file with mode: 0644]
tests/qemuxml2argvdata/qemuxml2argv-event_idx.xml [new file with mode: 0644]
tests/qemuxml2argvtest.c
tests/qemuxml2xmltest.c

index 7d2ba8a09d49eb71f5396f4841bd6bd33a004d5d..f46771df0f9db66d1845add27ed7b7dd7d4433b2 100644 (file)
     &lt;/disk&gt;
       ...
     &lt;disk type='network'&gt;
-      &lt;driver name="qemu" type="raw" io="threads" ioeventfd="on"/&gt;
+      &lt;driver name="qemu" type="raw" io="threads" ioeventfd="on" event_idx="off"/&gt;
       &lt;source protocol="sheepdog" name="image_name"&gt;
         &lt;host name="hostname" port="7000"/&gt;
       &lt;/source&gt;
             <b>In general you should leave this option alone, unless you
             are very certain you know what you are doing.</b>
           </li>
+          <li>
+            The optional <code>event_idx</code> 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.
+            <span class="since">Since 0.9.5 (QEMU and KVM only)</span>
+            <b>In general you should leave this option alone, unless you
+            are very certain you know what you are doing.</b>
+          </li>
         </ul>
       </dd>
       <dt><code>boot</code></dt>
@@ -1850,7 +1863,7 @@ qemu-kvm -net nic,model=? /dev/null
       &lt;source network='default'/&gt;
       &lt;target dev='vnet1'/&gt;
       &lt;model type='virtio'/&gt;
-      <b>&lt;driver name='vhost' txmode='iothread' ioeventfd='on'/&gt;</b>
+      <b>&lt;driver name='vhost' txmode='iothread' ioeventfd='on' event_idx='off'/&gt;</b>
     &lt;/interface&gt;
   &lt;/devices&gt;
   ...</pre>
@@ -1914,6 +1927,20 @@ qemu-kvm -net nic,model=? /dev/null
         on overloaded host it could increase guest I/O latency.
         <span class="since">Since 0.9.3 (QEMU and KVM only)</span><br/><br/>
 
+        <b>In general you should leave this option alone, unless you
+        are very certain you know what you are doing.</b>
+      </dd>
+      <dt><code>event_idx</code></dt>
+      <dd>
+        The <code>event_idx</code> 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.
+        <span class="since">Since 0.9.5 (QEMU and KVM only)</span><br/><br/>
+
         <b>In general you should leave this option alone, unless you
         are very certain you know what you are doing.</b>
       </dd>
index 6ccbeed27159fa76f675a83107b7d48febc00b61..dd8c41ae0cb80209846d3bf450922c5dfce09835 100644 (file)
       <optional>
         <ref name="ioeventfd"/>
       </optional>
+      <optional>
+        <ref name="event_idx"/>
+      </optional>
       <empty/>
     </element>
   </define>
       </choice>
     </attribute>
   </define>
+  <define name="event_idx">
+    <attribute name="event_idx">
+      <choice>
+        <value>on</value>
+        <value>off</value>
+      </choice>
+    </attribute>
+  </define>
   <define name="controller">
     <element name="controller">
       <choice>
           <optional>
             <ref name="ioeventfd"/>
           </optional>
+          <optional>
+            <ref name="event_idx"/>
+          </optional>
           <empty/>
         </element>
       </optional>
index 010ce571c02fa9f460c2e93603d3ad1bd3f20b9d..ce1f3c552f908b1d2c4a6ab3b9f25e3f9d6b2b96 100644 (file)
@@ -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, "      <driver");
         if (def->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");
         }
     }
index 1d5af95b41c31d8ce8f89051533ae784290e636a..2cc9b0653fdba38209ca996e8cccc9280812d19b 100644 (file)
@@ -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)
index 64b91eea3bb1522d99e3719e142c0ad586f06fe2..4286fbdf16372073f6191a8b6e02db4bf8e8a761 100644 (file)
@@ -414,6 +414,8 @@ virDomainVideoDefaultRAM;
 virDomainVideoDefaultType;
 virDomainVideoTypeFromString;
 virDomainVideoTypeToString;
+virDomainVirtioEventIdxTypeFromString;
+virDomainVirtioEventIdxTypeToString;
 virDomainVirtTypeToString;
 virDomainWatchdogActionTypeFromString;
 virDomainWatchdogActionTypeToString;
index 3f36212597b6739a34ffda6f17be48db15a20d62..f665de4c094a0a48796800fe14b0210fa5c93ca3 100644 (file)
@@ -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;
 }
index d251262362bcdd40fd7bd1f4592199304fbc20d1..13af0b9d7bc423e0e0f00cacf33d3362c5da50fb 100644 (file)
@@ -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 */
 };
index 2a4882691cd65440f27f99ffd8ec224ef3724519..dbfc7d973c26c6e09ad99a6dae30e3c431577df6 100644 (file)
@@ -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 (file)
index 0000000..f6ebb60
--- /dev/null
@@ -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 (file)
index 0000000..81f2200
--- /dev/null
@@ -0,0 +1,57 @@
+<domain type='qemu'>
+  <name>test</name>
+  <uuid>bba65c0e-c049-934f-b6aa-4e2c0582acdf</uuid>
+  <memory>1048576</memory>
+  <currentMemory>1048576</currentMemory>
+  <vcpu>1</vcpu>
+  <os>
+    <type arch='x86_64' machine='pc-0.13'>hvm</type>
+    <boot dev='cdrom'/>
+    <boot dev='hd'/>
+    <bootmenu enable='yes'/>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>restart</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu</emulator>
+    <disk type='file' device='disk'>
+      <driver name='qemu' type='qcow2' event_idx='on'/>
+      <source file='/var/lib/libvirt/images/f14.img'/>
+      <target dev='vda' bus='virtio'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+    </disk>
+    <disk type='file' device='cdrom'>
+      <driver name='qemu' type='raw'/>
+      <source file='/var/lib/libvirt/Fedora-14-x86_64-Live-KDE.iso'/>
+      <target dev='hdc' bus='ide'/>
+      <readonly/>
+      <address type='drive' controller='0' bus='1' unit='0'/>
+    </disk>
+    <controller type='virtio-serial' index='0'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
+    </controller>
+    <controller type='ide' index='0'/>
+    <interface type='user'>
+      <mac address='52:54:00:e5:48:58'/>
+      <model type='virtio'/>
+      <driver name='vhost' event_idx='off'/>
+    </interface>
+    <serial type='pty'>
+      <target port='0'/>
+    </serial>
+    <console type='pty'>
+      <target type='serial' port='0'/>
+    </console>
+    <input type='mouse' bus='ps2'/>
+    <graphics type='vnc' port='5091' autoport='no' listen='127.0.0.1'>
+      <listen type='address' address='127.0.0.1'/>
+    </graphics>
+    <video>
+      <model type='vga' vram='9216' heads='1'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
+    </video>
+    <memballoon model='virtio'/>
+  </devices>
+</domain>
index 434264a4283ca86221d7f805c9cd1c88abdc2874..6e8da5e756faa7538cc70c25ec3a29c9277d0e63 100644 (file)
@@ -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);
index c74f96c7b533a0bc159c6025088dd049f7deac4d..4e109d5294402e1270daca41fa8aaa0040adf77c 100644 (file)
@@ -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");