1
0
mirror of https://gitlab.com/libvirt/libvirt.git synced 2024-12-25 01:34:11 +03:00

conf: earlier allocation during backing chain crawl

Right now, we are allocating virStorageFileMetadata near the bottom
of the callchain, only after we have identified that we are visiting
a file (and not a network resource).  I'm hoping to eventually
support parsing the backing chain from XML, where the backing chain
crawl then validates what was parsed rather than allocating a fresh
structure.  Likewise, I'm working towards a setup where we have a
backing element even for networks.  Both of these use cases are
easier to code if the allocation is hoisted earlier.

* src/util/virstoragefile.c (virStorageFileGetMetadataInternal)
(virStorageFileGetMetadataFromFDInternal): Change signature.
(virStorageFileGetMetadataFromBuf)
(virStorageFileGetMetadataRecurse, virStorageFileGetMetadata):
Update callers.

Signed-off-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
Eric Blake 2014-04-08 15:20:36 -06:00
parent 79f11b35c7
commit 43f85b995b

View File

@ -771,26 +771,24 @@ qcow2GetFeatures(virBitmapPtr *features,
/* Given a header in BUF with length LEN, as parsed from the file with
* user-provided name PATH and opened from CANONPATH, and where any
* relative backing file will be opened from DIRECTORY, return
* metadata about that file, assuming it has the given FORMAT. */
static virStorageFileMetadataPtr ATTRIBUTE_NONNULL(1)
ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4)
* relative backing file will be opened from DIRECTORY, and assuming
* it has the given FORMAT, populate the newly-allocated META with
* information about the file and its backing store. */
static int ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2)
ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(7)
virStorageFileGetMetadataInternal(const char *path,
const char *canonPath,
const char *directory,
char *buf,
size_t len,
int format)
int format,
virStorageFileMetadataPtr meta)
{
virStorageFileMetadata *meta = NULL;
virStorageFileMetadata *ret = NULL;
int ret = -1;
VIR_DEBUG("path=%s, canonPath=%s, dir=%s, buf=%p, len=%zu, format=%d",
path, canonPath, directory, buf, len, format);
if (VIR_ALLOC(meta) < 0)
return NULL;
if (format == VIR_STORAGE_FILE_AUTO)
format = virStorageFileProbeFormatFromBuf(path, buf, len);
@ -886,11 +884,9 @@ virStorageFileGetMetadataInternal(const char *path,
goto cleanup;
done:
ret = meta;
meta = NULL;
ret = 0;
cleanup:
virStorageFileFreeMetadata(meta);
return ret;
}
@ -981,44 +977,52 @@ virStorageFileGetMetadataFromBuf(const char *path,
size_t len,
int format)
{
virStorageFileMetadataPtr ret;
virStorageFileMetadataPtr ret = NULL;
char *canonPath;
if (!(canonPath = canonicalize_file_name(path))) {
virReportSystemError(errno, _("unable to resolve '%s'"), path);
return NULL;
}
if (VIR_ALLOC(ret) < 0)
goto cleanup;
ret = virStorageFileGetMetadataInternal(path, canonPath, ".", buf, len,
format);
if (virStorageFileGetMetadataInternal(path, canonPath, ".", buf, len,
format, ret) < 0) {
virStorageFileFreeMetadata(ret);
ret = NULL;
}
cleanup:
VIR_FREE(canonPath);
return ret;
}
/* Internal version that also supports a containing directory name. */
static virStorageFileMetadataPtr
static int
virStorageFileGetMetadataFromFDInternal(const char *path,
const char *canonPath,
const char *directory,
int fd,
int format)
int format,
virStorageFileMetadataPtr meta)
{
char *buf = NULL;
ssize_t len = VIR_STORAGE_MAX_HEADER;
struct stat sb;
virStorageFileMetadataPtr ret = NULL;
int ret = -1;
if (fstat(fd, &sb) < 0) {
virReportSystemError(errno,
_("cannot stat file '%s'"),
path);
return NULL;
return -1;
}
/* No header to probe for directories, but also no backing file */
if (S_ISDIR(sb.st_mode)) {
ignore_value(VIR_ALLOC(ret));
ret = 0;
goto cleanup;
}
@ -1033,7 +1037,8 @@ virStorageFileGetMetadataFromFDInternal(const char *path,
}
ret = virStorageFileGetMetadataInternal(path, canonPath, directory,
buf, len, format);
buf, len, format, meta);
cleanup:
VIR_FREE(buf);
return ret;
@ -1063,71 +1068,81 @@ virStorageFileGetMetadataFromFD(const char *path,
int fd,
int format)
{
virStorageFileMetadataPtr ret;
virStorageFileMetadataPtr ret = NULL;
char *canonPath;
if (!(canonPath = canonicalize_file_name(path))) {
virReportSystemError(errno, _("unable to resolve '%s'"), path);
return NULL;
}
ret = virStorageFileGetMetadataFromFDInternal(path, canonPath, ".",
fd, format);
if (VIR_ALLOC(ret) < 0)
goto cleanup;
if (virStorageFileGetMetadataFromFDInternal(path, canonPath, ".",
fd, format, ret) < 0) {
virStorageFileFreeMetadata(ret);
ret = NULL;
}
cleanup:
VIR_FREE(canonPath);
return ret;
}
/* Recursive workhorse for virStorageFileGetMetadata. */
static virStorageFileMetadataPtr
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)
bool allow_probe, virHashTablePtr cycle,
virStorageFileMetadataPtr meta)
{
int fd;
int ret = -1;
VIR_DEBUG("path=%s canonPath=%s dir=%s format=%d uid=%d gid=%d probe=%d",
path, canonPath, NULLSTR(directory), format,
(int)uid, (int)gid, allow_probe);
virStorageFileMetadataPtr ret = NULL;
if (virHashLookup(cycle, canonPath)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("backing store for %s is self-referential"),
path);
return NULL;
return -1;
}
if (virHashAddEntry(cycle, canonPath, (void *)1) < 0)
return NULL;
return -1;
if ((fd = virFileOpenAs(canonPath, O_RDONLY, 0, uid, gid, 0)) < 0) {
virReportSystemError(-fd, _("Failed to open file '%s'"), path);
return NULL;
return -1;
}
ret = virStorageFileGetMetadataFromFDInternal(path, canonPath, directory,
fd, format);
fd, format, meta);
if (VIR_CLOSE(fd) < 0)
VIR_WARN("could not close file %s", path);
if (ret && ret->backingStoreIsFile) {
if (ret->backingStoreFormat == VIR_STORAGE_FILE_AUTO && !allow_probe)
ret->backingStoreFormat = VIR_STORAGE_FILE_RAW;
else if (ret->backingStoreFormat == VIR_STORAGE_FILE_AUTO_SAFE)
ret->backingStoreFormat = VIR_STORAGE_FILE_AUTO;
format = ret->backingStoreFormat;
ret->backingMeta = virStorageFileGetMetadataRecurse(ret->backingStoreRaw,
ret->backingStore,
ret->directory,
format,
uid, gid,
allow_probe,
cycle);
if (!ret->backingMeta) {
if (ret == 0 && meta->backingStoreIsFile) {
virStorageFileMetadataPtr backing;
if (meta->backingStoreFormat == VIR_STORAGE_FILE_AUTO && !allow_probe)
meta->backingStoreFormat = VIR_STORAGE_FILE_RAW;
else if (meta->backingStoreFormat == VIR_STORAGE_FILE_AUTO_SAFE)
meta->backingStoreFormat = VIR_STORAGE_FILE_AUTO;
format = meta->backingStoreFormat;
if (VIR_ALLOC(backing) < 0 ||
virStorageFileGetMetadataRecurse(meta->backingStoreRaw,
meta->backingStore,
meta->directory, format,
uid, gid, allow_probe,
cycle, backing) < 0) {
/* If we failed to get backing data, mark the chain broken */
ret->backingStoreFormat = VIR_STORAGE_FILE_NONE;
VIR_FREE(ret->backingStore);
meta->backingStoreFormat = VIR_STORAGE_FILE_NONE;
VIR_FREE(meta->backingStore);
virStorageFileFreeMetadata(backing);
} else {
meta->backingMeta = backing;
}
}
return ret;
@ -1164,6 +1179,7 @@ virStorageFileGetMetadata(const char *path, int format,
path, format, (int)uid, (int)gid, allow_probe);
virHashTablePtr cycle = virHashCreate(5, NULL);
virStorageFileMetadataPtr meta = NULL;
virStorageFileMetadataPtr ret = NULL;
char *canonPath = NULL;
char *directory = NULL;
@ -1179,12 +1195,20 @@ virStorageFileGetMetadata(const char *path, int format,
virReportOOMError();
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;
ret = virStorageFileGetMetadataRecurse(path, canonPath, directory, format,
uid, gid, allow_probe, cycle);
if (virStorageFileGetMetadataRecurse(path, canonPath, directory, format,
uid, gid, allow_probe, cycle,
meta) < 0)
goto cleanup;
ret = meta;
meta = NULL;
cleanup:
virStorageFileFreeMetadata(meta);
VIR_FREE(canonPath);
VIR_FREE(directory);
virHashFree(cycle);