>From QEMU docs/interop/qcow2.txt : Byte 20 - 23: cluster_bits Number of bits that are used for addressing an offset within a cluster (1 << cluster_bits is the cluster size).
With this patch libvirt will be able to report the current cluster_size for all existing storage volumes managed by storage driver. Signed-off-by: Pavel Hrdina <phrd...@redhat.com> --- src/storage/storage_util.c | 3 ++ src/storage_file/storage_file_probe.c | 55 +++++++++++++++++++-------- 2 files changed, 42 insertions(+), 16 deletions(-) diff --git a/src/storage/storage_util.c b/src/storage/storage_util.c index c8299852a3..a7c9355bf9 100644 --- a/src/storage/storage_util.c +++ b/src/storage/storage_util.c @@ -3483,6 +3483,9 @@ storageBackendProbeTarget(virStorageSource *target, if (meta->capacity) target->capacity = meta->capacity; + if (meta->clusterSize > 0) + target->clusterSize = meta->clusterSize; + if (encryption && meta->encryption) { if (meta->encryption->payload_offset != -1) target->capacity -= meta->encryption->payload_offset * 512; diff --git a/src/storage_file/storage_file_probe.c b/src/storage_file/storage_file_probe.c index afe64da02e..423597049f 100644 --- a/src/storage_file/storage_file_probe.c +++ b/src/storage_file/storage_file_probe.c @@ -94,6 +94,9 @@ struct FileTypeInfo { /* Store a COW base image path (possibly relative), * or NULL if there is no COW base image, to RES; * return BACKING_STORE_* */ + int clusterBitsOffset; /* Byte offset from start of file where we find + * number of cluster bits, -1 to skip. */ + int clusterBitsSize; /* Number of bytes for cluster bits. */ const struct FileEncryptionInfo *cryptInfo; /* Encryption info */ int (*getBackingStore)(char **res, int *format, const char *buf, size_t buf_size); @@ -116,7 +119,8 @@ qedGetBackingStore(char **, int *, const char *, size_t); #define QCOWX_HDR_VERSION (4) #define QCOWX_HDR_BACKING_FILE_OFFSET (QCOWX_HDR_VERSION+4) #define QCOWX_HDR_BACKING_FILE_SIZE (QCOWX_HDR_BACKING_FILE_OFFSET+8) -#define QCOWX_HDR_IMAGE_SIZE (QCOWX_HDR_BACKING_FILE_SIZE+4+4) +#define QCOWX_HDR_CLUSTER_BITS_OFFSET (QCOWX_HDR_BACKING_FILE_SIZE+4) +#define QCOWX_HDR_IMAGE_SIZE (QCOWX_HDR_CLUSTER_BITS_OFFSET+4) #define QCOW1_HDR_CRYPT (QCOWX_HDR_IMAGE_SIZE+8+1+1+2) #define QCOW2_HDR_CRYPT (QCOWX_HDR_IMAGE_SIZE+8) @@ -238,18 +242,18 @@ static struct FileEncryptionInfo const qcow2EncryptionInfo[] = { static struct FileTypeInfo const fileTypeInfo[] = { [VIR_STORAGE_FILE_NONE] = { 0, NULL, LV_LITTLE_ENDIAN, - -1, 0, {0}, 0, 0, 0, NULL, NULL, NULL }, + -1, 0, {0}, 0, 0, 0, -1, 0, NULL, NULL, NULL }, [VIR_STORAGE_FILE_RAW] = { 0, NULL, LV_LITTLE_ENDIAN, - -1, 0, {0}, 0, 0, 0, + -1, 0, {0}, 0, 0, 0, -1, 0, luksEncryptionInfo, NULL, NULL }, [VIR_STORAGE_FILE_DIR] = { 0, NULL, LV_LITTLE_ENDIAN, - -1, 0, {0}, 0, 0, 0, NULL, NULL, NULL }, + -1, 0, {0}, 0, 0, 0, -1, 0, NULL, NULL, NULL }, [VIR_STORAGE_FILE_BOCHS] = { /*"Bochs Virtual HD Image", */ /* Untested */ 0, NULL, LV_LITTLE_ENDIAN, 64, 4, {0x20000}, - 32+16+16+4+4+4+4+4, 8, 1, NULL, NULL, NULL + 32+16+16+4+4+4+4+4, 8, 1, -1, 0, NULL, NULL, NULL }, [VIR_STORAGE_FILE_CLOOP] = { /* #!/bin/sh @@ -258,7 +262,7 @@ static struct FileTypeInfo const fileTypeInfo[] = { */ /* Untested */ 0, NULL, LV_LITTLE_ENDIAN, -1, 0, {0}, - -1, 0, 0, NULL, NULL, NULL + -1, 0, 0, -1, 0, NULL, NULL, NULL }, [VIR_STORAGE_FILE_DMG] = { /* XXX QEMU says there's no magic for dmg, @@ -266,43 +270,44 @@ static struct FileTypeInfo const fileTypeInfo[] = { * would have to match) but then disables that check. */ 0, NULL, 0, -1, 0, {0}, - -1, 0, 0, NULL, NULL, NULL + -1, 0, 0, -1, 0, NULL, NULL, NULL }, [VIR_STORAGE_FILE_ISO] = { 32769, "CD001", LV_LITTLE_ENDIAN, -2, 0, {0}, - -1, 0, 0, NULL, NULL, NULL + -1, 0, 0, -1, 0, NULL, NULL, NULL }, [VIR_STORAGE_FILE_VPC] = { 0, "conectix", LV_BIG_ENDIAN, 12, 4, {0x10000}, - 8 + 4 + 4 + 8 + 4 + 4 + 2 + 2 + 4, 8, 1, NULL, NULL, NULL + 8 + 4 + 4 + 8 + 4 + 4 + 2 + 2 + 4, 8, 1, -1, 0, NULL, NULL, NULL }, /* TODO: add getBackingStore function */ [VIR_STORAGE_FILE_VDI] = { 64, "\x7f\x10\xda\xbe", LV_LITTLE_ENDIAN, 68, 4, {0x00010001}, - 64 + 5 * 4 + 256 + 7 * 4, 8, 1, NULL, NULL, NULL}, + 64 + 5 * 4 + 256 + 7 * 4, 8, 1, -1, 0, NULL, NULL, NULL}, /* Not direct file formats, but used for various drivers */ [VIR_STORAGE_FILE_FAT] = { 0, NULL, LV_LITTLE_ENDIAN, - -1, 0, {0}, 0, 0, 0, NULL, NULL, NULL }, + -1, 0, {0}, 0, 0, 0, -1, 0, NULL, NULL, NULL }, [VIR_STORAGE_FILE_VHD] = { 0, NULL, LV_LITTLE_ENDIAN, - -1, 0, {0}, 0, 0, 0, NULL, NULL, NULL }, + -1, 0, {0}, 0, 0, 0, -1, 0, NULL, NULL, NULL }, [VIR_STORAGE_FILE_PLOOP] = { 0, "WithouFreSpacExt", LV_LITTLE_ENDIAN, -2, 0, {0}, PLOOP_IMAGE_SIZE_OFFSET, 0, - PLOOP_SIZE_MULTIPLIER, NULL, NULL, NULL }, + PLOOP_SIZE_MULTIPLIER, -1, 0, NULL, NULL, NULL }, /* All formats with a backing store probe below here */ [VIR_STORAGE_FILE_COW] = { 0, "OOOM", LV_BIG_ENDIAN, 4, 4, {2}, - 4+4+1024+4, 8, 1, NULL, cowGetBackingStore, NULL + 4+4+1024+4, 8, 1, -1, 0, NULL, cowGetBackingStore, NULL }, [VIR_STORAGE_FILE_QCOW] = { 0, "QFI", LV_BIG_ENDIAN, 4, 4, {1}, QCOWX_HDR_IMAGE_SIZE, 8, 1, + -1, 0, qcow1EncryptionInfo, qcowXGetBackingStore, NULL }, @@ -310,6 +315,7 @@ static struct FileTypeInfo const fileTypeInfo[] = { 0, "QFI", LV_BIG_ENDIAN, 4, 4, {2, 3}, QCOWX_HDR_IMAGE_SIZE, 8, 1, + QCOWX_HDR_CLUSTER_BITS_OFFSET, 4, qcow2EncryptionInfo, qcowXGetBackingStore, qcow2GetFeatures @@ -318,12 +324,12 @@ static struct FileTypeInfo const fileTypeInfo[] = { /* https://wiki.qemu.org/Features/QED */ 0, "QED", LV_LITTLE_ENDIAN, -2, 0, {0}, - QED_HDR_IMAGE_SIZE, 8, 1, NULL, qedGetBackingStore, NULL + QED_HDR_IMAGE_SIZE, 8, 1, -1, 0, NULL, qedGetBackingStore, NULL }, [VIR_STORAGE_FILE_VMDK] = { 0, "KDMV", LV_LITTLE_ENDIAN, 4, 4, {1, 2, 3}, - 4+4+4, 8, 512, NULL, vmdk4GetBackingStore, NULL + 4+4+4, 8, 512, -1, 0, NULL, vmdk4GetBackingStore, NULL }, }; G_STATIC_ASSERT(G_N_ELEMENTS(fileTypeInfo) == VIR_STORAGE_FILE_LAST); @@ -890,6 +896,23 @@ virStorageFileProbeGetMetadata(virStorageSource *meta, meta->capacity *= fileTypeInfo[meta->format].sizeMultiplier; } + if (fileTypeInfo[meta->format].clusterBitsOffset != -1) { + int clusterBits = 0; + + if ((fileTypeInfo[meta->format].clusterBitsOffset + 4) > len) + return 0; + + if (fileTypeInfo[meta->format].endian == LV_LITTLE_ENDIAN) + clusterBits = virReadBufInt32LE(buf + + fileTypeInfo[meta->format].clusterBitsOffset); + else + clusterBits = virReadBufInt32BE(buf + + fileTypeInfo[meta->format].clusterBitsOffset); + + if (clusterBits > 0) + meta->clusterSize = 1 << clusterBits; + } + VIR_FREE(meta->backingStoreRaw); if (fileTypeInfo[meta->format].getBackingStore != NULL) { int store = fileTypeInfo[meta->format].getBackingStore(&meta->backingStoreRaw, -- 2.31.1