To avoid having the root of a backing chain present twice in the list we
need to invert the working of virStorageFileGetMetadataRecurse.
Until now the recursive worker created a new backing chain element from
the name and other information passed as arguments. This required us to
pass the data of the parend in a deconstructed way and the worker
created a new entry for the parent.
This patch converts this function so that it just fills in metadata
about the parent and creates a backing chain element from those. This
removes the duplication of the first element.
To avoid breaking the test suite, virstoragetest now calls a wrapper
that creates the parent structure explicitly and pre-fills it with the
test data with same function signature as previously used.
---
src/conf/domain_conf.c | 5 +-
src/qemu/qemu_domain.c | 12 ++-
src/qemu/qemu_driver.c | 6 +-
src/security/virt-aa-helper.c | 7 +-
src/util/virstoragefile.c | 193 ++++++++++++++++++++++--------------------
src/util/virstoragefile.h | 7 +-
tests/virstoragetest.c | 47 +++++++++-
7 files changed, 158 insertions(+), 119 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 69ca5e7..99b57ee 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -18564,9 +18564,8 @@ virDomainDiskDefForeachPath(virDomainDiskDefPtr disk,
if (iter(disk, path, 0, opaque) < 0)
goto cleanup;
- /* XXX: temporarily we need to select the second element of the backing
- * chain to start as the first is the copy of the disk itself. */
- tmp = disk->src.backingStore ? disk->src.backingStore->backingStore : NULL;
+
+ tmp = disk->src.backingStore;
while (tmp && virStorageIsFile(tmp->path)) {
if (!ignoreOpenFailure && tmp->backingStoreRaw &&
!tmp->backingStore) {
virReportError(VIR_ERR_INTERNAL_ERROR,
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 45ed872..bb9cb6b 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -2239,10 +2239,10 @@ qemuDiskChainCheckBroken(virDomainDiskDefPtr disk)
{
char *brokenFile = NULL;
- if (!virDomainDiskGetSource(disk) || !disk->src.backingStore)
+ if (!virDomainDiskGetSource(disk))
return 0;
- if (virStorageFileChainGetBroken(disk->src.backingStore, &brokenFile) < 0)
+ if (virStorageFileChainGetBroken(&disk->src, &brokenFile) < 0)
return -1;
if (brokenFile) {
@@ -2419,11 +2419,9 @@ qemuDomainDetermineDiskChain(virQEMUDriverPtr driver,
qemuDomainGetImageIds(cfg, vm, disk, &uid, &gid);
- disk->src.backingStore = virStorageFileGetMetadata(src,
- virDomainDiskGetFormat(disk),
- uid, gid,
- cfg->allowDiskFormatProbing);
- if (!disk->src.backingStore)
+ if (virStorageFileGetMetadata(&disk->src,
+ uid, gid,
+ cfg->allowDiskFormatProbing) < 0)
ret = -1;
cleanup:
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index c0094c1..7dd2b86 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -15134,7 +15134,7 @@ qemuDomainBlockCopy(virDomainObjPtr vm,
if ((flags & VIR_DOMAIN_BLOCK_REBASE_SHALLOW) &&
STREQ_NULLABLE(format, "raw") &&
- disk->src.backingStore->backingStore->path) {
+ disk->src.backingStore->path) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("disk '%s' has backing file, so raw shallow copy
"
"is not possible"),
@@ -15341,8 +15341,8 @@ qemuDomainBlockCommit(virDomainPtr dom, const char *path, const
char *base,
if (!top) {
top_canon = disk->src.path;
- top_meta = disk->src.backingStore;
- } else if (!(top_canon = virStorageFileChainLookup(disk->src.backingStore,
+ top_meta = &disk->src;
+ } else if (!(top_canon = virStorageFileChainLookup(&disk->src,
top, &top_meta,
&top_parent))) {
goto endjob;
diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c
index 1c89815..32fc04a 100644
--- a/src/security/virt-aa-helper.c
+++ b/src/security/virt-aa-helper.c
@@ -943,18 +943,15 @@ get_files(vahControl * ctl)
for (i = 0; i < ctl->def->ndisks; i++) {
virDomainDiskDefPtr disk = ctl->def->disks[i];
- const char *src = virDomainDiskGetSource(disk);
- if (!src)
+ if (!virDomainDiskGetSource(disk))
continue;
/* XXX - if we knew the qemu user:group here we could send it in
* so that the open could be re-tried as that user:group.
*/
if (!disk->src.backingStore) {
bool probe = ctl->allowDiskFormatProbing;
- disk->src.backingStore = virStorageFileGetMetadata(src,
-
virDomainDiskGetFormat(disk),
- -1, -1, probe);
+ virStorageFileGetMetadata(&disk->src, -1, -1, probe);
}
/* XXX passing ignoreOpenFailure = true to get back to the behavior
diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c
index 8d5ef2f..b2d8f62 100644
--- a/src/util/virstoragefile.c
+++ b/src/util/virstoragefile.c
@@ -1104,105 +1104,112 @@ virStorageFileGetMetadataFromFD(const char *path,
/* Recursive workhorse for virStorageFileGetMetadata. */
static int
-virStorageFileGetMetadataRecurse(const char *path, const char *canonPath,
- const char *directory,
- int format, uid_t uid, gid_t gid,
- bool allow_probe, virHashTablePtr cycle,
- virStorageSourcePtr meta)
+virStorageFileGetMetadataRecurse(virStorageSourcePtr src,
+ const char *canonPath,
+ uid_t uid, gid_t gid,
+ bool allow_probe,
+ virHashTablePtr cycle)
{
int fd;
int ret = -1;
+ virStorageSourcePtr backingStore = NULL;
int backingFormat;
- char *backingPath = NULL;
- char *backingDirectory = NULL;
VIR_DEBUG("path=%s canonPath=%s dir=%s format=%d uid=%d gid=%d probe=%d",
- path, canonPath, NULLSTR(directory), format,
+ src->path, canonPath, NULLSTR(src->relDir), src->format,
(int)uid, (int)gid, allow_probe);
if (virHashLookup(cycle, canonPath)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("backing store for %s is self-referential"),
- path);
+ src->path);
return -1;
}
+
if (virHashAddEntry(cycle, canonPath, (void *)1) < 0)
return -1;
- if (virStorageIsFile(path)) {
- if (VIR_STRDUP(meta->relPath, path) < 0)
- return -1;
- if (VIR_STRDUP(meta->path, canonPath) < 0)
- return -1;
- if (VIR_STRDUP(meta->relDir, directory) < 0)
+ if (virStorageSourceGetActualType(src) != VIR_STORAGE_TYPE_NETWORK) {
+ if ((fd = virFileOpenAs(src->path, O_RDONLY, 0, uid, gid, 0)) < 0) {
+ virReportSystemError(-fd, _("Failed to open file '%s'"),
+ src->path);
return -1;
- meta->format = format;
+ }
- if ((fd = virFileOpenAs(canonPath, O_RDONLY, 0, uid, gid, 0)) < 0) {
- virReportSystemError(-fd, _("Failed to open file '%s'"),
path);
+ if (virStorageFileGetMetadataFromFDInternal(src, fd,
+ &backingFormat) < 0) {
+ VIR_FORCE_CLOSE(fd);
return -1;
}
- ret = virStorageFileGetMetadataFromFDInternal(meta, fd, &backingFormat);
-
if (VIR_CLOSE(fd) < 0)
- VIR_WARN("could not close file %s", path);
+ VIR_WARN("could not close file %s", src->path);
} else {
- /* FIXME: when the proper storage drivers are compiled in, it
- * would be nice to read metadata from the network storage to
- * allow for non-raw images. */
- if (VIR_STRDUP(meta->relPath, path) < 0)
- return -1;
- if (VIR_STRDUP(meta->path, path) < 0)
- return -1;
- meta->type = VIR_STORAGE_TYPE_NETWORK;
- meta->format = VIR_STORAGE_FILE_RAW;
- ret = 0;
+ /* TODO: currently we call this only for local storage */
+ return 0;
}
- if (ret == 0 && meta->backingStoreRaw) {
- if (virStorageIsFile(meta->backingStoreRaw)) {
- if (virFindBackingFile(directory,
- meta->backingStoreRaw,
- &backingDirectory,
- &backingPath) < 0) {
- /* the backing file is (currently) unavailable, treat this
- * file as standalone:
- * backingStoreRaw is kept to mark broken image chains */
- VIR_WARN("Backing file '%s' of image '%s' is
missing.",
- meta->backingStoreRaw, path);
-
- return 0;
- }
- } else {
- if (VIR_STRDUP(backingPath, meta->backingStoreRaw) < 0)
- return -1;
- }
+ /* check wether we need to go deeper */
+ if (!src->backingStoreRaw)
+ return 0;
- virStorageSourcePtr backing;
-
- if (backingFormat == VIR_STORAGE_FILE_AUTO && !allow_probe)
- backingFormat = VIR_STORAGE_FILE_RAW;
- else if (backingFormat == VIR_STORAGE_FILE_AUTO_SAFE)
- backingFormat = VIR_STORAGE_FILE_AUTO;
- if (VIR_ALLOC(backing) < 0 ||
- virStorageFileGetMetadataRecurse(meta->backingStoreRaw,
- backingPath,
- backingDirectory, backingFormat,
- uid, gid, allow_probe,
- cycle, backing) < 0) {
- /* If we failed to get backing data, mark the chain broken */
- virStorageSourceFree(backing);
- } else {
- meta->backingStore = backing;
+ if (VIR_ALLOC(backingStore) < 0)
+ return -1;
+
+ if (VIR_STRDUP(backingStore->relPath, src->backingStoreRaw) < 0)
+ goto cleanup;
+
+ if (virStorageIsFile(src->backingStoreRaw)) {
+ backingStore->type = VIR_STORAGE_TYPE_FILE;
+
+ if (virFindBackingFile(src->relDir,
+ src->backingStoreRaw,
+ &backingStore->relDir,
+ &backingStore->path) < 0) {
+ /* the backing file is (currently) unavailable, treat this
+ * file as standalone:
+ * backingStoreRaw is kept to mark broken image chains */
+ VIR_WARN("Backing file '%s' of image '%s' is
missing.",
+ src->backingStoreRaw, src->path);
+ ret = 0;
+ goto cleanup;
}
+ } else {
+ /* TODO: To satisfy the test case, copy the network URI as path. T
+ * his will be removed later */
+ backingStore->type = VIR_STORAGE_TYPE_NETWORK;
+
+ if (VIR_STRDUP(backingStore->path, src->backingStoreRaw) < 0)
+ goto cleanup;
}
- VIR_FREE(backingDirectory);
- VIR_FREE(backingPath);
+ if (backingFormat == VIR_STORAGE_FILE_AUTO && !allow_probe)
+ backingStore->format = VIR_STORAGE_FILE_RAW;
+ else if (backingFormat == VIR_STORAGE_FILE_AUTO_SAFE)
+ backingStore->format = VIR_STORAGE_FILE_AUTO;
+ else
+ backingStore->format = backingFormat;
+
+ if (virStorageFileGetMetadataRecurse(backingStore,
+ backingStore->path,
+ uid, gid, allow_probe,
+ cycle) < 0) {
+ /* if we fail somewhere midway, just accept the and return a
+ * broken chain */
+ ret = 0;
+ goto cleanup;
+ }
+
+ src->backingStore = backingStore;
+ backingStore = NULL;
+ ret = 0;
+
+ cleanup:
+ virStorageSourceFree(backingStore);
return ret;
}
+
/**
* virStorageFileGetMetadata:
*
@@ -1220,51 +1227,51 @@ virStorageFileGetMetadataRecurse(const char *path, const char
*canonPath,
*
* Caller MUST free result after use via virStorageSourceFree.
*/
-virStorageSourcePtr
-virStorageFileGetMetadata(const char *path, int format,
+int
+virStorageFileGetMetadata(virStorageSourcePtr src,
uid_t uid, gid_t gid,
bool allow_probe)
{
VIR_DEBUG("path=%s format=%d uid=%d gid=%d probe=%d",
- path, format, (int)uid, (int)gid, allow_probe);
+ src->path, src->format, (int)uid, (int)gid, allow_probe);
- virHashTablePtr cycle = virHashCreate(5, NULL);
- virStorageSourcePtr meta = NULL;
- virStorageSourcePtr ret = NULL;
+ virHashTablePtr cycle = NULL;
char *canonPath = NULL;
- char *directory = NULL;
+ int ret = -1;
- if (!cycle)
- return NULL;
+ if (!(cycle = virHashCreate(5, NULL)))
+ return -1;
- if (virStorageIsFile(path)) {
- if (!(canonPath = canonicalize_file_name(path))) {
- virReportSystemError(errno, _("unable to resolve '%s'"),
path);
+ if (virStorageSourceGetActualType(src) != VIR_STORAGE_TYPE_NETWORK) {
+ if (!(canonPath = canonicalize_file_name(src->path))) {
+ virReportSystemError(errno, _("unable to resolve '%s'"),
+ src->path);
goto cleanup;
}
- if (!(directory = mdir_name(path))) {
+
+ if (!src->relPath &&
+ VIR_STRDUP(src->relPath, src->path) < 0)
+ goto cleanup;
+
+ if (!src->relDir &&
+ !(src->relDir = mdir_name(src->path))) {
virReportOOMError();
goto cleanup;
}
- } else if (VIR_STRDUP(canonPath, path) < 0) {
+ } else {
+ /* TODO: currently unimplemented for non-local storage */
+ ret = 0;
goto cleanup;
}
- if (VIR_ALLOC(meta) < 0)
- goto cleanup;
- if (format <= VIR_STORAGE_FILE_NONE)
- format = allow_probe ? VIR_STORAGE_FILE_AUTO : VIR_STORAGE_FILE_RAW;
- if (virStorageFileGetMetadataRecurse(path, canonPath, directory, format,
- uid, gid, allow_probe, cycle,
- meta) < 0)
- goto cleanup;
- ret = meta;
- meta = NULL;
+ if (src->format <= VIR_STORAGE_FILE_NONE)
+ src->format = allow_probe ? VIR_STORAGE_FILE_AUTO : VIR_STORAGE_FILE_RAW;
+
+ ret = virStorageFileGetMetadataRecurse(src, canonPath, uid, gid,
+ allow_probe, cycle);
cleanup:
- virStorageSourceFree(meta);
VIR_FREE(canonPath);
- VIR_FREE(directory);
virHashFree(cycle);
return ret;
}
diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h
index e60befe..a0adb9b 100644
--- a/src/util/virstoragefile.h
+++ b/src/util/virstoragefile.h
@@ -263,10 +263,9 @@ int virStorageFileProbeFormat(const char *path, uid_t uid, gid_t
gid);
int virStorageFileProbeFormatFromBuf(const char *path, char *buf,
size_t buflen);
-virStorageSourcePtr virStorageFileGetMetadata(const char *path,
- int format,
- uid_t uid, gid_t gid,
- bool allow_probe)
+int virStorageFileGetMetadata(virStorageSourcePtr src,
+ uid_t uid, gid_t gid,
+ bool allow_probe)
ATTRIBUTE_NONNULL(1);
virStorageSourcePtr virStorageFileGetMetadataFromFD(const char *path,
int fd,
diff --git a/tests/virstoragetest.c b/tests/virstoragetest.c
index 370b8c2..5320c78 100644
--- a/tests/virstoragetest.c
+++ b/tests/virstoragetest.c
@@ -29,6 +29,7 @@
#include "virlog.h"
#include "virstoragefile.h"
#include "virstring.h"
+#include "dirname.h"
#define VIR_FROM_THIS VIR_FROM_NONE
@@ -88,6 +89,44 @@ testCleanupImages(void)
virFileDeleteTree(datadir);
}
+
+static virStorageSourcePtr
+testStorageFileGetMetadata(const char *path,
+ int format,
+ uid_t uid, gid_t gid,
+ bool allow_probe)
+{
+ virStorageSourcePtr ret = NULL;
+
+ if (VIR_ALLOC(ret) < 0)
+ return NULL;
+
+ ret->type = VIR_STORAGE_TYPE_FILE;
+ ret->format = format;
+
+ if (VIR_STRDUP(ret->relPath, path) < 0)
+ goto error;
+
+ if (!(ret->relDir = mdir_name(path))) {
+ virReportOOMError();
+ goto error;
+ }
+
+ if (!(ret->path = canonicalize_file_name(path))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "failed to resolve
'%s'", path);
+ goto error;
+ }
+
+ if (virStorageFileGetMetadata(ret, uid, gid, allow_probe) < 0)
+ goto error;
+
+ return ret;
+
+ error:
+ virStorageSourceFree(ret);
+ return NULL;
+}
+
static int
testPrepImages(void)
{
@@ -272,7 +311,7 @@ testStorageChain(const void *args)
char *broken = NULL;
bool isAbs = !!(data->flags & ABS_START);
- meta = virStorageFileGetMetadata(data->start, data->format, -1, -1,
+ meta = testStorageFileGetMetadata(data->start, data->format, -1, -1,
(data->flags & ALLOW_PROBE) != 0);
if (!meta) {
if (data->flags & EXP_FAIL) {
@@ -825,7 +864,7 @@ mymain(void)
ret = -1;
/* Test behavior of chain lookups, absolute backing from relative start */
- chain = virStorageFileGetMetadata("wrap", VIR_STORAGE_FILE_QCOW2,
+ chain = testStorageFileGetMetadata("wrap", VIR_STORAGE_FILE_QCOW2,
-1, -1, false);
if (!chain) {
ret = -1;
@@ -870,7 +909,7 @@ mymain(void)
/* Test behavior of chain lookups, relative backing from absolute start */
virStorageSourceFree(chain);
- chain = virStorageFileGetMetadata(abswrap, VIR_STORAGE_FILE_QCOW2,
+ chain = testStorageFileGetMetadata(abswrap, VIR_STORAGE_FILE_QCOW2,
-1, -1, false);
if (!chain) {
ret = -1;
@@ -900,7 +939,7 @@ mymain(void)
/* Test behavior of chain lookups, relative backing */
virStorageSourceFree(chain);
- chain = virStorageFileGetMetadata("sub/link2", VIR_STORAGE_FILE_QCOW2,
+ chain = testStorageFileGetMetadata("sub/link2", VIR_STORAGE_FILE_QCOW2,
-1, -1, false);
if (!chain) {
ret = -1;
--
1.9.1