Create a helper function that can be reused for gathering block
info from virDomainListGetStats.
* src/qemu/qemu_driver.c (qemuDomainGetBlockInfo): Split guts...
(qemuStorageLimitsRefresh): ...into new helper function.
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
src/qemu/qemu_driver.c | 207 ++++++++++++++++++++++++++-----------------------
1 file changed, 110 insertions(+), 97 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 5e9c133..13ec903 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -10992,65 +10992,23 @@ qemuDomainMemoryPeek(virDomainPtr dom,
}
+/* Refresh the capacity and allocation limits of a given storage
+ * source. Assumes that the caller has already obtained a domain
+ * job. */
static int
-qemuDomainGetBlockInfo(virDomainPtr dom,
- const char *path,
- virDomainBlockInfoPtr info,
- unsigned int flags)
+qemuStorageLimitsRefresh(virQEMUDriverPtr driver, virQEMUDriverConfigPtr cfg,
+ virDomainObjPtr vm, virDomainDiskDefPtr disk,
+ virStorageSourcePtr src)
{
- virQEMUDriverPtr driver = dom->conn->privateData;
- virDomainObjPtr vm;
int ret = -1;
int fd = -1;
off_t end;
virStorageSourcePtr meta = NULL;
- virDomainDiskDefPtr disk = NULL;
struct stat sb;
- int idx;
- int format;
- bool activeFail = false;
- virQEMUDriverConfigPtr cfg = NULL;
+ int format = src->format;
char *buf = NULL;
ssize_t len;
- virCheckFlags(0, -1);
-
- if (!(vm = qemuDomObjFromDomain(dom)))
- return -1;
-
- cfg = virQEMUDriverGetConfig(driver);
-
- if (virDomainGetBlockInfoEnsureACL(dom->conn, vm->def) < 0)
- goto cleanup;
-
- if (!path || path[0] == '\0') {
- virReportError(VIR_ERR_INVALID_ARG, "%s", _("NULL or empty
path"));
- goto cleanup;
- }
-
- /* Technically, we only need a job if we are going to query the
- * monitor, which is only for active domains that are using
- * non-raw block devices. But it is easier to share code if we
- * always grab a job; furthermore, grabbing the job ensures that
- * hot-plug won't change disk behind our backs. */
- if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
- goto cleanup;
-
- /* Check the path belongs to this domain. */
- if ((idx = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
- virReportError(VIR_ERR_INVALID_ARG,
- _("invalid path %s not assigned to domain"), path);
- goto endjob;
- }
-
- disk = vm->def->disks[idx];
- if (virStorageSourceIsEmpty(disk->src)) {
- virReportError(VIR_ERR_INVALID_ARG,
- _("disk '%s' does not currently have a source
assigned"),
- path);
- goto endjob;
- }
-
/* FIXME: For an offline domain, we always want to check current
* on-disk statistics (as users have been known to change offline
* images behind our backs). For a running domain, however, it
@@ -11071,51 +11029,51 @@ qemuDomainGetBlockInfo(virDomainPtr dom,
* punching holes), and physical size of a non-raw file can
* change.
*/
- if (virStorageSourceIsLocalStorage(disk->src)) {
+ if (virStorageSourceIsLocalStorage(src)) {
/* Yes, this is a mild TOCTTOU race, but if someone is
* changing files in the background behind libvirt's back,
* they deserve bogus information. */
- if (stat(disk->src->path, &sb) < 0) {
+ if (stat(src->path, &sb) < 0) {
virReportSystemError(errno,
- _("cannot stat file '%s'"),
disk->src->path);
- goto endjob;
+ _("cannot stat file '%s'"),
src->path);
+ goto cleanup;
}
- if ((fd = qemuOpenFile(driver, vm, disk->src->path, O_RDONLY,
+ if ((fd = qemuOpenFile(driver, vm, src->path, O_RDONLY,
NULL, NULL)) == -1)
- goto endjob;
+ goto cleanup;
if ((len = virFileReadHeaderFD(fd, VIR_STORAGE_MAX_HEADER, &buf)) < 0) {
virReportSystemError(errno, _("cannot read header '%s'"),
- disk->src->path);
- goto endjob;
+ src->path);
+ goto cleanup;
}
} else {
- if (virStorageFileInitAs(disk->src, cfg->user, cfg->group) < 0)
- goto endjob;
+ if (virStorageFileInitAs(src, cfg->user, cfg->group) < 0)
+ goto cleanup;
- if (virStorageFileStat(disk->src, &sb) < 0) {
+ if (virStorageFileStat(src, &sb) < 0) {
virReportSystemError(errno, _("failed to stat remote file
'%s'"),
- NULLSTR(disk->src->path));
- goto endjob;
+ NULLSTR(src->path));
+ goto cleanup;
}
- if ((len = virStorageFileReadHeader(disk->src, VIR_STORAGE_MAX_HEADER,
+ if ((len = virStorageFileReadHeader(src, VIR_STORAGE_MAX_HEADER,
&buf)) < 0)
- goto endjob;
+ goto cleanup;
}
/* Get info for normal formats */
if (S_ISREG(sb.st_mode) || fd == -1) {
#ifndef WIN32
- disk->src->allocation = (unsigned long long)sb.st_blocks *
+ src->allocation = (unsigned long long)sb.st_blocks *
(unsigned long long)DEV_BSIZE;
#else
- disk->src->allocation = sb.st_size;
+ src->allocation = sb.st_size;
#endif
/* Allocation tracks when the file is sparse, physical is the
* last offset of the file. */
- disk->src->physical = sb.st_size;
+ src->physical = sb.st_size;
} else {
/* NB. Because we configure with AC_SYS_LARGEFILE, off_t
* should be 64 bits on all platforms. For block devices, we
@@ -11127,11 +11085,11 @@ qemuDomainGetBlockInfo(virDomainPtr dom,
end = lseek(fd, 0, SEEK_END);
if (end == (off_t)-1) {
virReportSystemError(errno,
- _("failed to seek to end of %s"), path);
- goto endjob;
+ _("failed to seek to end of %s"),
src->path);
+ goto cleanup;
}
- disk->src->physical = end;
- disk->src->allocation = end;
+ src->physical = end;
+ src->allocation = end;
}
/* Raw files: capacity is physical size. For all other files: if
@@ -11141,29 +11099,96 @@ qemuDomainGetBlockInfo(virDomainPtr dom,
if (!cfg->allowDiskFormatProbing) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("no disk format for %s and probing is disabled"),
- path);
- goto endjob;
+ src->path);
+ goto cleanup;
}
- if ((format = virStorageFileProbeFormatFromBuf(disk->src->path,
+ if ((format = virStorageFileProbeFormatFromBuf(src->path,
buf, len)) < 0)
- goto endjob;
+ goto cleanup;
}
if (format == VIR_STORAGE_FILE_RAW) {
- disk->src->capacity = disk->src->physical;
- } else if (!(meta = virStorageFileGetMetadataFromBuf(disk->src->path, buf,
+ src->capacity = src->physical;
+ } else if (!(meta = virStorageFileGetMetadataFromBuf(src->path, buf,
len, format, NULL))) {
- goto endjob;
- disk->src->capacity = meta->capacity ? meta->capacity
- : disk->src->physical;
+ goto cleanup;
+ src->capacity = meta->capacity ? meta->capacity : src->physical;
}
/* If guest is not using raw disk format and on a block device,
* then query highest allocated extent from QEMU
*/
- if (virStorageSourceGetActualType(disk->src) == VIR_STORAGE_TYPE_BLOCK &&
+ if (virStorageSourceGetActualType(src) == VIR_STORAGE_TYPE_BLOCK &&
format != VIR_STORAGE_FILE_RAW &&
- S_ISBLK(sb.st_mode)) {
+ S_ISBLK(sb.st_mode))
+ src->allocation = 0;
+
+ ret = 0;
+ cleanup:
+ VIR_FREE(buf);
+ virStorageSourceFree(meta);
+ VIR_FORCE_CLOSE(fd);
+ virStorageFileDeinit(src);
+ return ret;
+}
+
+
+static int
+qemuDomainGetBlockInfo(virDomainPtr dom,
+ const char *path,
+ virDomainBlockInfoPtr info,
+ unsigned int flags)
+{
+ virQEMUDriverPtr driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ int ret = -1;
+ virDomainDiskDefPtr disk = NULL;
+ int idx;
+ bool activeFail = false;
+ virQEMUDriverConfigPtr cfg = NULL;
+
+ virCheckFlags(0, -1);
+
+ if (!(vm = qemuDomObjFromDomain(dom)))
+ return -1;
+
+ cfg = virQEMUDriverGetConfig(driver);
+
+ if (virDomainGetBlockInfoEnsureACL(dom->conn, vm->def) < 0)
+ goto cleanup;
+
+ if (!path || path[0] == '\0') {
+ virReportError(VIR_ERR_INVALID_ARG, "%s", _("NULL or empty
path"));
+ goto cleanup;
+ }
+
+ /* Technically, we only need a job if we are going to query the
+ * monitor, which is only for active domains that are using
+ * non-raw block devices. But it is easier to share code if we
+ * always grab a job; furthermore, grabbing the job ensures that
+ * hot-plug won't change disk behind our backs. */
+ if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
+ goto cleanup;
+
+ /* Check the path belongs to this domain. */
+ if ((idx = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("invalid path %s not assigned to domain"), path);
+ goto endjob;
+ }
+
+ disk = vm->def->disks[idx];
+ if (virStorageSourceIsEmpty(disk->src)) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("disk '%s' does not currently have a source
assigned"),
+ path);
+ goto endjob;
+ }
+
+ if ((ret = qemuStorageLimitsRefresh(driver, cfg, vm, disk, disk->src)) < 0)
+ goto endjob;
+
+ if (!disk->src->allocation) {
qemuDomainObjPrivatePtr priv = vm->privateData;
/* If the guest is not running, then success/failure return
@@ -11171,7 +11196,6 @@ qemuDomainGetBlockInfo(virDomainPtr dom,
*/
if (!virDomainObjIsActive(vm)) {
activeFail = true;
- ret = 0;
goto endjob;
}
@@ -11180,27 +11204,16 @@ qemuDomainGetBlockInfo(virDomainPtr dom,
disk->info.alias,
&disk->src->allocation);
qemuDomainObjExitMonitor(driver, vm);
-
- } else {
- ret = 0;
}
- if (ret == 0) {
- info->capacity = disk->src->capacity;
- info->allocation = disk->src->allocation;
- info->physical = disk->src->physical;
- }
+ info->capacity = disk->src->capacity;
+ info->allocation = disk->src->allocation;
+ info->physical = disk->src->physical;
endjob:
if (!qemuDomainObjEndJob(driver, vm))
vm = NULL;
cleanup:
- VIR_FREE(buf);
- virStorageSourceFree(meta);
- VIR_FORCE_CLOSE(fd);
- if (disk)
- virStorageFileDeinit(disk->src);
-
/* If we failed to get data from a domain because it's inactive and
* it's not a persistent domain, then force failure.
*/
--
1.9.3