Add unsafe cache mode support for disk driver

QEMU 0.13 introduced cache=unsafe for -drive, this patch exposes
it in the libvirt layer.

  * Introduced a new QEMU capability flag ($prefix_CACHE_UNSAFE),
    as even if $prefix_CACHE_V2 is set, we can't know if unsafe
    is supported.

  * Improved the reliability of qemu cache type detection.
This commit is contained in:
Oskari Saarenmaa 2011-09-22 22:33:47 +03:00 committed by Eric Blake
parent cb61009236
commit f887334dcf
13 changed files with 84 additions and 13 deletions

View File

@ -996,10 +996,15 @@
<li> <li>
The optional <code>cache</code> attribute controls the The optional <code>cache</code> attribute controls the
cache mechanism, possible values are "default", "none", cache mechanism, possible values are "default", "none",
"writethrough", "writeback", and "directsync". "directsync" "writethrough", "writeback", "directsync" (like
is like "writethrough", but it bypasses the host page "writethrough", but it bypasses the host page cache) and
cache. "unsafe" (host may cache all disk io, and sync requests from
<span class="since">Since 0.6.0</span> guest are ignored).
<span class="since">
Since 0.6.0,
"directsync" since 0.9.5,
"unsafe" since 0.9.7
</span>
</li> </li>
<li> <li>
The optional <code>error_policy</code> attribute controls The optional <code>error_policy</code> attribute controls

View File

@ -848,6 +848,7 @@
<value>writeback</value> <value>writeback</value>
<value>writethrough</value> <value>writethrough</value>
<value>directsync</value> <value>directsync</value>
<value>unsafe</value>
</choice> </choice>
</attribute> </attribute>
</define> </define>

View File

@ -164,7 +164,8 @@ VIR_ENUM_IMPL(virDomainDiskCache, VIR_DOMAIN_DISK_CACHE_LAST,
"none", "none",
"writethrough", "writethrough",
"writeback", "writeback",
"directsync") "directsync",
"unsafe")
VIR_ENUM_IMPL(virDomainDiskErrorPolicy, VIR_DOMAIN_DISK_ERROR_POLICY_LAST, VIR_ENUM_IMPL(virDomainDiskErrorPolicy, VIR_DOMAIN_DISK_ERROR_POLICY_LAST,
"default", "default",

View File

@ -192,6 +192,7 @@ enum virDomainDiskCache {
VIR_DOMAIN_DISK_CACHE_WRITETHRU, VIR_DOMAIN_DISK_CACHE_WRITETHRU,
VIR_DOMAIN_DISK_CACHE_WRITEBACK, VIR_DOMAIN_DISK_CACHE_WRITEBACK,
VIR_DOMAIN_DISK_CACHE_DIRECTSYNC, VIR_DOMAIN_DISK_CACHE_DIRECTSYNC,
VIR_DOMAIN_DISK_CACHE_UNSAFE,
VIR_DOMAIN_DISK_CACHE_LAST VIR_DOMAIN_DISK_CACHE_LAST
}; };

View File

@ -137,6 +137,8 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST,
"usb-redir", "usb-redir",
"usb-hub", "usb-hub",
"no-shutdown", "no-shutdown",
"cache-unsafe", /* 75 */
); );
struct qemu_feature_flags { struct qemu_feature_flags {
@ -912,12 +914,16 @@ qemuCapsComputeCmdFlags(const char *help,
else if (strstr(help, "-domid")) else if (strstr(help, "-domid"))
qemuCapsSet(flags, QEMU_CAPS_DOMID); qemuCapsSet(flags, QEMU_CAPS_DOMID);
if (strstr(help, "-drive")) { if (strstr(help, "-drive")) {
const char *cache = strstr(help, "cache=");
qemuCapsSet(flags, QEMU_CAPS_DRIVE); qemuCapsSet(flags, QEMU_CAPS_DRIVE);
if (strstr(help, "cache=") && if (cache && (p = strchr(cache, ']'))) {
!strstr(help, "cache=on|off")) { if (memmem(cache, p - cache, "on|off", sizeof("on|off") - 1) == NULL)
qemuCapsSet(flags, QEMU_CAPS_DRIVE_CACHE_V2); qemuCapsSet(flags, QEMU_CAPS_DRIVE_CACHE_V2);
if (strstr(help, "directsync")) if (memmem(cache, p - cache, "directsync", sizeof("directsync") - 1))
qemuCapsSet(flags, QEMU_CAPS_DRIVE_CACHE_DIRECTSYNC); qemuCapsSet(flags, QEMU_CAPS_DRIVE_CACHE_DIRECTSYNC);
if (memmem(cache, p - cache, "unsafe", sizeof("unsafe") - 1))
qemuCapsSet(flags, QEMU_CAPS_DRIVE_CACHE_UNSAFE);
} }
if (strstr(help, "format=")) if (strstr(help, "format="))
qemuCapsSet(flags, QEMU_CAPS_DRIVE_FORMAT); qemuCapsSet(flags, QEMU_CAPS_DRIVE_FORMAT);

View File

@ -112,6 +112,8 @@ enum qemuCapsFlags {
QEMU_CAPS_USB_HUB = 73, /* -device usb-hub */ QEMU_CAPS_USB_HUB = 73, /* -device usb-hub */
QEMU_CAPS_NO_SHUTDOWN = 74, /* usable -no-shutdown */ QEMU_CAPS_NO_SHUTDOWN = 74, /* usable -no-shutdown */
QEMU_CAPS_DRIVE_CACHE_UNSAFE = 75, /* Is cache=unsafe supported? */
QEMU_CAPS_LAST, /* this must always be the last item */ QEMU_CAPS_LAST, /* this must always be the last item */
}; };

View File

@ -66,14 +66,16 @@ VIR_ENUM_IMPL(qemuDiskCacheV1, VIR_DOMAIN_DISK_CACHE_LAST,
"off", "off",
"off", /* writethrough not supported, so for safety, disable */ "off", /* writethrough not supported, so for safety, disable */
"on", /* Old 'on' was equivalent to 'writeback' */ "on", /* Old 'on' was equivalent to 'writeback' */
"off"); /* directsync not supported, for safety, disable */ "off", /* directsync not supported, for safety, disable */
"off"); /* unsafe not supported, for safety, disable */
VIR_ENUM_IMPL(qemuDiskCacheV2, VIR_DOMAIN_DISK_CACHE_LAST, VIR_ENUM_IMPL(qemuDiskCacheV2, VIR_DOMAIN_DISK_CACHE_LAST,
"default", "default",
"none", "none",
"writethrough", "writethrough",
"writeback", "writeback",
"directsync"); "directsync",
"unsafe");
VIR_ENUM_DECL(qemuVideo) VIR_ENUM_DECL(qemuVideo)
@ -1622,6 +1624,12 @@ qemuBuildDriveStr(virDomainDiskDefPtr disk,
_("disk cache mode 'directsync' is not " _("disk cache mode 'directsync' is not "
"supported by this QEMU")); "supported by this QEMU"));
goto error; goto error;
} else if (disk->cachemode == VIR_DOMAIN_DISK_CACHE_UNSAFE &&
!qemuCapsGet(qemuCaps, QEMU_CAPS_DRIVE_CACHE_UNSAFE)) {
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("disk cache mode 'unsafe' is not "
"supported by this QEMU"));
goto error;
} }
} else { } else {
mode = qemuDiskCacheV1TypeToString(disk->cachemode); mode = qemuDiskCacheV1TypeToString(disk->cachemode);
@ -5536,6 +5544,8 @@ qemuParseCommandLineDisk(virCapsPtr caps,
def->cachemode = VIR_DOMAIN_DISK_CACHE_WRITETHRU; def->cachemode = VIR_DOMAIN_DISK_CACHE_WRITETHRU;
else if (STREQ(values[i], "directsync")) else if (STREQ(values[i], "directsync"))
def->cachemode = VIR_DOMAIN_DISK_CACHE_DIRECTSYNC; def->cachemode = VIR_DOMAIN_DISK_CACHE_DIRECTSYNC;
else if (STREQ(values[i], "unsafe"))
def->cachemode = VIR_DOMAIN_DISK_CACHE_UNSAFE;
} else if (STREQ(keywords[i], "werror") || } else if (STREQ(keywords[i], "werror") ||
STREQ(keywords[i], "rerror")) { STREQ(keywords[i], "rerror")) {
if (STREQ(values[i], "stop")) if (STREQ(values[i], "stop"))

View File

@ -169,6 +169,7 @@ mymain(void)
DO_TEST("disk-drive-cache-v2-wb"); DO_TEST("disk-drive-cache-v2-wb");
DO_TEST("disk-drive-cache-v2-none"); DO_TEST("disk-drive-cache-v2-none");
DO_TEST("disk-drive-cache-directsync"); DO_TEST("disk-drive-cache-directsync");
DO_TEST("disk-drive-cache-unsafe");
DO_TEST("disk-drive-network-nbd"); DO_TEST("disk-drive-network-nbd");
DO_TEST("disk-drive-network-rbd"); DO_TEST("disk-drive-network-rbd");
DO_TEST("disk-drive-network-sheepdog"); DO_TEST("disk-drive-network-sheepdog");

View File

@ -165,6 +165,7 @@ mymain(void)
QEMU_CAPS_MIGRATE_QEMU_TCP, QEMU_CAPS_MIGRATE_QEMU_TCP,
QEMU_CAPS_MIGRATE_QEMU_EXEC, QEMU_CAPS_MIGRATE_QEMU_EXEC,
QEMU_CAPS_DRIVE_CACHE_V2, QEMU_CAPS_DRIVE_CACHE_V2,
QEMU_CAPS_DRIVE_CACHE_UNSAFE,
QEMU_CAPS_KVM, QEMU_CAPS_KVM,
QEMU_CAPS_DRIVE_FORMAT, QEMU_CAPS_DRIVE_FORMAT,
QEMU_CAPS_DRIVE_SERIAL, QEMU_CAPS_DRIVE_SERIAL,
@ -408,6 +409,7 @@ mymain(void)
QEMU_CAPS_MIGRATE_QEMU_TCP, QEMU_CAPS_MIGRATE_QEMU_TCP,
QEMU_CAPS_MIGRATE_QEMU_EXEC, QEMU_CAPS_MIGRATE_QEMU_EXEC,
QEMU_CAPS_DRIVE_CACHE_V2, QEMU_CAPS_DRIVE_CACHE_V2,
QEMU_CAPS_DRIVE_CACHE_UNSAFE,
QEMU_CAPS_KVM, QEMU_CAPS_KVM,
QEMU_CAPS_DRIVE_FORMAT, QEMU_CAPS_DRIVE_FORMAT,
QEMU_CAPS_DRIVE_SERIAL, QEMU_CAPS_DRIVE_SERIAL,
@ -460,6 +462,7 @@ mymain(void)
QEMU_CAPS_MIGRATE_QEMU_TCP, QEMU_CAPS_MIGRATE_QEMU_TCP,
QEMU_CAPS_MIGRATE_QEMU_EXEC, QEMU_CAPS_MIGRATE_QEMU_EXEC,
QEMU_CAPS_DRIVE_CACHE_V2, QEMU_CAPS_DRIVE_CACHE_V2,
QEMU_CAPS_DRIVE_CACHE_UNSAFE,
QEMU_CAPS_KVM, QEMU_CAPS_KVM,
QEMU_CAPS_DRIVE_FORMAT, QEMU_CAPS_DRIVE_FORMAT,
QEMU_CAPS_DRIVE_SERIAL, QEMU_CAPS_DRIVE_SERIAL,

View File

@ -0,0 +1,5 @@
LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M \
pc -m 214 -smp 1 -nographic -monitor unix:/tmp/test-monitor,server,nowait \
-no-acpi -boot c -drive file=/dev/HostVG/QEMUGuest1,if=ide,bus=0,unit=0,\
format=qcow2,cache=unsafe -drive file=/dev/HostVG/QEMUGuest2,if=ide,\
media=cdrom,bus=1,unit=0,format=raw -net none -serial none -parallel none -usb

View File

@ -0,0 +1,33 @@
<domain type='qemu'>
<name>QEMUGuest1</name>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory>219136</memory>
<currentMemory>219136</currentMemory>
<vcpu>1</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
</os>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>/usr/bin/qemu</emulator>
<disk type='block' device='disk'>
<driver name='qemu' type='qcow2' cache='unsafe'/>
<source dev='/dev/HostVG/QEMUGuest1'/>
<target dev='hda' bus='ide'/>
<address type='drive' controller='0' bus='0' unit='0'/>
</disk>
<disk type='block' device='cdrom'>
<driver name='qemu' type='raw'/>
<source dev='/dev/HostVG/QEMUGuest2'/>
<target dev='hdc' bus='ide'/>
<readonly/>
<address type='drive' controller='0' bus='1' unit='0'/>
</disk>
<controller type='ide' index='0'/>
<memballoon model='virtio'/>
</devices>
</domain>

View File

@ -341,6 +341,9 @@ mymain(void)
DO_TEST("disk-drive-cache-directsync", false, DO_TEST("disk-drive-cache-directsync", false,
QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_CACHE_V2, QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_CACHE_V2,
QEMU_CAPS_DRIVE_CACHE_DIRECTSYNC, QEMU_CAPS_DRIVE_FORMAT); QEMU_CAPS_DRIVE_CACHE_DIRECTSYNC, QEMU_CAPS_DRIVE_FORMAT);
DO_TEST("disk-drive-cache-unsafe", false,
QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_CACHE_V2,
QEMU_CAPS_DRIVE_CACHE_UNSAFE, QEMU_CAPS_DRIVE_FORMAT);
DO_TEST("disk-drive-network-nbd", false, DO_TEST("disk-drive-network-nbd", false,
QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_FORMAT); QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_FORMAT);
DO_TEST("disk-drive-network-rbd", false, DO_TEST("disk-drive-network-rbd", false,

View File

@ -1195,8 +1195,8 @@ floppy device; consider using B<update-device> for this usage instead.
I<mode> can specify the two specific mode I<readonly> or I<shareable>. I<mode> can specify the two specific mode I<readonly> or I<shareable>.
I<persistent> indicates the changes will affect the next boot of the domain. I<persistent> indicates the changes will affect the next boot of the domain.
I<sourcetype> can indicate the type of source (block|file) I<sourcetype> can indicate the type of source (block|file)
I<cache> can be one of "default", "none", "writethrough", "writeback", or I<cache> can be one of "default", "none", "writethrough", "writeback",
"directsync". "directsync" or "unsafe".
I<serial> is the serial of disk device. I<shareable> indicates the disk device I<serial> is the serial of disk device. I<shareable> indicates the disk device
is shareable between domains. is shareable between domains.
I<address> is the address of disk device in the form of pci:domain.bus.slot.function, I<address> is the address of disk device in the form of pci:domain.bus.slot.function,