From 3ea661deeabadc3c114dfb6f662b9fd17d714a01 Mon Sep 17 00:00:00 2001 From: Peter Krempa Date: Mon, 7 Jul 2014 12:56:23 +0200 Subject: [PATCH] qemu: refactor qemuDomainGetBlockInfo to work with remote storage 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 | 86 ++++++++++++++++++++++++--------------- src/util/virstoragefile.c | 2 +- src/util/virstoragefile.h | 3 ++ 4 files changed, 59 insertions(+), 33 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 18d5f28c4a..6d7bf41952 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 fe76d5568b..23f3f089a8 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; + disk = vm->def->disks[idx]; + + 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 0b8715d04c..466da0ae90 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 89ecc1e187..18d3a753b1 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,