[libvirt] [PATCH 2/7] util: add support for qcow2v3 image detection

Martin Kletzander mkletzan at redhat.com
Mon Jun 10 15:11:06 UTC 2013


On 06/10/2013 02:10 PM, Ján Tomko wrote:
> Detect qcow2 images with version 3 in the image header as
> VIR_STORAGE_FILE_QCOW2.
> 
> These images have a feature bitfield, with just one feature supported
> so far: lazy_refcounts.
> 
> The header length changed too, moving the location of the backing
> format name.
> ---
>  src/util/virstoragefile.c | 164 +++++++++++++++++++++++++++++++++++-----------
>  src/util/virstoragefile.h |  12 ++++
>  2 files changed, 139 insertions(+), 37 deletions(-)
> 
> diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c
> index a391738..f30324e 100644
> --- a/src/util/virstoragefile.c
> +++ b/src/util/virstoragefile.c
> @@ -59,6 +59,11 @@ VIR_ENUM_IMPL(virStorageFileFormat,
>                "qcow", "qcow2", "qed", "vmdk", "vpc",
>                "fat", "vhd", "vdi")
>  
> +VIR_ENUM_IMPL(virStorageFileFeature,
> +              VIR_STORAGE_FILE_FEATURE_LAST,
> +              "lazy_refcounts",
> +              )
> +
>  enum lv_endian {
>      LV_LITTLE_ENDIAN = 1, /* 1234 */
>      LV_BIG_ENDIAN         /* 4321 */
> @@ -81,7 +86,7 @@ struct FileTypeInfo {
>                             * where we find version number,
>                             * -1 to always fail the version test,
>                             * -2 to always pass the version test */
> -    int versionNumber;    /* Version number to validate */
> +    int versionNumbers[3]; /* Version numbers to validate, terminated by 0 */

There could be a constant for this, which will be increased in case of
need and will appear on some more readable place.

>      int sizeOffset;       /* Byte offset from start of file
>                             * where we find capacity info,
>                             * -1 to use st_size as capacity */
> @@ -95,6 +100,8 @@ struct FileTypeInfo {
>                             * -1 if encryption is not used */
>      int (*getBackingStore)(char **res, int *format,
>                             const unsigned char *buf, size_t buf_size);
> +    int (*getFeatures)(virBitmapPtr *features, int format,
> +                       unsigned char *buf, ssize_t len);
>  };
>  
>  static int cowGetBackingStore(char **, int *,
> @@ -103,6 +110,8 @@ static int qcow1GetBackingStore(char **, int *,
>                                  const unsigned char *, size_t);
>  static int qcow2GetBackingStore(char **, int *,
>                                  const unsigned char *, size_t);
> +static int qcow2GetFeatures(virBitmapPtr *features, int format,
> +                            unsigned char *buf, ssize_t len);
>  static int vmdk4GetBackingStore(char **, int *,
>                                  const unsigned char *, size_t);
>  static int
> @@ -122,6 +131,13 @@ qedGetBackingStore(char **, int *, const unsigned char *, size_t);
>  #define QCOW2_HDR_EXTENSION_END 0
>  #define QCOW2_HDR_EXTENSION_BACKING_FORMAT 0xE2792ACA
>  
> +#define QCOW2v3_HDR_FEATURES_INCOMPATIBLE (QCOW2_HDR_TOTAL_SIZE)
> +#define QCOW2v3_HDR_FEATURES_COMPATIBLE (QCOW2v3_HDR_FEATURES_INCOMPATIBLE+8)
> +#define QCOW2v3_HDR_FEATURES_AUTOCLEAR (QCOW2v3_HDR_FEATURES_COMPATIBLE+8)
> +
> +/* The location of the header size [4 bytes] */
> +#define QCOW2v3_HDR_SIZE       (QCOW2_HDR_TOTAL_SIZE+8+8+8+4)
> +

I must admit I'm not very fond of the naming (qcow2v3), but since this
is an implementation detail and makes sense, let's go with it.

>  #define QED_HDR_FEATURES_OFFSET (4+4+4+4)
>  #define QED_HDR_IMAGE_SIZE (QED_HDR_FEATURES_OFFSET+8+8+8+8)
>  #define QED_HDR_BACKING_FILE_OFFSET (QED_HDR_IMAGE_SIZE+8)
> @@ -137,16 +153,16 @@ qedGetBackingStore(char **, int *, const unsigned char *, size_t);
>  
>  static struct FileTypeInfo const fileTypeInfo[] = {
>      [VIR_STORAGE_FILE_NONE] = { 0, NULL, NULL, LV_LITTLE_ENDIAN,
> -                                -1, 0, 0, 0, 0, 0, NULL },
> +                                -1, {0}, 0, 0, 0, 0, NULL, NULL },
>      [VIR_STORAGE_FILE_RAW] = { 0, NULL, NULL, LV_LITTLE_ENDIAN,
> -                               -1, 0, 0, 0, 0, 0, NULL },
> +                               -1, {0}, 0, 0, 0, 0, NULL, NULL },
>      [VIR_STORAGE_FILE_DIR] = { 0, NULL, NULL, LV_LITTLE_ENDIAN,
> -                               -1, 0, 0, 0, 0, 0, NULL },
> +                               -1, {0}, 0, 0, 0, 0, NULL, NULL },
>      [VIR_STORAGE_FILE_BOCHS] = {
>          /*"Bochs Virtual HD Image", */ /* Untested */
>          0, NULL, NULL,
> -        LV_LITTLE_ENDIAN, 64, 0x20000,
> -        32+16+16+4+4+4+4+4, 8, 1, -1, NULL
> +        LV_LITTLE_ENDIAN, 64, {0x20000, 0},

Good you added the trailing zero, in case some format goes to 3 version
numbers, compiler will shout and we won't get to segfauls'n'stuff.  Took
me a while to appreciate this ;)  But...

[...]
>  
> +/* qcow2 compatible features in the order they appear on-disk */
> +enum qcow2CompatibleFeature {
> +    QCOW2_COMPATIBLE_FEATURE_LAZY_REFCOUNTS = 0,
> +
> +    QCOW2_COMPATIBLE_FEATURE_LAST
> +};
> +
> +/* conversion to virStorageFeatures */

Did you mean virStorageFileFeature?

> +static int qcow2CompatibleFeatureArray[] = {

s/int/const int/ maybe ?

[...]
> @@ -611,12 +653,14 @@ virStorageFileMatchesVersion(int format,
>      else
>          version = virReadBufInt32BE(buf + fileTypeInfo[format].versionOffset);
>  
> -    VIR_DEBUG("Compare detected version %d vs expected version %d",
> -              version, fileTypeInfo[format].versionNumber);
> -    if (version != fileTypeInfo[format].versionNumber)
> -        return false;
> +    for (i = 0; fileTypeInfo[format].versionNumbers[i] != 0; i++) {
> +        VIR_DEBUG("Compare detected version %d vs expected version %d",

Changing the 'expected version' to something like 'one of the expected
versions' could make users less confused when going through the logs,
but not required.

> +                  version, fileTypeInfo[format].versionNumbers[i]);
> +        if (version == fileTypeInfo[format].versionNumbers[i])
> +            return true;
> +    }
>  

... the constant mentioned earlier could be checked upon in here as well
and that would make the format specification 1) safer 2) shorter (not
much, though).

[...]
> @@ -669,6 +713,42 @@ cleanup:
>  }
>  
>  
> +static int
> +qcow2GetFeatures(virBitmapPtr *features,
> +                int format,
> +                unsigned char *buf,
> +                ssize_t len)

indentation

[...]

ACK with:
 - the constant used instead of magic '3'
 - const int
 - indentation

Martin




More information about the libvir-list mailing list