[libvirt] [PATCH] qemu: Add option to enable/disable IOEventFD feature

Michal Privoznik mprivozn at redhat.com
Wed Apr 27 10:17:25 UTC 2011


This feature allows QEMU to achieve higher throughput, but is available
only in recent versions. It is accessible via ioeventfd attribute
with accepting values 'on', 'off'. Only experienced users needs to set
this, because QEMU defaults to 'on', meaning higher performance.
Translates into virtio-{blk|net}-pci.ioeventfd option.
---
 docs/formatdomain.html.in    |   15 ++++++++++++-
 docs/schemas/domain.rng      |   14 +++++++++++++
 src/conf/domain_conf.c       |   44 +++++++++++++++++++++++++++++++++++++++++-
 src/conf/domain_conf.h       |   12 +++++++++++
 src/libvirt_private.syms     |    2 +
 src/qemu/qemu_capabilities.c |    2 +
 src/qemu/qemu_capabilities.h |    1 +
 src/qemu/qemu_command.c      |   23 +++++++++++++++++++++
 tests/qemuhelptest.c         |    3 +-
 9 files changed, 112 insertions(+), 4 deletions(-)

diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index a055b38..409b26a 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -751,7 +751,7 @@
     </disk>
       ...
     <disk type='network'>
-      <driver name="qemu" type="raw" io="threads"/>
+      <driver name="qemu" type="raw" io="threads" ioeventfd="on"/>
       <source protocol="sheepdog" name="image_name">
         <host name="hostname" port="7000"/>
       </source>
@@ -835,6 +835,11 @@
             policies on I/O; qemu guests support "threads" and
             "native". <span class="since">Since 0.8.8</span>
           </li>
+          <li>
+           The optional <code>ioeventfd</code> attribute enables or disables
+           IOEventFD feature for virtqueue notify. The value can be either
+           'on' or 'off'.
+            <span class="since">Since 0.9.0 (QEMU and KVM only)</span>
         </ul>
       </dd>
       <dt><code>boot</code></dt>
@@ -1458,7 +1463,7 @@ qemu-kvm -net nic,model=? /dev/null
       <source network='default'/>
       <target dev='vnet1'/>
       <model type='virtio'/>
-      <b><driver name='vhost' txmode='iothread'/></b>
+      <b><driver name='vhost' txmode='iothread' ioeventfd='on'/></b>
     </interface>
   </devices>
   ...</pre>
@@ -1509,6 +1514,12 @@ qemu-kvm -net nic,model=? /dev/null
         <b>In general you should leave this option alone, unless you
         are very certain you know what you are doing.</b>
       </dd>
+      <dt><code>ioeventfd</code><code></dt>
+      <dd>
+        This optional attribute allows users to enable or disable IOeventFD
+        feature for virtqueue notify. The value can be either 'on' or 'off'.
+        <span class="since">Since 0.9.0 (QEMU and KVM only)</span>
+      </dd>
     </dl>
 
     <h5><a name="elementsNICSTargetOverride">Overriding the target element</a></h5>
diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng
index 7163c6e..c3e8e15 100644
--- a/docs/schemas/domain.rng
+++ b/docs/schemas/domain.rng
@@ -735,6 +735,9 @@
       <optional>
         <ref name="driverIO"/>
       </optional>
+      <optional>
+        <ref name="ioeventfd"/>
+      </optional>
       <empty/>
     </element>
   </define>
@@ -774,6 +777,14 @@
       </choice>
     </attribute>
   </define>
+  <define name="ioeventfd">
+    <attribute name="ioeventfd">
+      <choice>
+        <value>on</value>
+        <value>off</value>
+      </choice>
+    </attribute>
+  </define>
   <define name="controller">
     <element name="controller">
       <choice>
@@ -1074,6 +1085,9 @@
               </choice>
             </attribute>
           </optional>
+          <optional>
+            <ref name="ioeventfd"/>
+          </optional>
           <empty/>
         </element>
       </optional>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 0e7aeb5..2aca162 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -155,6 +155,11 @@ VIR_ENUM_IMPL(virDomainDiskIo, VIR_DOMAIN_DISK_IO_LAST,
               "native",
               "threads")
 
+VIR_ENUM_IMPL(virDomainVirtioEventFd, VIR_DOMAIN_VIRTIO_EVENT_FD_LAST,
+              "default",
+              "on",
+              "off")
+
 VIR_ENUM_IMPL(virDomainController, VIR_DOMAIN_CONTROLLER_TYPE_LAST,
               "ide",
               "fdc",
@@ -1829,6 +1834,7 @@ virDomainDiskDefParseXML(virCapsPtr caps,
     char *cachetag = NULL;
     char *error_policy = NULL;
     char *iotag = NULL;
+    char *ioeventfd = NULL;
     char *devaddr = NULL;
     virStorageEncryptionPtr encryption = NULL;
     char *serial = NULL;
@@ -1944,6 +1950,7 @@ virDomainDiskDefParseXML(virCapsPtr caps,
                 cachetag = virXMLPropString(cur, "cache");
                 error_policy = virXMLPropString(cur, "error_policy");
                 iotag = virXMLPropString(cur, "io");
+                ioeventfd = virXMLPropString(cur, "ioeventfd");
             } else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
                 def->readonly = 1;
             } else if (xmlStrEqual(cur->name, BAD_CAST "shareable")) {
@@ -2080,6 +2087,18 @@ virDomainDiskDefParseXML(virCapsPtr caps,
         }
     }
 
+    if (ioeventfd) {
+        int i;
+        if ((i = virDomainVirtioEventFdTypeFromString(ioeventfd)) <= 0) {
+            virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                                 _("unknown disk ioeventfd mode '%s'"),
+                                 ioeventfd);
+            goto error;
+        }
+        def->ioeventfd = i;
+    }
+
+
     if (devaddr) {
         if (virDomainParseLegacyDeviceAddress(devaddr,
                                               &def->info.addr.pci) < 0) {
@@ -2142,6 +2161,7 @@ cleanup:
     VIR_FREE(cachetag);
     VIR_FREE(error_policy);
     VIR_FREE(iotag);
+    VIR_FREE(ioeventfd);
     VIR_FREE(devaddr);
     VIR_FREE(serial);
     virStorageEncryptionFree(encryption);
@@ -2529,6 +2549,7 @@ virDomainNetDefParseXML(virCapsPtr caps,
     char *model = NULL;
     char *backend = NULL;
     char *txmode = NULL;
+    char *ioeventfd = NULL;
     char *filter = NULL;
     char *internal = NULL;
     char *devaddr = NULL;
@@ -2618,6 +2639,7 @@ virDomainNetDefParseXML(virCapsPtr caps,
             } else if (xmlStrEqual (cur->name, BAD_CAST "driver")) {
                 backend = virXMLPropString(cur, "name");
                 txmode = virXMLPropString(cur, "txmode");
+                ioeventfd = virXMLPropString(cur, "ioeventfd");
             } else if (xmlStrEqual (cur->name, BAD_CAST "filterref")) {
                 filter = virXMLPropString(cur, "filter");
                 VIR_FREE(filterparams);
@@ -2834,6 +2856,17 @@ virDomainNetDefParseXML(virCapsPtr caps,
             }
             def->driver.virtio.txmode = m;
         }
+        if (ioeventfd != NULL) {
+            int i;
+            if ((i = virDomainVirtioEventFdTypeFromString(ioeventfd)) <= 0) {
+                virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                                     _("unknown interface <driver "
+                                       "ioeventfd='%s'> has been specified"),
+                                     ioeventfd);
+                goto error;
+            }
+            def->driver.virtio.ioeventfd = i;
+        }
     }
 
     if (filter != NULL) {
@@ -2873,6 +2906,7 @@ cleanup:
     VIR_FREE(model);
     VIR_FREE(backend);
     VIR_FREE(txmode);
+    VIR_FREE(ioeventfd);
     VIR_FREE(filter);
     VIR_FREE(type);
     VIR_FREE(internal);
@@ -6910,6 +6944,7 @@ virDomainDiskDefFormat(virBufferPtr buf,
     const char *cachemode = virDomainDiskCacheTypeToString(def->cachemode);
     const char *error_policy = virDomainDiskErrorPolicyTypeToString(def->error_policy);
     const char *iomode = virDomainDiskIoTypeToString(def->iomode);
+    const char *ioeventfd = virDomainVirtioEventFdTypeToString(def->ioeventfd);
 
     if (!type) {
         virDomainReportError(VIR_ERR_INTERNAL_ERROR,
@@ -6941,7 +6976,8 @@ virDomainDiskDefFormat(virBufferPtr buf,
                       "    <disk type='%s' device='%s'>\n",
                       type, device);
 
-    if (def->driverName || def->driverType || def->cachemode) {
+    if (def->driverName || def->driverType || def->cachemode ||
+        def->ioeventfd) {
         virBufferVSprintf(buf, "      <driver");
         if (def->driverName)
             virBufferVSprintf(buf, " name='%s'", def->driverName);
@@ -6953,6 +6989,8 @@ virDomainDiskDefFormat(virBufferPtr buf,
             virBufferVSprintf(buf, " error_policy='%s'", error_policy);
         if (def->iomode)
             virBufferVSprintf(buf, " io='%s'", iomode);
+        if (def->ioeventfd)
+            virBufferVSprintf(buf, " ioeventfd='%s'", ioeventfd);
         virBufferVSprintf(buf, "/>\n");
     }
 
@@ -7243,6 +7281,10 @@ virDomainNetDefFormat(virBufferPtr buf,
                 virBufferVSprintf(buf, " txmode='%s'",
                                   virDomainNetVirtioTxModeTypeToString(def->driver.virtio.txmode));
             }
+            if (def->driver.virtio.ioeventfd) {
+                virBufferVSprintf(buf, " ioeventfd='%s'",
+                                  virDomainVirtioEventFdTypeToString(def->driver.virtio.ioeventfd));
+            }
             virBufferAddLit(buf, "/>\n");
         }
     }
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 6ea30b9..42ca601 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -197,6 +197,15 @@ enum  virDomainDiskIo {
     VIR_DOMAIN_DISK_IO_LAST
 };
 
+enum virDomainVirtioEventFd {
+    VIR_DOMAIN_VIRTIO_EVENT_FD_DEFAULT = 0,
+    VIR_DOMAIN_VIRTIO_EVENT_FD_ON,
+    VIR_DOMAIN_VIRTIO_EVENT_FD_OFF,
+
+    VIR_DOMAIN_VIRTIO_EVENT_FD_LAST
+};
+
+
 /* Stores the virtual disk configuration */
 typedef struct _virDomainDiskDef virDomainDiskDef;
 typedef virDomainDiskDef *virDomainDiskDefPtr;
@@ -216,6 +225,7 @@ struct _virDomainDiskDef {
     int error_policy;
     int bootIndex;
     int iomode;
+    enum virDomainVirtioEventFd ioeventfd;
     unsigned int readonly : 1;
     unsigned int shared : 1;
     virDomainDeviceInfo info;
@@ -351,6 +361,7 @@ struct _virDomainNetDef {
         struct {
             enum virDomainNetBackendType name; /* which driver backend to use */
             enum virDomainNetVirtioTxModeType txmode;
+            enum virDomainVirtioEventFd ioeventfd;
         } virtio;
     } driver;
     union {
@@ -1439,6 +1450,7 @@ VIR_ENUM_DECL(virDomainDiskCache)
 VIR_ENUM_DECL(virDomainDiskErrorPolicy)
 VIR_ENUM_DECL(virDomainDiskProtocol)
 VIR_ENUM_DECL(virDomainDiskIo)
+VIR_ENUM_DECL(virDomainVirtioEventFd)
 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 3d53287..1bd90a1 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -338,6 +338,8 @@ virDomainVideoDefaultType;
 virDomainVideoTypeFromString;
 virDomainVideoTypeToString;
 virDomainVirtTypeToString;
+virDomainVirtioEventFdTypeFromString;
+virDomainVirtioEventFdTypeToString;
 virDomainWatchdogActionTypeFromString;
 virDomainWatchdogActionTypeToString;
 virDomainWatchdogModelTypeFromString;
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 63486cc..6e8aa50 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -1124,6 +1124,8 @@ qemuCapsParseDeviceStr(const char *str, virBitmapPtr flags)
         qemuCapsSet(flags, QEMU_CAPS_VIRTIO_TX_ALG);
     if (strstr(str, "name \"qxl-vga\""))
         qemuCapsSet(flags, QEMU_CAPS_DEVICE_QXL_VGA);
+    if (strstr(str, "virtio-blk-pci.ioeventfd"))
+        qemuCapsSet(flags, QEMU_CAPS_VIRTIO_IOEVENTFD);
 
     return 0;
 }
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index 68c5958..400d73c 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -95,6 +95,7 @@ enum qemuCapsFlags {
     QEMU_CAPS_DEVICE_SPICEVMC   = 57, /* older -device spicevmc*/
     QEMU_CAPS_VIRTIO_TX_ALG     = 58, /* -device virtio-net-pci,tx=string */
     QEMU_CAPS_DEVICE_QXL_VGA    = 59, /* Is the primary and vga campatible qxl device named qxl-vga? */
+    QEMU_CAPS_VIRTIO_IOEVENTFD  = 60, /* IOEventFD feature: virtio-{net|blk}-pci.ioeventfd=on/off */
 
     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 2205ed1..41b4fdd 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -1169,6 +1169,26 @@ qemuBuildDeviceAddressStr(virBufferPtr buf,
     return 0;
 }
 
+static int
+qemuBuildIoEventFdStr(virBufferPtr buf,
+                      enum virDomainVirtioEventFd use,
+                      virBitmapPtr qemuCaps)
+{
+    if (qemuCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_IOEVENTFD)) {
+        switch (use) {
+        case VIR_DOMAIN_VIRTIO_EVENT_FD_ON:
+        case VIR_DOMAIN_VIRTIO_EVENT_FD_OFF:
+            virBufferVSprintf(buf, ",ioeventfd=%s",
+                              virDomainVirtioEventFdTypeToString(use));
+            break;
+        default:
+            /* In other cases (_DEFAULT, _LAST) we don't
+             * want to add anything */
+            break;
+        }
+    }
+    return 0;
+}
 
 #define QEMU_SERIAL_PARAM_ACCEPTED_CHARS \
   "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
@@ -1434,6 +1454,7 @@ qemuBuildDriveDevStr(virDomainDiskDefPtr disk,
         break;
     case VIR_DOMAIN_DISK_BUS_VIRTIO:
         virBufferAddLit(&opt, "virtio-blk-pci");
+        qemuBuildIoEventFdStr(&opt, disk->ioeventfd, qemuCaps);
         qemuBuildDeviceAddressStr(&opt, &disk->info, qemuCaps);
         break;
     case VIR_DOMAIN_DISK_BUS_USB:
@@ -1656,6 +1677,8 @@ qemuBuildNicDevStr(virDomainNetDefPtr net,
             goto error;
         }
     }
+    if(usingVirtio)
+        qemuBuildIoEventFdStr(&buf, net->driver.virtio.ioeventfd, qemuCaps);
     if (vlan == -1)
         virBufferVSprintf(&buf, ",netdev=host%s", net->info.alias);
     else
diff --git a/tests/qemuhelptest.c b/tests/qemuhelptest.c
index c86c578..776acf5 100644
--- a/tests/qemuhelptest.c
+++ b/tests/qemuhelptest.c
@@ -490,7 +490,8 @@ mymain(int argc, char **argv)
             QEMU_CAPS_CCID_PASSTHRU,
             QEMU_CAPS_CHARDEV_SPICEVMC,
             QEMU_CAPS_DEVICE_QXL_VGA,
-            QEMU_CAPS_VIRTIO_TX_ALG);
+            QEMU_CAPS_VIRTIO_TX_ALG,
+            QEMU_CAPS_VIRTIO_IOEVENTFD);
 
     return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
 }
-- 
1.7.4.4




More information about the libvir-list mailing list