[libvirt] [PATCH v2] qemu: Support copy on read for disk

The new introduced optional attribute "copy_on_read</code> controls wether to copy read backing file into the image file. The value can be either "on" or "off". Copy-on-read avoids accessing the same backing file sectors repeatedly and is useful when the backing file is over a slow network. By default copy-on-read is off. --- docs/formatdomain.html.in | 9 ++++ docs/schemas/domaincommon.rng | 11 ++++ src/conf/domain_conf.c | 24 +++++++++- src/conf/domain_conf.h | 10 ++++ src/libvirt_private.syms | 2 + src/qemu/qemu_capabilities.c | 3 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 11 ++++ tests/qemuhelptest.c | 3 +- .../qemuxml2argv-disk-copy_on_read.args | 11 ++++ .../qemuxml2argv-disk-copy_on_read.xml | 50 ++++++++++++++++++++ tests/qemuxml2argvtest.c | 4 ++ 12 files changed, 137 insertions(+), 2 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-copy_on_read.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-copy_on_read.xml diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 42e23a1..3a42ebb 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -1202,6 +1202,15 @@ <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>copy_on_read</code> attribute controls + wether to copy read backing file into the image file. The + value can be either "on" or "off". + Copy-on-read avoids accessing the same backing file sectors + repeatedly and is useful when the backing file is over a slow + network. By default copy-on-read is off. + <span class='since'>Since 0.9.9 (QEMU and KVM only)</span> + </li> </ul> </dd> <dt><code>boot</code></dt> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index e93ae77..fdcbc28 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -958,6 +958,9 @@ <optional> <ref name="event_idx"/> </optional> + <optional> + <ref name="copy_on_read"/> + </optional> <empty/> </element> </define> @@ -1025,6 +1028,14 @@ </choice> </attribute> </define> + <define name="copy_on_read"> + <attribute name='copy_on_read'> + <choice> + <value>on</value> + <value>off</value> + </choice> + </attribute> + </define> <define name="controller"> <element name="controller"> <choice> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 180dd2b..c70faee 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -209,6 +209,11 @@ VIR_ENUM_IMPL(virDomainVirtioEventIdx, VIR_DOMAIN_VIRTIO_EVENT_IDX_LAST, "on", "off") +VIR_ENUM_IMPL(virDomainDiskCopyOnRead, VIR_DOMAIN_DISK_COPY_ON_READ_LAST, + "default", + "on", + "off") + VIR_ENUM_IMPL(virDomainDiskSnapshot, VIR_DOMAIN_DISK_SNAPSHOT_LAST, "default", "no", @@ -2783,6 +2788,7 @@ virDomainDiskDefParseXML(virCapsPtr caps, char *iotag = NULL; char *ioeventfd = NULL; char *event_idx = NULL; + char *copy_on_read = NULL; char *devaddr = NULL; virStorageEncryptionPtr encryption = NULL; char *serial = NULL; @@ -2911,6 +2917,7 @@ virDomainDiskDefParseXML(virCapsPtr caps, iotag = virXMLPropString(cur, "io"); ioeventfd = virXMLPropString(cur, "ioeventfd"); event_idx = virXMLPropString(cur, "event_idx"); + copy_on_read = virXMLPropString(cur, "copy_on_read"); } else if (xmlStrEqual(cur->name, BAD_CAST "auth")) { authUsername = virXMLPropString(cur, "username"); if (authUsername == NULL) { @@ -3226,6 +3233,17 @@ virDomainDiskDefParseXML(virCapsPtr caps, def->event_idx = idx; } + if (copy_on_read) { + int cor; + if ((cor = virDomainDiskCopyOnReadTypeFromString(copy_on_read)) <= 0) { + virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("unknown disk copy_on_read mode '%s'"), + copy_on_read); + goto error; + } + def->copy_on_read = cor; + } + if (devaddr) { if (virDomainParseLegacyDeviceAddress(devaddr, &def->info.addr.pci) < 0) { @@ -3319,6 +3337,7 @@ cleanup: VIR_FREE(iotag); VIR_FREE(ioeventfd); VIR_FREE(event_idx); + VIR_FREE(copy_on_read); VIR_FREE(devaddr); VIR_FREE(serial); virStorageEncryptionFree(encryption); @@ -9870,6 +9889,7 @@ virDomainDiskDefFormat(virBufferPtr buf, const char *iomode = virDomainDiskIoTypeToString(def->iomode); const char *ioeventfd = virDomainIoEventFdTypeToString(def->ioeventfd); const char *event_idx = virDomainVirtioEventIdxTypeToString(def->event_idx); + const char *copy_on_read = virDomainVirtioEventIdxTypeToString(def->copy_on_read); const char *startupPolicy = virDomainStartupPolicyTypeToString(def->startupPolicy); char uuidstr[VIR_UUID_STRING_BUFLEN]; @@ -9910,7 +9930,7 @@ virDomainDiskDefFormat(virBufferPtr buf, virBufferAddLit(buf, ">\n"); if (def->driverName || def->driverType || def->cachemode || - def->ioeventfd || def->event_idx) { + def->ioeventfd || def->event_idx || def->copy_on_read) { virBufferAddLit(buf, " <driver"); if (def->driverName) virBufferAsprintf(buf, " name='%s'", def->driverName); @@ -9928,6 +9948,8 @@ virDomainDiskDefFormat(virBufferPtr buf, virBufferAsprintf(buf, " ioeventfd='%s'", ioeventfd); if (def->event_idx) virBufferAsprintf(buf, " event_idx='%s'", event_idx); + if (def->copy_on_read) + virBufferAsprintf(buf, " copy_on_read='%s'", copy_on_read); virBufferAddLit(buf, "/>\n"); } diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 3d5d4f8..bac5a87 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -308,6 +308,14 @@ enum virDomainVirtioEventIdx { VIR_DOMAIN_VIRTIO_EVENT_IDX_LAST }; +enum virDomainDiskCopyOnRead { + VIR_DOMAIN_DISK_COPY_ON_READ_DEFAULT = 0, + VIR_DOMAIN_DISK_COPY_ON_READ_ON, + VIR_DOMAIN_DISK_COPY_ON_READ_OFF, + + VIR_DOMAIN_DISK_COPY_ON_READ_LAST +}; + enum virDomainDiskSnapshot { VIR_DOMAIN_DISK_SNAPSHOT_DEFAULT = 0, VIR_DOMAIN_DISK_SNAPSHOT_NO, @@ -384,6 +392,7 @@ struct _virDomainDiskDef { int iomode; int ioeventfd; int event_idx; + int copy_on_read; int snapshot; /* enum virDomainDiskSnapshot */ int startupPolicy; /* enum virDomainStartupPolicy */ unsigned int readonly : 1; @@ -1969,6 +1978,7 @@ VIR_ENUM_DECL(virDomainDiskSecretType) VIR_ENUM_DECL(virDomainDiskSnapshot) VIR_ENUM_DECL(virDomainIoEventFd) VIR_ENUM_DECL(virDomainVirtioEventIdx) +VIR_ENUM_DECL(virDomainDiskCopyOnRead) VIR_ENUM_DECL(virDomainController) VIR_ENUM_DECL(virDomainControllerModelSCSI) VIR_ENUM_DECL(virDomainControllerModelUSB) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index ca4beb1..27a093c 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -290,6 +290,8 @@ virDomainDeviceTypeToString; virDomainDiskBusTypeToString; virDomainDiskCacheTypeFromString; virDomainDiskCacheTypeToString; +virDomainDiskCopyOnReadTypeFromString; +virDomainDiskCopyOnReadTypeToString; virDomainDiskDefAssignAddress; virDomainDiskDefForeachPath; virDomainDiskDefFree; diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 6842cfe..530bbb1 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -147,6 +147,7 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST, "virtio-blk-pci.scsi", "blk-sg-io", + "drive-copy-on-read", ); struct qemu_feature_flags { @@ -1026,6 +1027,8 @@ qemuCapsComputeCmdFlags(const char *help, qemuCapsSet(flags, QEMU_CAPS_DRIVE_READONLY); if (strstr(help, "aio=threads|native")) qemuCapsSet(flags, QEMU_CAPS_DRIVE_AIO); + if (strstr(help, "copy-on-read=on|off")) + qemuCapsSet(flags, QEMU_CAPS_DRIVE_COPY_ON_READ); } if ((p = strstr(help, "-vga")) && !strstr(help, "-std-vga")) { const char *nl = strstr(p, "\n"); diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index d47177c..ee9d5ab 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -120,6 +120,7 @@ enum qemuCapsFlags { QEMU_CAPS_VIRTIO_BLK_SCSI = 80, /* virtio-blk-pci.scsi */ QEMU_CAPS_VIRTIO_BLK_SG_IO = 81, /* support for SG_IO commands, reportedly added in 0.11 */ + QEMU_CAPS_DRIVE_COPY_ON_READ = 82, /* -drive copy-on-read */ 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 16ffb4c..ee51965 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1929,6 +1929,17 @@ qemuBuildDriveStr(virConnectPtr conn ATTRIBUTE_UNUSED, virBufferAddLit(&opt, ",cache=off"); } + if (disk->copy_on_read) { + if (qemuCapsGet(qemuCaps, QEMU_CAPS_DRIVE_COPY_ON_READ)) { + virBufferAsprintf(&opt, ",copy-on-read=%s", + virDomainDiskCopyOnReadTypeToString(disk->copy_on_read)); + } else { + qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("copy_on_read is not supported by this QEMU binary")); + goto error; + } + } + if (qemuCapsGet(qemuCaps, QEMU_CAPS_MONITOR_JSON)) { const char *wpolicy = NULL, *rpolicy = NULL; diff --git a/tests/qemuhelptest.c b/tests/qemuhelptest.c index 1ef0d9b..2b08af9 100644 --- a/tests/qemuhelptest.c +++ b/tests/qemuhelptest.c @@ -592,7 +592,8 @@ mymain(void) QEMU_CAPS_PCI_ROMBAR, QEMU_CAPS_NO_ACPI, QEMU_CAPS_VIRTIO_BLK_SCSI, - QEMU_CAPS_VIRTIO_BLK_SG_IO); + QEMU_CAPS_VIRTIO_BLK_SG_IO, + QEMU_CAPS_DRIVE_COPY_ON_READ); DO_TEST("qemu-1.0", 1000000, 0, 0, QEMU_CAPS_VNC_COLON, QEMU_CAPS_NO_REBOOT, diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-copy_on_read.args b/tests/qemuxml2argvdata/qemuxml2argv-disk-copy_on_read.args new file mode 100644 index 0000000..2ca586d --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-copy_on_read.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,copy-on-read=on \ +-device virtio-blk-pci,scsi=off,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,tx=bh,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-disk-copy_on_read.xml b/tests/qemuxml2argvdata/qemuxml2argv-disk-copy_on_read.xml new file mode 100644 index 0000000..433c641 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-copy_on_read.xml @@ -0,0 +1,50 @@ +<domain type='qemu'> + <name>test</name> + <memory>1048576</memory> + <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' copy_on_read='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> + <interface type='user'> + <mac address='52:54:00:e5:48:58'/> + <model type='virtio'/> + <driver name='vhost' txmode='iothread'/> + </interface> + <controller type='virtio-serial' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> + </controller> + <serial type='pty'> + <target port='0'/> + </serial> + <console type='pty'> + <target type='serial' port='0'/> + </console> + <graphics type='vnc' port='5091' autoport='no' listen='127.0.0.1'/> + <video> + <model type='vga' vram='9216' heads='1'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </video> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index d87654c..30bea37 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -439,6 +439,10 @@ mymain(void) QEMU_CAPS_DRIVE, QEMU_CAPS_VIRTIO_IOEVENTFD, QEMU_CAPS_VIRTIO_TX_ALG, QEMU_CAPS_DEVICE, QEMU_CAPS_VIRTIO_BLK_SCSI, QEMU_CAPS_VIRTIO_BLK_SG_IO); + DO_TEST("disk-copy_on_read", false, + QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_COPY_ON_READ, + QEMU_CAPS_VIRTIO_TX_ALG, QEMU_CAPS_DEVICE, + QEMU_CAPS_VIRTIO_BLK_SCSI, QEMU_CAPS_VIRTIO_BLK_SG_IO); DO_TEST("disk-snapshot", false, QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_CACHE_V2, QEMU_CAPS_DRIVE_FORMAT); DO_TEST("event_idx", false, -- 1.7.7.3

On 01/12/2012 03:13 AM, Osier Yang wrote:
The new introduced optional attribute "copy_on_read</code> controls wether to copy read backing file into the image file. The value can
s/wether/whether/
be either "on" or "off". Copy-on-read avoids accessing the same backing file sectors repeatedly and is useful when the backing file is over a slow network. By default copy-on-read is off. --- docs/formatdomain.html.in | 9 ++++ docs/schemas/domaincommon.rng | 11 ++++ src/conf/domain_conf.c | 24 +++++++++- src/conf/domain_conf.h | 10 ++++ src/libvirt_private.syms | 2 + src/qemu/qemu_capabilities.c | 3 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 11 ++++ tests/qemuhelptest.c | 3 +- .../qemuxml2argv-disk-copy_on_read.args | 11 ++++ .../qemuxml2argv-disk-copy_on_read.xml | 50 ++++++++++++++++++++ tests/qemuxml2argvtest.c | 4 ++ 12 files changed, 137 insertions(+), 2 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-copy_on_read.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-copy_on_read.xml
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 42e23a1..3a42ebb 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -1202,6 +1202,15 @@ <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>copy_on_read</code> attribute controls + wether to copy read backing file into the image file. The + value can be either "on" or "off". + Copy-on-read avoids accessing the same backing file sectors + repeatedly and is useful when the backing file is over a slow + network. By default copy-on-read is off. + <span class='since'>Since 0.9.9 (QEMU and KVM only)</span>
0.9.10
+++ b/docs/schemas/domaincommon.rng @@ -958,6 +958,9 @@ <optional> <ref name="event_idx"/> </optional> + <optional> + <ref name="copy_on_read"/> + </optional>
Your placement as an attribute of <driver> makes sense - the guest sees no difference in behavior, so this really is an option for just how the host behaves. Looks pretty clean. ACK with the minor doc nit fixed. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On 2012年01月13日 08:11, Eric Blake wrote:
On 01/12/2012 03:13 AM, Osier Yang wrote:
The new introduced optional attribute "copy_on_read</code> controls wether to copy read backing file into the image file. The value can
s/wether/whether/
be either "on" or "off". Copy-on-read avoids accessing the same backing file sectors repeatedly and is useful when the backing file is over a slow network. By default copy-on-read is off. --- docs/formatdomain.html.in | 9 ++++ docs/schemas/domaincommon.rng | 11 ++++ src/conf/domain_conf.c | 24 +++++++++- src/conf/domain_conf.h | 10 ++++ src/libvirt_private.syms | 2 + src/qemu/qemu_capabilities.c | 3 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 11 ++++ tests/qemuhelptest.c | 3 +- .../qemuxml2argv-disk-copy_on_read.args | 11 ++++ .../qemuxml2argv-disk-copy_on_read.xml | 50 ++++++++++++++++++++ tests/qemuxml2argvtest.c | 4 ++ 12 files changed, 137 insertions(+), 2 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-copy_on_read.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-copy_on_read.xml
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 42e23a1..3a42ebb 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -1202,6 +1202,15 @@ <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>copy_on_read</code> attribute controls + wether to copy read backing file into the image file. The + value can be either "on" or "off". + Copy-on-read avoids accessing the same backing file sectors + repeatedly and is useful when the backing file is over a slow + network. By default copy-on-read is off. +<span class='since'>Since 0.9.9 (QEMU and KVM only)</span>
0.9.10
+++ b/docs/schemas/domaincommon.rng @@ -958,6 +958,9 @@ <optional> <ref name="event_idx"/> </optional> +<optional> +<ref name="copy_on_read"/> +</optional>
Your placement as an attribute of<driver> makes sense - the guest sees no difference in behavior, so this really is an option for just how the host behaves.
Looks pretty clean. ACK with the minor doc nit fixed.
Thanks, Pushed. Osier
participants (2)
-
Eric Blake
-
Osier Yang