The qemu block info function relied on working with local storage. Break this assumption by adding support for remote volumes. Unfortunately we still need to take a hybrid approach as some of the operations require a filedescriptor. Previously you'd get: $ virsh domblkinfo gl vda error: cannot stat file '/img10': Bad file descriptor Now you get some stats: $ virsh domblkinfo gl vda Capacity: 10485760 Allocation: 197120 Physical: 197120 Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1110198 --- src/libvirt_private.syms | 1 + src/qemu/qemu_driver.c | 84 ++++++++++++++++++++++++++++++----------------- src/util/virstoragefile.c | 2 +- src/util/virstoragefile.h | 3 ++ 4 files changed, 58 insertions(+), 32 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 18d5f28..6d7bf41 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1910,6 +1910,7 @@ virStorageFileGetSCSIKey; virStorageFileIsClusterFS; virStorageFileParseChainIndex; virStorageFileProbeFormat; +virStorageFileProbeFormatFromBuf; virStorageFileResize; virStorageIsFile; virStorageNetHostDefClear; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index fe76d55..23f3f08 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -10334,11 +10334,13 @@ qemuDomainGetBlockInfo(virDomainPtr dom, int activeFail = false; virQEMUDriverConfigPtr cfg = NULL; char *alias = NULL; + char *buf = NULL; + ssize_t len; virCheckFlags(0, -1); if (!(vm = qemuDomObjFromDomain(dom))) - goto cleanup; + return -1; cfg = virQEMUDriverGetConfig(driver); @@ -10346,8 +10348,7 @@ qemuDomainGetBlockInfo(virDomainPtr dom, goto cleanup; if (!path || path[0] == '\0') { - virReportError(VIR_ERR_INVALID_ARG, - "%s", _("NULL or empty path")); + virReportError(VIR_ERR_INVALID_ARG, "%s", _("NULL or empty path")); goto cleanup; } @@ -10357,48 +10358,68 @@ qemuDomainGetBlockInfo(virDomainPtr dom, _("invalid path %s not assigned to domain"), path); goto cleanup; } + disk = vm->def->disks[idx]; - path = virDomainDiskGetSource(disk); - if (!path) { - virReportError(VIR_ERR_INVALID_ARG, - _("disk %s does not currently have a source assigned"), - path); - goto cleanup; - } - /* The path is correct, now try to open it and get its size. */ - fd = qemuOpenFile(driver, vm, path, O_RDONLY, NULL, NULL); - if (fd == -1) - goto cleanup; + if (virStorageSourceIsLocalStorage(disk->src)) { + if (!disk->src->path) { + virReportError(VIR_ERR_INVALID_ARG, + _("disk '%s' does not currently have a source assigned"), + path); + goto cleanup; + } + + if ((fd = qemuOpenFile(driver, vm, path, O_RDONLY, NULL, NULL)) == -1) + goto cleanup; + + if (fstat(fd, &sb) < 0) { + virReportSystemError(errno, + _("cannot stat file '%s'"), disk->src->path); + goto cleanup; + } + + if ((len = virFileReadHeaderFD(fd, VIR_STORAGE_MAX_HEADER, &buf)) < 0) { + virReportSystemError(errno, _("cannot read header '%s'"), + disk->src->path); + goto cleanup; + } + } else { + if (virStorageFileInitAs(disk->src, cfg->user, cfg->group) < 0) + goto cleanup; + + if ((len = virStorageFileReadHeader(disk->src, VIR_STORAGE_MAX_HEADER, + &buf)) < 0) + goto cleanup; + + if (virStorageFileStat(disk->src, &sb) < 0) { + virReportSystemError(errno, _("failed to stat remote file '%s'"), + NULLSTR(disk->src->path)); + goto cleanup; + } + } /* Probe for magic formats */ if (virDomainDiskGetFormat(disk)) { format = virDomainDiskGetFormat(disk); } else { - if (cfg->allowDiskFormatProbing) { - if ((format = virStorageFileProbeFormat(path, - cfg->user, - cfg->group)) < 0) - goto cleanup; - } else { + if (!cfg->allowDiskFormatProbing) { virReportError(VIR_ERR_INTERNAL_ERROR, _("no disk format for %s and probing is disabled"), path); goto cleanup; } + + if ((format = virStorageFileProbeFormatFromBuf(disk->src->path, + buf, len)) < 0) + goto cleanup; } - if (!(meta = virStorageFileGetMetadataFromFD(path, fd, format, NULL))) + if (!(meta = virStorageFileGetMetadataFromBuf(disk->src->path, buf, len, + format, NULL))) goto cleanup; /* Get info for normal formats */ - if (fstat(fd, &sb) < 0) { - virReportSystemError(errno, - _("cannot stat file '%s'"), path); - goto cleanup; - } - - if (S_ISREG(sb.st_mode)) { + if (S_ISREG(sb.st_mode) || fd == -1) { #ifndef WIN32 info->physical = (unsigned long long)sb.st_blocks * (unsigned long long)DEV_BSIZE; @@ -10434,7 +10455,7 @@ qemuDomainGetBlockInfo(virDomainPtr dom, /* ..but if guest is not using raw disk format and on a block device, * then query highest allocated extent from QEMU */ - if (virDomainDiskGetType(disk) == VIR_STORAGE_TYPE_BLOCK && + if (virStorageSourceGetActualType(disk->src) == VIR_STORAGE_TYPE_BLOCK && format != VIR_STORAGE_FILE_RAW && S_ISBLK(sb.st_mode)) { qemuDomainObjPrivatePtr priv = vm->privateData; @@ -10475,6 +10496,8 @@ qemuDomainGetBlockInfo(virDomainPtr dom, VIR_FREE(alias); 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. @@ -10484,8 +10507,7 @@ qemuDomainGetBlockInfo(virDomainPtr dom, _("domain is not running")); ret = -1; } - if (vm) - virObjectUnlock(vm); + virObjectUnlock(vm); virObjectUnref(cfg); return ret; } diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c index 7ae4642..6789463 100644 --- a/src/util/virstoragefile.c +++ b/src/util/virstoragefile.c @@ -682,7 +682,7 @@ virStorageIsRelative(const char *backing) } -static int +int virStorageFileProbeFormatFromBuf(const char *path, char *buf, size_t buflen) diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h index 89ecc1e..18d3a75 100644 --- a/src/util/virstoragefile.h +++ b/src/util/virstoragefile.h @@ -276,6 +276,9 @@ struct _virStorageSource { # endif int virStorageFileProbeFormat(const char *path, uid_t uid, gid_t gid); +int virStorageFileProbeFormatFromBuf(const char *path, + char *buf, + size_t buflen); int virStorageFileGetMetadataInternal(virStorageSourcePtr meta, char *buf, -- 2.0.0 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list