提交 8823272d 编写于 作者: P Peter Krempa

util: storage: Invert the way recursive metadata retrieval works

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 parent 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.
上级 cc92ee32
...@@ -18537,9 +18537,8 @@ virDomainDiskDefForeachPath(virDomainDiskDefPtr disk, ...@@ -18537,9 +18537,8 @@ virDomainDiskDefForeachPath(virDomainDiskDefPtr disk,
if (iter(disk, path, 0, opaque) < 0) if (iter(disk, path, 0, opaque) < 0)
goto cleanup; 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;
tmp = disk->src.backingStore ? disk->src.backingStore->backingStore : NULL;
while (tmp && virStorageIsFile(tmp->path)) { while (tmp && virStorageIsFile(tmp->path)) {
if (!ignoreOpenFailure && tmp->backingStoreRaw && !tmp->backingStore) { if (!ignoreOpenFailure && tmp->backingStoreRaw && !tmp->backingStore) {
virReportError(VIR_ERR_INTERNAL_ERROR, virReportError(VIR_ERR_INTERNAL_ERROR,
......
...@@ -2239,10 +2239,10 @@ qemuDiskChainCheckBroken(virDomainDiskDefPtr disk) ...@@ -2239,10 +2239,10 @@ qemuDiskChainCheckBroken(virDomainDiskDefPtr disk)
{ {
char *brokenFile = NULL; char *brokenFile = NULL;
if (!virDomainDiskGetSource(disk) || !disk->src.backingStore) if (!virDomainDiskGetSource(disk))
return 0; return 0;
if (virStorageFileChainGetBroken(disk->src.backingStore, &brokenFile) < 0) if (virStorageFileChainGetBroken(&disk->src, &brokenFile) < 0)
return -1; return -1;
if (brokenFile) { if (brokenFile) {
...@@ -2419,11 +2419,9 @@ qemuDomainDetermineDiskChain(virQEMUDriverPtr driver, ...@@ -2419,11 +2419,9 @@ qemuDomainDetermineDiskChain(virQEMUDriverPtr driver,
qemuDomainGetImageIds(cfg, vm, disk, &uid, &gid); qemuDomainGetImageIds(cfg, vm, disk, &uid, &gid);
disk->src.backingStore = virStorageFileGetMetadata(src, if (virStorageFileGetMetadata(&disk->src,
virDomainDiskGetFormat(disk), uid, gid,
uid, gid, cfg->allowDiskFormatProbing) < 0)
cfg->allowDiskFormatProbing);
if (!disk->src.backingStore)
ret = -1; ret = -1;
cleanup: cleanup:
......
...@@ -15123,7 +15123,7 @@ qemuDomainBlockCopy(virDomainObjPtr vm, ...@@ -15123,7 +15123,7 @@ qemuDomainBlockCopy(virDomainObjPtr vm,
if ((flags & VIR_DOMAIN_BLOCK_REBASE_SHALLOW) && if ((flags & VIR_DOMAIN_BLOCK_REBASE_SHALLOW) &&
STREQ_NULLABLE(format, "raw") && STREQ_NULLABLE(format, "raw") &&
disk->src.backingStore->backingStore->path) { disk->src.backingStore->path) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("disk '%s' has backing file, so raw shallow copy " _("disk '%s' has backing file, so raw shallow copy "
"is not possible"), "is not possible"),
...@@ -15330,8 +15330,8 @@ qemuDomainBlockCommit(virDomainPtr dom, const char *path, const char *base, ...@@ -15330,8 +15330,8 @@ qemuDomainBlockCommit(virDomainPtr dom, const char *path, const char *base,
if (!top) { if (!top) {
top_canon = disk->src.path; top_canon = disk->src.path;
top_meta = disk->src.backingStore; top_meta = &disk->src;
} else if (!(top_canon = virStorageFileChainLookup(disk->src.backingStore, } else if (!(top_canon = virStorageFileChainLookup(&disk->src,
top, &top_meta, top, &top_meta,
&top_parent))) { &top_parent))) {
goto endjob; goto endjob;
......
...@@ -943,18 +943,15 @@ get_files(vahControl * ctl) ...@@ -943,18 +943,15 @@ get_files(vahControl * ctl)
for (i = 0; i < ctl->def->ndisks; i++) { for (i = 0; i < ctl->def->ndisks; i++) {
virDomainDiskDefPtr disk = ctl->def->disks[i]; virDomainDiskDefPtr disk = ctl->def->disks[i];
const char *src = virDomainDiskGetSource(disk);
if (!src) if (!virDomainDiskGetSource(disk))
continue; continue;
/* XXX - if we knew the qemu user:group here we could send it in /* 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. * so that the open could be re-tried as that user:group.
*/ */
if (!disk->src.backingStore) { if (!disk->src.backingStore) {
bool probe = ctl->allowDiskFormatProbing; bool probe = ctl->allowDiskFormatProbing;
disk->src.backingStore = virStorageFileGetMetadata(src, virStorageFileGetMetadata(&disk->src, -1, -1, probe);
virDomainDiskGetFormat(disk),
-1, -1, probe);
} }
/* XXX passing ignoreOpenFailure = true to get back to the behavior /* XXX passing ignoreOpenFailure = true to get back to the behavior
......
...@@ -1110,105 +1110,112 @@ virStorageFileGetMetadataFromFD(const char *path, ...@@ -1110,105 +1110,112 @@ virStorageFileGetMetadataFromFD(const char *path,
/* Recursive workhorse for virStorageFileGetMetadata. */ /* Recursive workhorse for virStorageFileGetMetadata. */
static int static int
virStorageFileGetMetadataRecurse(const char *path, const char *canonPath, virStorageFileGetMetadataRecurse(virStorageSourcePtr src,
const char *directory, const char *canonPath,
int format, uid_t uid, gid_t gid, uid_t uid, gid_t gid,
bool allow_probe, virHashTablePtr cycle, bool allow_probe,
virStorageSourcePtr meta) virHashTablePtr cycle)
{ {
int fd; int fd;
int ret = -1; int ret = -1;
virStorageSourcePtr backingStore = NULL;
int backingFormat; int backingFormat;
char *backingPath = NULL;
char *backingDirectory = NULL;
VIR_DEBUG("path=%s canonPath=%s dir=%s format=%d uid=%d gid=%d probe=%d", 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); (int)uid, (int)gid, allow_probe);
if (virHashLookup(cycle, canonPath)) { if (virHashLookup(cycle, canonPath)) {
virReportError(VIR_ERR_INTERNAL_ERROR, virReportError(VIR_ERR_INTERNAL_ERROR,
_("backing store for %s is self-referential"), _("backing store for %s is self-referential"),
path); src->path);
return -1; return -1;
} }
if (virHashAddEntry(cycle, canonPath, (void *)1) < 0) if (virHashAddEntry(cycle, canonPath, (void *)1) < 0)
return -1; return -1;
if (virStorageIsFile(path)) { if (virStorageSourceGetActualType(src) != VIR_STORAGE_TYPE_NETWORK) {
if (VIR_STRDUP(meta->relPath, path) < 0) if ((fd = virFileOpenAs(src->path, O_RDONLY, 0, uid, gid, 0)) < 0) {
return -1; virReportSystemError(-fd, _("Failed to open file '%s'"),
if (VIR_STRDUP(meta->path, canonPath) < 0) src->path);
return -1;
if (VIR_STRDUP(meta->relDir, directory) < 0)
return -1; return -1;
meta->format = format; }
if ((fd = virFileOpenAs(canonPath, O_RDONLY, 0, uid, gid, 0)) < 0) { if (virStorageFileGetMetadataFromFDInternal(src, fd,
virReportSystemError(-fd, _("Failed to open file '%s'"), path); &backingFormat) < 0) {
VIR_FORCE_CLOSE(fd);
return -1; return -1;
} }
ret = virStorageFileGetMetadataFromFDInternal(meta, fd, &backingFormat);
if (VIR_CLOSE(fd) < 0) if (VIR_CLOSE(fd) < 0)
VIR_WARN("could not close file %s", path); VIR_WARN("could not close file %s", src->path);
} else { } else {
/* FIXME: when the proper storage drivers are compiled in, it /* TODO: currently we call this only for local storage */
* would be nice to read metadata from the network storage to return 0;
* 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;
} }
if (ret == 0 && meta->backingStoreRaw) { /* check whether we need to go deeper */
virStorageSourcePtr backing; if (!src->backingStoreRaw)
return 0;
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;
}
if (backingFormat == VIR_STORAGE_FILE_AUTO && !allow_probe) if (VIR_ALLOC(backingStore) < 0)
backingFormat = VIR_STORAGE_FILE_RAW; return -1;
else if (backingFormat == VIR_STORAGE_FILE_AUTO_SAFE)
backingFormat = VIR_STORAGE_FILE_AUTO; if (VIR_STRDUP(backingStore->relPath, src->backingStoreRaw) < 0)
if (VIR_ALLOC(backing) < 0 || goto cleanup;
virStorageFileGetMetadataRecurse(meta->backingStoreRaw,
backingPath, if (virStorageIsFile(src->backingStoreRaw)) {
backingDirectory, backingFormat, backingStore->type = VIR_STORAGE_TYPE_FILE;
uid, gid, allow_probe,
cycle, backing) < 0) { if (virFindBackingFile(src->relDir,
/* If we failed to get backing data, mark the chain broken */ src->backingStoreRaw,
virStorageSourceFree(backing); &backingStore->relDir,
} else { &backingStore->path) < 0) {
meta->backingStore = backing; /* 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. This
* will be removed later. */
backingStore->type = VIR_STORAGE_TYPE_NETWORK;
if (VIR_STRDUP(backingStore->path, src->backingStoreRaw) < 0)
goto cleanup;
} }
VIR_FREE(backingDirectory); if (backingFormat == VIR_STORAGE_FILE_AUTO && !allow_probe)
VIR_FREE(backingPath); 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 and return a
* broken chain */
ret = 0;
goto cleanup;
}
src->backingStore = backingStore;
backingStore = NULL;
ret = 0;
cleanup:
virStorageSourceFree(backingStore);
return ret; return ret;
} }
/** /**
* virStorageFileGetMetadata: * virStorageFileGetMetadata:
* *
...@@ -1226,51 +1233,51 @@ virStorageFileGetMetadataRecurse(const char *path, const char *canonPath, ...@@ -1226,51 +1233,51 @@ virStorageFileGetMetadataRecurse(const char *path, const char *canonPath,
* *
* Caller MUST free result after use via virStorageSourceFree. * Caller MUST free result after use via virStorageSourceFree.
*/ */
virStorageSourcePtr int
virStorageFileGetMetadata(const char *path, int format, virStorageFileGetMetadata(virStorageSourcePtr src,
uid_t uid, gid_t gid, uid_t uid, gid_t gid,
bool allow_probe) bool allow_probe)
{ {
VIR_DEBUG("path=%s format=%d uid=%d gid=%d probe=%d", 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); virHashTablePtr cycle = NULL;
virStorageSourcePtr meta = NULL;
virStorageSourcePtr ret = NULL;
char *canonPath = NULL; char *canonPath = NULL;
char *directory = NULL; int ret = -1;
if (!cycle) if (!(cycle = virHashCreate(5, NULL)))
return NULL; return -1;
if (virStorageIsFile(path)) { if (virStorageSourceGetActualType(src) != VIR_STORAGE_TYPE_NETWORK) {
if (!(canonPath = canonicalize_file_name(path))) { if (!(canonPath = canonicalize_file_name(src->path))) {
virReportSystemError(errno, _("unable to resolve '%s'"), path); virReportSystemError(errno, _("unable to resolve '%s'"),
src->path);
goto cleanup; 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(); virReportOOMError();
goto cleanup; goto cleanup;
} }
} else if (VIR_STRDUP(canonPath, path) < 0) { } else {
/* TODO: currently unimplemented for non-local storage */
ret = 0;
goto cleanup; goto cleanup;
} }
if (VIR_ALLOC(meta) < 0)
goto cleanup;
if (format <= VIR_STORAGE_FILE_NONE) if (src->format <= VIR_STORAGE_FILE_NONE)
format = allow_probe ? VIR_STORAGE_FILE_AUTO : VIR_STORAGE_FILE_RAW; src->format = allow_probe ? VIR_STORAGE_FILE_AUTO : VIR_STORAGE_FILE_RAW;
if (virStorageFileGetMetadataRecurse(path, canonPath, directory, format,
uid, gid, allow_probe, cycle, ret = virStorageFileGetMetadataRecurse(src, canonPath, uid, gid,
meta) < 0) allow_probe, cycle);
goto cleanup;
ret = meta;
meta = NULL;
cleanup: cleanup:
virStorageSourceFree(meta);
VIR_FREE(canonPath); VIR_FREE(canonPath);
VIR_FREE(directory);
virHashFree(cycle); virHashFree(cycle);
return ret; return ret;
} }
......
...@@ -263,10 +263,9 @@ int virStorageFileProbeFormat(const char *path, uid_t uid, gid_t gid); ...@@ -263,10 +263,9 @@ int virStorageFileProbeFormat(const char *path, uid_t uid, gid_t gid);
int virStorageFileProbeFormatFromBuf(const char *path, char *buf, int virStorageFileProbeFormatFromBuf(const char *path, char *buf,
size_t buflen); size_t buflen);
virStorageSourcePtr virStorageFileGetMetadata(const char *path, int virStorageFileGetMetadata(virStorageSourcePtr src,
int format, uid_t uid, gid_t gid,
uid_t uid, gid_t gid, bool allow_probe)
bool allow_probe)
ATTRIBUTE_NONNULL(1); ATTRIBUTE_NONNULL(1);
virStorageSourcePtr virStorageFileGetMetadataFromFD(const char *path, virStorageSourcePtr virStorageFileGetMetadataFromFD(const char *path,
int fd, int fd,
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include "virlog.h" #include "virlog.h"
#include "virstoragefile.h" #include "virstoragefile.h"
#include "virstring.h" #include "virstring.h"
#include "dirname.h"
#define VIR_FROM_THIS VIR_FROM_NONE #define VIR_FROM_THIS VIR_FROM_NONE
...@@ -88,6 +89,44 @@ testCleanupImages(void) ...@@ -88,6 +89,44 @@ testCleanupImages(void)
virFileDeleteTree(datadir); 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 static int
testPrepImages(void) testPrepImages(void)
{ {
...@@ -272,8 +311,8 @@ testStorageChain(const void *args) ...@@ -272,8 +311,8 @@ testStorageChain(const void *args)
char *broken = NULL; char *broken = NULL;
bool isAbs = !!(data->flags & ABS_START); 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); (data->flags & ALLOW_PROBE) != 0);
if (!meta) { if (!meta) {
if (data->flags & EXP_FAIL) { if (data->flags & EXP_FAIL) {
virResetLastError(); virResetLastError();
...@@ -825,8 +864,8 @@ mymain(void) ...@@ -825,8 +864,8 @@ mymain(void)
ret = -1; ret = -1;
/* Test behavior of chain lookups, absolute backing from relative start */ /* 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); -1, -1, false);
if (!chain) { if (!chain) {
ret = -1; ret = -1;
goto cleanup; goto cleanup;
...@@ -870,8 +909,8 @@ mymain(void) ...@@ -870,8 +909,8 @@ mymain(void)
/* Test behavior of chain lookups, relative backing from absolute start */ /* Test behavior of chain lookups, relative backing from absolute start */
virStorageSourceFree(chain); virStorageSourceFree(chain);
chain = virStorageFileGetMetadata(abswrap, VIR_STORAGE_FILE_QCOW2, chain = testStorageFileGetMetadata(abswrap, VIR_STORAGE_FILE_QCOW2,
-1, -1, false); -1, -1, false);
if (!chain) { if (!chain) {
ret = -1; ret = -1;
goto cleanup; goto cleanup;
...@@ -900,8 +939,8 @@ mymain(void) ...@@ -900,8 +939,8 @@ mymain(void)
/* Test behavior of chain lookups, relative backing */ /* Test behavior of chain lookups, relative backing */
virStorageSourceFree(chain); virStorageSourceFree(chain);
chain = virStorageFileGetMetadata("sub/link2", VIR_STORAGE_FILE_QCOW2, chain = testStorageFileGetMetadata("sub/link2", VIR_STORAGE_FILE_QCOW2,
-1, -1, false); -1, -1, false);
if (!chain) { if (!chain) {
ret = -1; ret = -1;
goto cleanup; goto cleanup;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册