|
|
c401cc |
From 7968d4cc1504076a3b28601ef896909961d06444 Mon Sep 17 00:00:00 2001
|
|
|
c401cc |
Message-Id: <7968d4cc1504076a3b28601ef896909961d06444@dist-git>
|
|
|
c401cc |
From: John Ferlan <jferlan@redhat.com>
|
|
|
c401cc |
Date: Fri, 14 Feb 2014 16:33:32 -0500
|
|
|
c401cc |
Subject: [PATCH] Block info query: Add check for transient domain
|
|
|
c401cc |
|
|
|
c401cc |
https://bugzilla.redhat.com/show_bug.cgi?id=1065531
|
|
|
c401cc |
|
|
|
c401cc |
Currently the qemuDomainGetBlockInfo will return allocation == physical
|
|
|
c401cc |
for most backing stores. For a qcow2 block backed device it's possible
|
|
|
c401cc |
to return the highest lv extent allocated from qemu for an active guest.
|
|
|
c401cc |
That is a value where allocation != physical and one would hope be less.
|
|
|
c401cc |
However, if the guest is not running, then the code falls back to returning
|
|
|
c401cc |
allocation == physical. This turns out to be problematic for rhev which
|
|
|
c401cc |
monitors the size of the backing store. During a migration, before the
|
|
|
c401cc |
VM has been started on the target and while it is deemed inactive on the
|
|
|
c401cc |
source, there's a small window of time where the allocation is returned
|
|
|
c401cc |
as physical triggering the code to extend the file unnecessarily.
|
|
|
c401cc |
|
|
|
c401cc |
Since rhev uses transient domains and this is edge condition for a transient
|
|
|
c401cc |
domain, rather than returning good status and allocation == physical when
|
|
|
c401cc |
this "window of opportunity" exists, this patch will check for a transient
|
|
|
c401cc |
(or non persistent) domain and return a failure to the caller rather than
|
|
|
c401cc |
returning the defaults. For a persistent domain, the defaults will be
|
|
|
c401cc |
returned. The description for the virDomainGetBlockInfo has been updated
|
|
|
c401cc |
to describe the phenomena.
|
|
|
c401cc |
|
|
|
c401cc |
(cherry picked from commit 46a0737e13cec06a6b7cb0afdcdd200c2bec317f)
|
|
|
c401cc |
Signed-off-by: John Ferlan <jferlan@redhat.com>
|
|
|
c401cc |
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
|
|
c401cc |
---
|
|
|
c401cc |
include/libvirt/libvirt.h.in | 8 ++++---
|
|
|
c401cc |
src/libvirt.c | 53 ++++++++++++++++++++++++++++++++++++++++++++
|
|
|
c401cc |
src/qemu/qemu_driver.c | 29 +++++++++++++++++++-----
|
|
|
c401cc |
3 files changed, 82 insertions(+), 8 deletions(-)
|
|
|
c401cc |
|
|
|
c401cc |
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
|
|
|
c401cc |
index 1bc6624..91d89ec 100644
|
|
|
c401cc |
--- a/include/libvirt/libvirt.h.in
|
|
|
c401cc |
+++ b/include/libvirt/libvirt.h.in
|
|
|
c401cc |
@@ -2079,7 +2079,8 @@ int virDomainBlockResize (virDomainPtr dom,
|
|
|
c401cc |
|
|
|
c401cc |
/** virDomainBlockInfo:
|
|
|
c401cc |
*
|
|
|
c401cc |
- * This struct provides information about the size of a block device backing store
|
|
|
c401cc |
+ * This struct provides information about the size of a block device
|
|
|
c401cc |
+ * backing store
|
|
|
c401cc |
*
|
|
|
c401cc |
* Examples:
|
|
|
c401cc |
*
|
|
|
c401cc |
@@ -2092,11 +2093,12 @@ int virDomainBlockResize (virDomainPtr dom,
|
|
|
c401cc |
*
|
|
|
c401cc |
* - qcow2 file in filesystem
|
|
|
c401cc |
* * capacity: logical size from qcow2 header
|
|
|
c401cc |
- * * allocation, physical: logical size of the file / highest qcow extent (identical)
|
|
|
c401cc |
+ * * allocation, physical: logical size of the file /
|
|
|
c401cc |
+ * highest qcow extent (identical)
|
|
|
c401cc |
*
|
|
|
c401cc |
* - qcow2 file in a block device
|
|
|
c401cc |
* * capacity: logical size from qcow2 header
|
|
|
c401cc |
- * * allocation: highest qcow extent written
|
|
|
c401cc |
+ * * allocation: highest qcow extent written for an active domain
|
|
|
c401cc |
* * physical: size of the block device container
|
|
|
c401cc |
*/
|
|
|
c401cc |
typedef struct _virDomainBlockInfo virDomainBlockInfo;
|
|
|
c401cc |
diff --git a/src/libvirt.c b/src/libvirt.c
|
|
|
c401cc |
index 61cae03..af94326 100644
|
|
|
c401cc |
--- a/src/libvirt.c
|
|
|
c401cc |
+++ b/src/libvirt.c
|
|
|
c401cc |
@@ -9028,6 +9028,59 @@ error:
|
|
|
c401cc |
* can be found by calling virDomainGetXMLDesc() and inspecting
|
|
|
c401cc |
* elements within //domain/devices/disk.
|
|
|
c401cc |
*
|
|
|
c401cc |
+ * For QEMU domains, the allocation and physical virDomainBlockInfo
|
|
|
c401cc |
+ * values returned will generally be the same, except when using a
|
|
|
c401cc |
+ * non raw, block backing device, such as qcow2 for an active domain.
|
|
|
c401cc |
+ * When the persistent domain is not active, QEMU will return the
|
|
|
c401cc |
+ * default which is the same value for allocation and physical.
|
|
|
c401cc |
+ *
|
|
|
c401cc |
+ * Active QEMU domains can return an allocation value which is more
|
|
|
c401cc |
+ * representative of the currently used blocks by the device compared
|
|
|
c401cc |
+ * to the physical size of the device. Applications can use/monitor
|
|
|
c401cc |
+ * the allocation value with the understanding that if the domain
|
|
|
c401cc |
+ * becomes inactive during an attempt to get the value, the default
|
|
|
c401cc |
+ * values will be returned. Thus, the application should check
|
|
|
c401cc |
+ * after the call for the domain being inactive if the values are
|
|
|
c401cc |
+ * the same. Optionally, the application could be watching for a
|
|
|
c401cc |
+ * shutdown event and then ignore any values received afterwards.
|
|
|
c401cc |
+ * This can be an issue when a domain is being migrated and the
|
|
|
c401cc |
+ * exact timing of the domain being made inactive and check of
|
|
|
c401cc |
+ * the allocation value results the default being returned. For
|
|
|
c401cc |
+ * a transient domain in the similar situation, this call will return
|
|
|
c401cc |
+ * -1 and an error message indicating the "domain is not running".
|
|
|
c401cc |
+ *
|
|
|
c401cc |
+ * The following is some pseudo code illustrating the call sequence:
|
|
|
c401cc |
+ *
|
|
|
c401cc |
+ * ...
|
|
|
c401cc |
+ * virDomainPtr dom;
|
|
|
c401cc |
+ * virDomainBlockInfo info;
|
|
|
c401cc |
+ * char *device;
|
|
|
c401cc |
+ * ...
|
|
|
c401cc |
+ * // Either get a list of all domains or a specific domain
|
|
|
c401cc |
+ * // via a virDomainLookupBy*() call.
|
|
|
c401cc |
+ * //
|
|
|
c401cc |
+ * // It's also required to fill in the device pointer, but that's
|
|
|
c401cc |
+ * // specific to the implementation. For the purposes of this example
|
|
|
c401cc |
+ * // a qcow2 backed device name string would need to be provided.
|
|
|
c401cc |
+ * ...
|
|
|
c401cc |
+ * // If the following call is made on a persistent domain with a
|
|
|
c401cc |
+ * // qcow2 block backed block device, then it's possible the returned
|
|
|
c401cc |
+ * // allocation equals the physical value. In that case, the domain
|
|
|
c401cc |
+ * // that may have been active prior to calling has become inactive,
|
|
|
c401cc |
+ * // such as is the case during a domain migration. Thus once we
|
|
|
c401cc |
+ * // get data returned, check for active domain when the values are
|
|
|
c401cc |
+ * // the same.
|
|
|
c401cc |
+ * if (virDomainGetBlockInfo(dom, device, &info, 0) < 0)
|
|
|
c401cc |
+ * goto failure;
|
|
|
c401cc |
+ * if (info.allocation == info.physical) {
|
|
|
c401cc |
+ * // If the domain is no longer active,
|
|
|
c401cc |
+ * // then the defaults are being returned.
|
|
|
c401cc |
+ * if (!virDomainIsActive())
|
|
|
c401cc |
+ * goto ignore_return;
|
|
|
c401cc |
+ * }
|
|
|
c401cc |
+ * // Do something with the allocation and physical values
|
|
|
c401cc |
+ * ...
|
|
|
c401cc |
+ *
|
|
|
c401cc |
* Returns 0 in case of success and -1 in case of failure.
|
|
|
c401cc |
*/
|
|
|
c401cc |
int
|
|
|
c401cc |
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
|
|
|
c401cc |
index ee622a2..a7da257 100644
|
|
|
c401cc |
--- a/src/qemu/qemu_driver.c
|
|
|
c401cc |
+++ b/src/qemu/qemu_driver.c
|
|
|
c401cc |
@@ -10084,6 +10084,7 @@ qemuDomainGetBlockInfo(virDomainPtr dom,
|
|
|
c401cc |
struct stat sb;
|
|
|
c401cc |
int idx;
|
|
|
c401cc |
int format;
|
|
|
c401cc |
+ int activeFail = false;
|
|
|
c401cc |
virQEMUDriverConfigPtr cfg = NULL;
|
|
|
c401cc |
char *alias = NULL;
|
|
|
c401cc |
|
|
|
c401cc |
@@ -10183,15 +10184,23 @@ qemuDomainGetBlockInfo(virDomainPtr dom,
|
|
|
c401cc |
/* Set default value .. */
|
|
|
c401cc |
info->allocation = info->physical;
|
|
|
c401cc |
|
|
|
c401cc |
- /* ..but if guest is running & not using raw
|
|
|
c401cc |
- disk format and on a block device, then query
|
|
|
c401cc |
- highest allocated extent from QEMU */
|
|
|
c401cc |
+ /* ..but if guest is not using raw disk format and on a block device,
|
|
|
c401cc |
+ * then query highest allocated extent from QEMU
|
|
|
c401cc |
+ */
|
|
|
c401cc |
if (disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK &&
|
|
|
c401cc |
format != VIR_STORAGE_FILE_RAW &&
|
|
|
c401cc |
- S_ISBLK(sb.st_mode) &&
|
|
|
c401cc |
- virDomainObjIsActive(vm)) {
|
|
|
c401cc |
+ S_ISBLK(sb.st_mode)) {
|
|
|
c401cc |
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
c401cc |
|
|
|
c401cc |
+ /* If the guest is not running, then success/failure return
|
|
|
c401cc |
+ * depends on whether domain is persistent
|
|
|
c401cc |
+ */
|
|
|
c401cc |
+ if (!virDomainObjIsActive(vm)) {
|
|
|
c401cc |
+ activeFail = true;
|
|
|
c401cc |
+ ret = 0;
|
|
|
c401cc |
+ goto cleanup;
|
|
|
c401cc |
+ }
|
|
|
c401cc |
+
|
|
|
c401cc |
if (VIR_STRDUP(alias, disk->info.alias) < 0)
|
|
|
c401cc |
goto cleanup;
|
|
|
c401cc |
|
|
|
c401cc |
@@ -10205,6 +10214,7 @@ qemuDomainGetBlockInfo(virDomainPtr dom,
|
|
|
c401cc |
&info->allocation);
|
|
|
c401cc |
qemuDomainObjExitMonitor(driver, vm);
|
|
|
c401cc |
} else {
|
|
|
c401cc |
+ activeFail = true;
|
|
|
c401cc |
ret = 0;
|
|
|
c401cc |
}
|
|
|
c401cc |
|
|
|
c401cc |
@@ -10218,6 +10228,15 @@ cleanup:
|
|
|
c401cc |
VIR_FREE(alias);
|
|
|
c401cc |
virStorageFileFreeMetadata(meta);
|
|
|
c401cc |
VIR_FORCE_CLOSE(fd);
|
|
|
c401cc |
+
|
|
|
c401cc |
+ /* If we failed to get data from a domain because it's inactive and
|
|
|
c401cc |
+ * it's not a persistent domain, then force failure.
|
|
|
c401cc |
+ */
|
|
|
c401cc |
+ if (activeFail && vm && !vm->persistent) {
|
|
|
c401cc |
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
|
c401cc |
+ _("domain is not running"));
|
|
|
c401cc |
+ ret = -1;
|
|
|
c401cc |
+ }
|
|
|
c401cc |
if (vm)
|
|
|
c401cc |
virObjectUnlock(vm);
|
|
|
c401cc |
virObjectUnref(cfg);
|
|
|
c401cc |
--
|
|
|
c401cc |
1.9.0
|
|
|
c401cc |
|