From 73c0a148af5fc6b782f757fae4b7f94f9a514147 Mon Sep 17 00:00:00 2001 From: Laine Stump Date: Sat, 13 Aug 2011 02:32:45 -0400 Subject: [PATCH] qemu: support event_idx parameter for virtio disk and net devices 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 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. --- docs/formatdomain.html.in | 31 +++++++++- docs/schemas/domain.rng | 14 +++++ src/conf/domain_conf.c | 47 ++++++++++++++- src/conf/domain_conf.h | 11 ++++ src/libvirt_private.syms | 2 + src/qemu/qemu_capabilities.c | 6 ++ src/qemu/qemu_capabilities.h | 2 + src/qemu/qemu_command.c | 13 ++++- .../qemuxml2argv-event_idx.args | 11 ++++ .../qemuxml2argv-event_idx.xml | 57 +++++++++++++++++++ tests/qemuxml2argvtest.c | 5 ++ tests/qemuxml2xmltest.c | 1 + 12 files changed, 196 insertions(+), 4 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-event_idx.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-event_idx.xml 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 + + + + +
    + + + + + + +
    + + +
    + + + + + + + + + + + + + + + + + +