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.
This commit is contained in:
Osier Yang 2013-05-14 20:44:54 +08:00
parent f60bd7c7a7
commit a7c4202cdd
12 changed files with 112 additions and 0 deletions

View File

@ -1702,6 +1702,14 @@
network. By default copy-on-read is off. network. By default copy-on-read is off.
<span class='since'>Since 0.9.10 (QEMU and KVM only)</span> <span class='since'>Since 0.9.10 (QEMU and KVM only)</span>
</li> </li>
<li>
The optional <code>discard</code> 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).
<span class='since'>Since 1.0.6 (QEMU and KVM only)</span>
</li>
</ul> </ul>
</dd> </dd>
<dt><code>boot</code></dt> <dt><code>boot</code></dt>

View File

@ -1311,6 +1311,9 @@
<optional> <optional>
<ref name="copy_on_read"/> <ref name="copy_on_read"/>
</optional> </optional>
<optional>
<ref name="discard"/>
</optional>
<empty/> <empty/>
</element> </element>
</define> </define>
@ -1407,6 +1410,14 @@
</choice> </choice>
</attribute> </attribute>
</define> </define>
<define name="discard">
<attribute name='discard'>
<choice>
<value>on</value>
<value>off</value>
</choice>
</attribute>
</define>
<define name="controller"> <define name="controller">
<element name="controller"> <element name="controller">
<attribute name="index"> <attribute name="index">

View File

@ -743,6 +743,10 @@ VIR_ENUM_IMPL(virDomainTPMModel, VIR_DOMAIN_TPM_MODEL_LAST,
VIR_ENUM_IMPL(virDomainTPMBackend, VIR_DOMAIN_TPM_TYPE_LAST, VIR_ENUM_IMPL(virDomainTPMBackend, VIR_DOMAIN_TPM_TYPE_LAST,
"passthrough") "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_WRITE_FLAGS VIR_DOMAIN_XML_SECURE
#define VIR_DOMAIN_XML_READ_FLAGS VIR_DOMAIN_XML_INACTIVE #define VIR_DOMAIN_XML_READ_FLAGS VIR_DOMAIN_XML_INACTIVE
@ -4534,6 +4538,7 @@ virDomainDiskDefParseXML(virDomainXMLOptionPtr xmlopt,
char *wwn = NULL; char *wwn = NULL;
char *vendor = NULL; char *vendor = NULL;
char *product = NULL; char *product = NULL;
char *discard = NULL;
int expected_secret_usage = -1; int expected_secret_usage = -1;
int auth_secret_usage = -1; int auth_secret_usage = -1;
@ -4761,6 +4766,7 @@ virDomainDiskDefParseXML(virDomainXMLOptionPtr xmlopt,
ioeventfd = virXMLPropString(cur, "ioeventfd"); ioeventfd = virXMLPropString(cur, "ioeventfd");
event_idx = virXMLPropString(cur, "event_idx"); event_idx = virXMLPropString(cur, "event_idx");
copy_on_read = virXMLPropString(cur, "copy_on_read"); copy_on_read = virXMLPropString(cur, "copy_on_read");
discard = virXMLPropString(cur, "discard");
} else if (!mirror && xmlStrEqual(cur->name, BAD_CAST "mirror") && } else if (!mirror && xmlStrEqual(cur->name, BAD_CAST "mirror") &&
!(flags & VIR_DOMAIN_XML_INACTIVE)) { !(flags & VIR_DOMAIN_XML_INACTIVE)) {
char *ready; char *ready;
@ -5207,6 +5213,14 @@ virDomainDiskDefParseXML(virDomainXMLOptionPtr xmlopt,
def->copy_on_read = cor; 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 (devaddr) {
if (virDomainParseLegacyDeviceAddress(devaddr, if (virDomainParseLegacyDeviceAddress(devaddr,
&def->info.addr.pci) < 0) { &def->info.addr.pci) < 0) {
@ -5326,6 +5340,7 @@ cleanup:
VIR_FREE(ioeventfd); VIR_FREE(ioeventfd);
VIR_FREE(event_idx); VIR_FREE(event_idx);
VIR_FREE(copy_on_read); VIR_FREE(copy_on_read);
VIR_FREE(discard);
VIR_FREE(devaddr); VIR_FREE(devaddr);
VIR_FREE(serial); VIR_FREE(serial);
virStorageEncryptionFree(encryption); virStorageEncryptionFree(encryption);
@ -13658,6 +13673,7 @@ virDomainDiskDefFormat(virBufferPtr buf,
const char *event_idx = virDomainVirtioEventIdxTypeToString(def->event_idx); const char *event_idx = virDomainVirtioEventIdxTypeToString(def->event_idx);
const char *copy_on_read = virDomainVirtioEventIdxTypeToString(def->copy_on_read); const char *copy_on_read = virDomainVirtioEventIdxTypeToString(def->copy_on_read);
const char *sgio = virDomainDiskSGIOTypeToString(def->sgio); const char *sgio = virDomainDiskSGIOTypeToString(def->sgio);
const char *discard = virDomainDiskDiscardTypeToString(def->discard);
char uuidstr[VIR_UUID_STRING_BUFLEN]; char uuidstr[VIR_UUID_STRING_BUFLEN];
@ -13734,6 +13750,8 @@ virDomainDiskDefFormat(virBufferPtr buf,
virBufferAsprintf(buf, " event_idx='%s'", event_idx); virBufferAsprintf(buf, " event_idx='%s'", event_idx);
if (def->copy_on_read) if (def->copy_on_read)
virBufferAsprintf(buf, " copy_on_read='%s'", copy_on_read); virBufferAsprintf(buf, " copy_on_read='%s'", copy_on_read);
if (def->discard)
virBufferAsprintf(buf, " discard='%s'", discard);
virBufferAddLit(buf, "/>\n"); virBufferAddLit(buf, "/>\n");
} }

View File

@ -625,6 +625,14 @@ enum virDomainDiskSGIO {
VIR_DOMAIN_DISK_SGIO_LAST 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; typedef struct _virDomainBlockIoTuneInfo virDomainBlockIoTuneInfo;
struct _virDomainBlockIoTuneInfo { struct _virDomainBlockIoTuneInfo {
unsigned long long total_bytes_sec; unsigned long long total_bytes_sec;
@ -707,6 +715,7 @@ struct _virDomainDiskDef {
bool rawio_specified; bool rawio_specified;
int rawio; /* no = 0, yes = 1 */ int rawio; /* no = 0, yes = 1 */
int sgio; /* enum virDomainDiskSGIO */ int sgio; /* enum virDomainDiskSGIO */
int discard; /* enum virDomainDiskDiscard */
size_t nseclabels; size_t nseclabels;
virSecurityDeviceLabelDefPtr *seclabels; virSecurityDeviceLabelDefPtr *seclabels;
@ -2464,6 +2473,7 @@ VIR_ENUM_DECL(virDomainDiskIo)
VIR_ENUM_DECL(virDomainDiskSecretType) VIR_ENUM_DECL(virDomainDiskSecretType)
VIR_ENUM_DECL(virDomainDiskSGIO) VIR_ENUM_DECL(virDomainDiskSGIO)
VIR_ENUM_DECL(virDomainDiskTray) VIR_ENUM_DECL(virDomainDiskTray)
VIR_ENUM_DECL(virDomainDiskDiscard)
VIR_ENUM_DECL(virDomainIoEventFd) VIR_ENUM_DECL(virDomainIoEventFd)
VIR_ENUM_DECL(virDomainVirtioEventIdx) VIR_ENUM_DECL(virDomainVirtioEventIdx)
VIR_ENUM_DECL(virDomainDiskCopyOnRead) VIR_ENUM_DECL(virDomainDiskCopyOnRead)

View File

@ -142,6 +142,7 @@ virDomainDiskDefFree;
virDomainDiskDefGenSecurityLabelDef; virDomainDiskDefGenSecurityLabelDef;
virDomainDiskDefGetSecurityLabelDef; virDomainDiskDefGetSecurityLabelDef;
virDomainDiskDeviceTypeToString; virDomainDiskDeviceTypeToString;
virDomainDiskDiscardTypeToString;
virDomainDiskErrorPolicyTypeFromString; virDomainDiskErrorPolicyTypeFromString;
virDomainDiskErrorPolicyTypeToString; virDomainDiskErrorPolicyTypeToString;
virDomainDiskFindByBusAndDst; virDomainDiskFindByBusAndDst;

View File

@ -229,6 +229,7 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST,
"scsi-generic.bootindex", /* 145 */ "scsi-generic.bootindex", /* 145 */
"mem-merge", "mem-merge",
"vnc-websocket", "vnc-websocket",
"drive-discard",
); );
struct _virQEMUCaps { struct _virQEMUCaps {
@ -2244,6 +2245,7 @@ struct virQEMUCapsCommandLineProps {
static struct virQEMUCapsCommandLineProps virQEMUCapsCommandLine[] = { static struct virQEMUCapsCommandLineProps virQEMUCapsCommandLine[] = {
{ "machine", "mem-merge", QEMU_CAPS_MEM_MERGE }, { "machine", "mem-merge", QEMU_CAPS_MEM_MERGE },
{ "drive", "discard", QEMU_CAPS_DRIVE_DISCARD },
}; };
static int static int

View File

@ -186,6 +186,7 @@ enum virQEMUCapsFlags {
QEMU_CAPS_DEVICE_SCSI_GENERIC_BOOTINDEX = 145, /* -device scsi-generic.bootindex */ QEMU_CAPS_DEVICE_SCSI_GENERIC_BOOTINDEX = 145, /* -device scsi-generic.bootindex */
QEMU_CAPS_MEM_MERGE = 146, /* -machine mem-merge */ QEMU_CAPS_MEM_MERGE = 146, /* -machine mem-merge */
QEMU_CAPS_VNC_WEBSOCKET = 147, /* -vnc x:y,websocket */ 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 */ QEMU_CAPS_LAST, /* this must always be the last item */
}; };

View File

@ -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)) { if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_MONITOR_JSON)) {
const char *wpolicy = NULL, *rpolicy = NULL; const char *wpolicy = NULL, *rpolicy = NULL;

View File

@ -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

View File

@ -0,0 +1,37 @@
<domain type='qemu'>
<name>test</name>
<uuid>92d7a226-cfae-425b-a6d3-00bbf9ec5c9e</uuid>
<memory unit='KiB'>1048576</memory>
<currentMemory unit='KiB'>1048576</currentMemory>
<vcpu placement='static'>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' discard='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' discard='off'/>
<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' target='0' unit='0'/>
</disk>
<controller type='usb' index='0'/>
<controller type='ide' index='0'/>
<controller type='pci' index='0' model='pci-root'/>
<memballoon model='virtio'/>
</devices>
</domain>

View File

@ -585,6 +585,9 @@ mymain(void)
QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_COPY_ON_READ, QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_COPY_ON_READ,
QEMU_CAPS_VIRTIO_TX_ALG, QEMU_CAPS_DEVICE, QEMU_CAPS_VIRTIO_TX_ALG, QEMU_CAPS_DEVICE,
QEMU_CAPS_VIRTIO_BLK_SCSI, QEMU_CAPS_VIRTIO_BLK_SG_IO); 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", DO_TEST("disk-snapshot",
QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_CACHE_V2, QEMU_CAPS_DRIVE_FORMAT); QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_CACHE_V2, QEMU_CAPS_DRIVE_FORMAT);
DO_TEST("event_idx", DO_TEST("event_idx",

View File

@ -261,6 +261,8 @@ mymain(void)
DO_TEST("disk-scsi-disk-vpd"); DO_TEST("disk-scsi-disk-vpd");
DO_TEST("disk-source-pool"); DO_TEST("disk-source-pool");
DO_TEST("disk-drive-discard");
DO_TEST("virtio-rng-random"); DO_TEST("virtio-rng-random");
DO_TEST("virtio-rng-egd"); DO_TEST("virtio-rng-egd");