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@xxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list