From a7c4202cdd12208dcd107fde3b79b2420d863370 Mon Sep 17 00:00:00 2001 From: Osier Yang Date: Tue, 14 May 2013 20:44:54 +0800 Subject: [PATCH] qemu: Support discard for disk QEMU introduced "discard" option for drive since commit a9384aff53, <...> @var{discard} is one of "ignore" (or "off") or "unmap" (or "on") and controls whether @dfn{discard} (also known as @dfn{trim} or @dfn{unmap}) requests are ignored or passed to the filesystem. Some machine types may not support discard requests. This patch exposes the support in libvirt. QEMU supported "discard" for "-drive" since v1.5.0-rc0: % git tag --contains a9384aff53 contains v1.5.0-rc0 v1.5.0-rc1 So this only detects the capability bit using virQEMUCapsProbeQMPCommandLine. --- docs/formatdomain.html.in | 8 ++++ docs/schemas/domaincommon.rng | 11 ++++++ src/conf/domain_conf.c | 18 +++++++++ src/conf/domain_conf.h | 10 +++++ src/libvirt_private.syms | 1 + src/qemu/qemu_capabilities.c | 2 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 11 ++++++ .../qemuxml2argv-disk-drive-discard.args | 8 ++++ .../qemuxml2argv-disk-drive-discard.xml | 37 +++++++++++++++++++ tests/qemuxml2argvtest.c | 3 ++ tests/qemuxml2xmltest.c | 2 + 12 files changed, 112 insertions(+) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-drive-discard.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-drive-discard.xml diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index b118b49d1a..e4f9a92cf6 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -1702,6 +1702,14 @@ network. By default copy-on-read is off. Since 0.9.10 (QEMU and KVM only) +
  • + The optional discard attribute controls whether + to discard (also known as "trim" or "unmap") requests are + ignored or passed to the filesystem. The value can be either + "on" (allow the discard request to be passed) or "off" (ingore + the discard request). + Since 1.0.6 (QEMU and KVM only) +
  • boot
    diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 414fd727db..361794e9b1 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -1311,6 +1311,9 @@ + + + @@ -1406,6 +1409,14 @@ off + + + + + on + off + + diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 91f3b3168f..472b4b406e 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -743,6 +743,10 @@ VIR_ENUM_IMPL(virDomainTPMModel, VIR_DOMAIN_TPM_MODEL_LAST, VIR_ENUM_IMPL(virDomainTPMBackend, VIR_DOMAIN_TPM_TYPE_LAST, "passthrough") +VIR_ENUM_IMPL(virDomainDiskDiscard, VIR_DOMAIN_DISK_DISCARD_LAST, + "default", + "on", + "off") #define VIR_DOMAIN_XML_WRITE_FLAGS VIR_DOMAIN_XML_SECURE #define VIR_DOMAIN_XML_READ_FLAGS VIR_DOMAIN_XML_INACTIVE @@ -4534,6 +4538,7 @@ virDomainDiskDefParseXML(virDomainXMLOptionPtr xmlopt, char *wwn = NULL; char *vendor = NULL; char *product = NULL; + char *discard = NULL; int expected_secret_usage = -1; int auth_secret_usage = -1; @@ -4761,6 +4766,7 @@ virDomainDiskDefParseXML(virDomainXMLOptionPtr xmlopt, ioeventfd = virXMLPropString(cur, "ioeventfd"); event_idx = virXMLPropString(cur, "event_idx"); copy_on_read = virXMLPropString(cur, "copy_on_read"); + discard = virXMLPropString(cur, "discard"); } else if (!mirror && xmlStrEqual(cur->name, BAD_CAST "mirror") && !(flags & VIR_DOMAIN_XML_INACTIVE)) { char *ready; @@ -5207,6 +5213,14 @@ virDomainDiskDefParseXML(virDomainXMLOptionPtr xmlopt, def->copy_on_read = cor; } + if (discard) { + if ((def->discard = virDomainDiskDiscardTypeFromString(discard)) <= 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("unknown disk discard mode '%s'"), discard); + goto error; + } + } + if (devaddr) { if (virDomainParseLegacyDeviceAddress(devaddr, &def->info.addr.pci) < 0) { @@ -5326,6 +5340,7 @@ cleanup: VIR_FREE(ioeventfd); VIR_FREE(event_idx); VIR_FREE(copy_on_read); + VIR_FREE(discard); VIR_FREE(devaddr); VIR_FREE(serial); virStorageEncryptionFree(encryption); @@ -13658,6 +13673,7 @@ virDomainDiskDefFormat(virBufferPtr buf, const char *event_idx = virDomainVirtioEventIdxTypeToString(def->event_idx); const char *copy_on_read = virDomainVirtioEventIdxTypeToString(def->copy_on_read); const char *sgio = virDomainDiskSGIOTypeToString(def->sgio); + const char *discard = virDomainDiskDiscardTypeToString(def->discard); char uuidstr[VIR_UUID_STRING_BUFLEN]; @@ -13734,6 +13750,8 @@ virDomainDiskDefFormat(virBufferPtr buf, virBufferAsprintf(buf, " event_idx='%s'", event_idx); if (def->copy_on_read) virBufferAsprintf(buf, " copy_on_read='%s'", copy_on_read); + if (def->discard) + virBufferAsprintf(buf, " discard='%s'", discard); virBufferAddLit(buf, "/>\n"); } diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 8d4b868393..c176a4cd3a 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -625,6 +625,14 @@ enum virDomainDiskSGIO { VIR_DOMAIN_DISK_SGIO_LAST }; +enum virDomainDiskDiscard { + VIR_DOMAIN_DISK_DISCARD_DEFAULT = 0, + VIR_DOMAIN_DISK_DISCARD_ON, + VIR_DOMAIN_DISK_DISCARD_OFF, + + VIR_DOMAIN_DISK_DISCARD_LAST +}; + typedef struct _virDomainBlockIoTuneInfo virDomainBlockIoTuneInfo; struct _virDomainBlockIoTuneInfo { unsigned long long total_bytes_sec; @@ -707,6 +715,7 @@ struct _virDomainDiskDef { bool rawio_specified; int rawio; /* no = 0, yes = 1 */ int sgio; /* enum virDomainDiskSGIO */ + int discard; /* enum virDomainDiskDiscard */ size_t nseclabels; virSecurityDeviceLabelDefPtr *seclabels; @@ -2464,6 +2473,7 @@ VIR_ENUM_DECL(virDomainDiskIo) VIR_ENUM_DECL(virDomainDiskSecretType) VIR_ENUM_DECL(virDomainDiskSGIO) VIR_ENUM_DECL(virDomainDiskTray) +VIR_ENUM_DECL(virDomainDiskDiscard) VIR_ENUM_DECL(virDomainIoEventFd) VIR_ENUM_DECL(virDomainVirtioEventIdx) VIR_ENUM_DECL(virDomainDiskCopyOnRead) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index cdd0b41baa..cc734da21e 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -142,6 +142,7 @@ virDomainDiskDefFree; virDomainDiskDefGenSecurityLabelDef; virDomainDiskDefGetSecurityLabelDef; virDomainDiskDeviceTypeToString; +virDomainDiskDiscardTypeToString; virDomainDiskErrorPolicyTypeFromString; virDomainDiskErrorPolicyTypeToString; virDomainDiskFindByBusAndDst; diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 49cb7a6645..488cbfe94e 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -229,6 +229,7 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST, "scsi-generic.bootindex", /* 145 */ "mem-merge", "vnc-websocket", + "drive-discard", ); struct _virQEMUCaps { @@ -2244,6 +2245,7 @@ struct virQEMUCapsCommandLineProps { static struct virQEMUCapsCommandLineProps virQEMUCapsCommandLine[] = { { "machine", "mem-merge", QEMU_CAPS_MEM_MERGE }, + { "drive", "discard", QEMU_CAPS_DRIVE_DISCARD }, }; static int diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 609f3f9390..173ca777c0 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -186,6 +186,7 @@ enum virQEMUCapsFlags { QEMU_CAPS_DEVICE_SCSI_GENERIC_BOOTINDEX = 145, /* -device scsi-generic.bootindex */ QEMU_CAPS_MEM_MERGE = 146, /* -machine mem-merge */ QEMU_CAPS_VNC_WEBSOCKET = 147, /* -vnc x:y,websocket */ + QEMU_CAPS_DRIVE_DISCARD = 148, /* -drive discard=off(ignore)|on(unmap) */ 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 58eab54a28..5b95c07fa5 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -3274,6 +3274,17 @@ qemuBuildDriveStr(virConnectPtr conn ATTRIBUTE_UNUSED, } } + if (disk->discard) { + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_DISCARD)) { + virBufferAsprintf(&opt, ",discard=%s", + virDomainDiskDiscardTypeToString(disk->discard)); + } else { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("discard is not supported by this QEMU binary")); + goto error; + } + } + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_MONITOR_JSON)) { const char *wpolicy = NULL, *rpolicy = NULL; diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-discard.args b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-discard.args new file mode 100644 index 0000000000..02e2ddb151 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-discard.args @@ -0,0 +1,8 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test \ +/usr/bin/qemu -S -M pc-0.13 -m 1024 -smp 1 -nographic -nodefaults \ +-monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot dc -usb \ +-drive file=/var/lib/libvirt/images/f14.img,if=none,id=drive-virtio-disk0,discard=on \ +-device virtio-blk-pci,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,discard=off \ +-device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-discard.xml b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-discard.xml new file mode 100644 index 0000000000..a6a8135a67 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-discard.xml @@ -0,0 +1,37 @@ + + test + 92d7a226-cfae-425b-a6d3-00bbf9ec5c9e + 1048576 + 1048576 + 1 + + hvm + + + + + + destroy + restart + restart + + /usr/bin/qemu + + + + +
    + + + + + + +
    + + + + + + + diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index d0b49b0fe4..ac31d2a980 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -585,6 +585,9 @@ mymain(void) 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-drive-discard", + QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_DISCARD, + QEMU_CAPS_DEVICE); DO_TEST("disk-snapshot", QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_CACHE_V2, QEMU_CAPS_DRIVE_FORMAT); DO_TEST("event_idx", diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 92b7383fbe..148a05aab0 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -261,6 +261,8 @@ mymain(void) DO_TEST("disk-scsi-disk-vpd"); DO_TEST("disk-source-pool"); + DO_TEST("disk-drive-discard"); + DO_TEST("virtio-rng-random"); DO_TEST("virtio-rng-egd");