[libvirt] [PATCHv3 08/19] storage: get entire metadata chain in one call

Laine Stump laine at laine.org
Thu Oct 18 18:33:10 UTC 2012


On 10/17/2012 06:30 PM, Eric Blake wrote:
> Previously, no one was using virStorageFileGetMetadata, and for good
> reason - it couldn't support root-squash NFS.  Change the signature
> and make it useful to future patches, including enhancing the metadata
> to recursively track the entire chain.
>
> * src/util/storage_file.h (_virStorageFileMetadata): Add field.
> (virStorageFileGetMetadata): Alter signature.
> * src/util/storage_file.c (virStorageFileGetMetadata): Rewrite.
> (virStorageFileGetMetadataRecurse): New function.
> (virStorageFileFreeMetadata): Handle recursion.
>
> ---
>
> v3: warn rather than error when not returning NULL; inline one
> more bit of functionality regarding probing when format unknown
>
>  src/util/storage_file.c | 95 +++++++++++++++++++++++++++++++++++++++----------
>  src/util/storage_file.h | 18 ++++++----
>  2 files changed, 88 insertions(+), 25 deletions(-)
>
> diff --git a/src/util/storage_file.c b/src/util/storage_file.c
> index 0d8cb86..68c7605 100644
> --- a/src/util/storage_file.c
> +++ b/src/util/storage_file.c
> @@ -40,6 +40,7 @@
>  #include "logging.h"
>  #include "virfile.h"
>  #include "c-ctype.h"
> +#include "virhash.h"
>
>  #define VIR_FROM_THIS VIR_FROM_STORAGE
>
> @@ -839,7 +840,7 @@ virStorageFileProbeFormat(const char *path)
>   *
>   * Extract metadata about the storage volume with the specified
>   * image format. If image format is VIR_STORAGE_FILE_AUTO, it
> - * will probe to automatically identify the format.
> + * will probe to automatically identify the format.  Does not recurse.
>   *
>   * Callers are advised never to use VIR_STORAGE_FILE_AUTO as a
>   * format, since a malicious guest can turn a raw file into any
> @@ -909,12 +910,69 @@ cleanup:
>      return ret;
>  }
>
> +/* Recursive workhorse for virStorageFileGetMetadata.  */
> +static virStorageFileMetadataPtr
> +virStorageFileGetMetadataRecurse(const char *path, int format,
> +                                 uid_t uid, gid_t gid,
> +                                 bool allow_probe, virHashTablePtr cycle)
> +{
> +    int fd;
> +    virStorageFileMetadataPtr ret = NULL;
> +
> +    if (virHashLookup(cycle, path)) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("backing store for %s is self-referential"),
> +                       path);
> +        return NULL;
> +    }
> +    if (virHashAddEntry(cycle, path, (void *)1) < 0)
> +        return NULL;
> +
> +    if ((fd = virFileOpenAs(path, O_RDONLY, 0, uid, gid, 0)) < 0) {
> +        virReportSystemError(-fd, _("cannot open file '%s'"), path);
> +        return NULL;
> +    }
> +
> +    if (VIR_ALLOC(ret) < 0) {
> +        virReportOOMError();
> +        VIR_FORCE_CLOSE(fd);
> +        return NULL;
> +    }
> +    if (virStorageFileGetMetadataFromFD(path, fd, format, ret) < 0) {
> +        virStorageFileFreeMetadata(ret);
> +        VIR_FORCE_CLOSE(fd);
> +        return NULL;
> +    }
> +
> +    if (VIR_CLOSE(fd) < 0)
> +        VIR_WARN("could not close file %s", path);
> +
> +    if (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->backingStore,
> +                                                            format,
> +                                                            uid, gid,
> +                                                            allow_probe,
> +                                                            cycle);
> +    }
> +
> +    return ret;
> +}
> +
>  /**
>   * virStorageFileGetMetadata:
>   *
>   * Extract metadata about the storage volume with the specified
>   * image format. If image format is VIR_STORAGE_FILE_AUTO, it
> - * will probe to automatically identify the format.
> + * will probe to automatically identify the format.  Recurses through
> + * the entire chain.
> + *
> + * Open files using UID and GID (or pass -1 for the current user/group).
> + * Treat any backing files without explicit type as raw, unless ALLOW_PROBE.
>   *
>   * Callers are advised never to use VIR_STORAGE_FILE_AUTO as a
>   * format, since a malicious guest can turn a raw file into any
> @@ -922,27 +980,27 @@ cleanup:
>   *
>   * If the returned meta.backingStoreFormat is VIR_STORAGE_FILE_AUTO
>   * it indicates the image didn't specify an explicit format for its
> - * backing store. Callers are advised against probing for the
> - * backing store format in this case.
> + * backing store. Callers are advised against using ALLOW_PROBE, as
> + * it would probe the backing store format in this case.
>   *
> - * Caller MUST free @meta after use via virStorageFileFreeMetadata.
> + * Caller MUST free result after use via virStorageFileFreeMetadata.
>   */
> -int
> -virStorageFileGetMetadata(const char *path,
> -                          int format,
> -                          virStorageFileMetadata *meta)
> +virStorageFileMetadataPtr
> +virStorageFileGetMetadata(const char *path, int format,
> +                          uid_t uid, gid_t gid,
> +                          bool allow_probe)
>  {
> -    int fd, ret;
> +    virHashTablePtr cycle = virHashCreate(5, NULL);
> +    virStorageFileMetadataPtr ret;
>
> -    if ((fd = open(path, O_RDONLY)) < 0) {
> -        virReportSystemError(errno, _("cannot open file '%s'"), path);
> -        return -1;
> -    }
> -
> -    ret = virStorageFileGetMetadataFromFD(path, fd, format, meta);
> -
> -    VIR_FORCE_CLOSE(fd);
> +    if (!cycle)
> +        return NULL;
>
> +    if (format <= VIR_STORAGE_FILE_NONE)
> +        format = allow_probe ? VIR_STORAGE_FILE_AUTO : VIR_STORAGE_FILE_RAW;
> +    ret = virStorageFileGetMetadataRecurse(path, format, uid, gid,
> +                                           allow_probe, cycle);
> +    virHashFree(cycle);
>      return ret;
>  }
>
> @@ -957,6 +1015,7 @@ virStorageFileFreeMetadata(virStorageFileMetadata *meta)
>      if (!meta)
>          return;
>
> +    virStorageFileFreeMetadata(meta->backingMeta);
>      VIR_FREE(meta->backingStore);
>      VIR_FREE(meta);
>  }
> diff --git a/src/util/storage_file.h b/src/util/storage_file.h
> index 683ec73..18dea6a 100644
> --- a/src/util/storage_file.h
> +++ b/src/util/storage_file.h
> @@ -50,13 +50,16 @@ enum virStorageFileFormat {
>
>  VIR_ENUM_DECL(virStorageFileFormat);
>
> -typedef struct _virStorageFileMetadata {
> +typedef struct _virStorageFileMetadata virStorageFileMetadata;
> +typedef virStorageFileMetadata *virStorageFileMetadataPtr;
> +struct _virStorageFileMetadata {
>      char *backingStore;
> -    int backingStoreFormat;
> +    int backingStoreFormat; /* enum virStorageFileFormat */
>      bool backingStoreIsFile;
> +    virStorageFileMetadataPtr backingMeta;
>      unsigned long long capacity;
>      bool encrypted;
> -} virStorageFileMetadata;
> +};
>
>  # ifndef DEV_BSIZE
>  #  define DEV_BSIZE 512
> @@ -66,15 +69,16 @@ int virStorageFileProbeFormat(const char *path);
>  int virStorageFileProbeFormatFromFD(const char *path,
>                                      int fd);
>
> -int virStorageFileGetMetadata(const char *path,
> -                              int format,
> -                              virStorageFileMetadata *meta);
> +virStorageFileMetadataPtr virStorageFileGetMetadata(const char *path,
> +                                                    int format,
> +                                                    uid_t uid, gid_t gid,
> +                                                    bool allow_probe);
>  int virStorageFileGetMetadataFromFD(const char *path,
>                                      int fd,
>                                      int format,
>                                      virStorageFileMetadata *meta);
>
> -void virStorageFileFreeMetadata(virStorageFileMetadata *meta);
> +void virStorageFileFreeMetadata(virStorageFileMetadataPtr meta);
>
>  int virStorageFileResize(const char *path, unsigned long long capacity);
>

ACK.




More information about the libvir-list mailing list