[libvirt] [PATCH 0/4] Support the QED disk image format (V3)

Changes since V2: - VIR_STORAGE_FILE_AUTO_SAFE is not XML parsable - Break out QED header defines by field and add link to QED spec - Removed redundant overflow check in qedGetBackingStore Changes since V1: - Fix virStorageFileMatchesVersion() for formats without version info - Allow backingStore format probing for QED images since it is safe Qemu is about to gain support for a new disk image format: QED. Details on this format (including specification) can be found here: http://wiki.qemu.org/Features/QED. This short series of patches allows QED images to be used with libvirt. Adam Litke (4): Allow probing of image formats without version information QED: Basic support for QED images storage_file: Add a new flag to mark backing files that are safe to probe Support for probing qed image metadata src/conf/domain_conf.c | 4 ++ src/util/storage_file.c | 86 +++++++++++++++++++++++++++++++++++++++++++++- src/util/storage_file.h | 2 + 3 files changed, 90 insertions(+), 2 deletions(-) -- 1.7.3.2.164.g6f10c

Disk image formats that wish to opt-out of version validation are supposed to set versionOffset to -1 in their fileTypeInfo entry. By unconditionally returning False for these formats, virStorageFileMatchesVersion() incorrectly reports a version mismatch when the test was actually skipped. The correct behavior is to return True so these formats can be successfully probed using the magic bytes alone. Signed-off-by: Adam Litke <agl@us.ibm.com> Acked-by: Eric Blake <eblake@redhat.com> --- src/util/storage_file.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/src/util/storage_file.c b/src/util/storage_file.c index 4098383..f8ab168 100644 --- a/src/util/storage_file.c +++ b/src/util/storage_file.c @@ -478,7 +478,7 @@ virStorageFileMatchesVersion(int format, /* Validate version number info */ if (fileTypeInfo[format].versionOffset == -1) - return false; + return true; if ((fileTypeInfo[format].versionOffset + 4) > buflen) return false; -- 1.7.3.2.164.g6f10c

Add an entry in fileTypeInfo for QED image files. Signed-off-by: Adam Litke <agl@us.ibm.com> Acked-by: Eric Blake <eblake@redhat.com> Cc: Stefan Hajnoczi <stefan.hajnoczi@uk.ibm.com> Cc: Anthony Liguori <aliguori@linux.vnet.ibm.com> --- src/util/storage_file.c | 10 +++++++++- src/util/storage_file.h | 1 + 2 files changed, 10 insertions(+), 1 deletions(-) diff --git a/src/util/storage_file.c b/src/util/storage_file.c index f8ab168..89c2cbe 100644 --- a/src/util/storage_file.c +++ b/src/util/storage_file.c @@ -43,7 +43,7 @@ VIR_ENUM_IMPL(virStorageFileFormat, VIR_STORAGE_FILE_LAST, "raw", "dir", "bochs", "cloop", "cow", "dmg", "iso", - "qcow", "qcow2", "vmdk", "vpc") + "qcow", "qcow2", "qed", "vmdk", "vpc") enum lv_endian { LV_LITTLE_ENDIAN = 1, /* 1234 */ @@ -104,6 +104,8 @@ static int vmdk4GetBackingStore(char **, int *, #define QCOW2_HDR_EXTENSION_END 0 #define QCOW2_HDR_EXTENSION_BACKING_FORMAT 0xE2792ACA +#define QED_HDR_IMAGE_SIZE (4+4+4+4+8+8+8) + /* VMDK needs at least this to find backing store, * other formats need less */ #define STORAGE_MAX_HEAD (20*512) @@ -151,6 +153,12 @@ static struct FileTypeInfo const fileTypeInfo[] = { LV_BIG_ENDIAN, 4, 2, QCOWX_HDR_IMAGE_SIZE, 8, 1, QCOW2_HDR_CRYPT, qcow2GetBackingStore, }, + [VIR_STORAGE_FILE_QED] = { + /* http://wiki.qemu.org/Features/QED */ + "QED\0", NULL, + LV_LITTLE_ENDIAN, -1, -1, + QED_HDR_IMAGE_SIZE, 8, 1, -1, NULL, + }, [VIR_STORAGE_FILE_VMDK] = { "KDMV", NULL, LV_LITTLE_ENDIAN, 4, 1, diff --git a/src/util/storage_file.h b/src/util/storage_file.h index a3703f5..c4d4650 100644 --- a/src/util/storage_file.h +++ b/src/util/storage_file.h @@ -38,6 +38,7 @@ enum virStorageFileFormat { VIR_STORAGE_FILE_ISO, VIR_STORAGE_FILE_QCOW, VIR_STORAGE_FILE_QCOW2, + VIR_STORAGE_FILE_QED, VIR_STORAGE_FILE_VMDK, VIR_STORAGE_FILE_VPC, VIR_STORAGE_FILE_LAST, -- 1.7.3.2.164.g6f10c

Signed-off-by: Adam Litke <agl@us.ibm.com> Acked-by: Eric Blake <eblake@redhat.com> --- src/conf/domain_conf.c | 4 ++++ src/util/storage_file.h | 1 + 2 files changed, 5 insertions(+), 0 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 2d11785..a08c846 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -7825,6 +7825,10 @@ int virDomainDiskDefForeachPath(virDomainDiskDefPtr disk, if (format == VIR_STORAGE_FILE_AUTO && !allowProbing) format = VIR_STORAGE_FILE_RAW; /* Stops further recursion */ + + /* Allow probing for image formats that are safe */ + if (format == VIR_STORAGE_FILE_AUTO_SAFE) + format = VIR_STORAGE_FILE_AUTO; } while (nextpath); ret = 0; diff --git a/src/util/storage_file.h b/src/util/storage_file.h index c4d4650..1eef4c5 100644 --- a/src/util/storage_file.h +++ b/src/util/storage_file.h @@ -28,6 +28,7 @@ # include <stdbool.h> enum virStorageFileFormat { + VIR_STORAGE_FILE_AUTO_SAFE = -2, VIR_STORAGE_FILE_AUTO = -1, VIR_STORAGE_FILE_RAW = 0, VIR_STORAGE_FILE_DIR, -- 1.7.3.2.164.g6f10c

Implement getBackingStore() for QED images. The header format is defined in the QED spec: http://wiki.qemu.org/Features/QED . Signed-off-by: Adam Litke <agl@us.ibm.com> Acked-by: Eric Blake <eblake@redhat.com> Cc: Stefan Hajnoczi <stefan.hajnoczi@uk.ibm.com> Cc: Anthony Liguori <aliguori@linux.vnet.ibm.com> --- src/util/storage_file.c | 78 +++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 76 insertions(+), 2 deletions(-) diff --git a/src/util/storage_file.c b/src/util/storage_file.c index 89c2cbe..9d97066 100644 --- a/src/util/storage_file.c +++ b/src/util/storage_file.c @@ -89,6 +89,8 @@ static int qcow2GetBackingStore(char **, int *, const unsigned char *, size_t); static int vmdk4GetBackingStore(char **, int *, const unsigned char *, size_t); +static int +qedGetBackingStore(char **, int *, const unsigned char *, size_t); #define QCOWX_HDR_VERSION (4) #define QCOWX_HDR_BACKING_FILE_OFFSET (QCOWX_HDR_VERSION+4) @@ -104,7 +106,12 @@ static int vmdk4GetBackingStore(char **, int *, #define QCOW2_HDR_EXTENSION_END 0 #define QCOW2_HDR_EXTENSION_BACKING_FORMAT 0xE2792ACA -#define QED_HDR_IMAGE_SIZE (4+4+4+4+8+8+8) +#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) +#define QED_HDR_BACKING_FILE_SIZE (QED_HDR_BACKING_FILE_OFFSET+4) +#define QED_F_BACKING_FILE 0x01 +#define QED_F_BACKING_FORMAT_NO_PROBE 0x04 /* VMDK needs at least this to find backing store, * other formats need less */ @@ -157,7 +164,7 @@ static struct FileTypeInfo const fileTypeInfo[] = { /* http://wiki.qemu.org/Features/QED */ "QED\0", NULL, LV_LITTLE_ENDIAN, -1, -1, - QED_HDR_IMAGE_SIZE, 8, 1, -1, NULL, + QED_HDR_IMAGE_SIZE, 8, 1, -1, qedGetBackingStore, }, [VIR_STORAGE_FILE_VMDK] = { "KDMV", NULL, @@ -417,6 +424,73 @@ cleanup: return ret; } +static unsigned long +qedGetHeaderUL(const unsigned char *loc) +{ + return ( ((unsigned long)loc[3] << 24) + | ((unsigned long)loc[2] << 16) + | ((unsigned long)loc[1] << 8) + | ((unsigned long)loc[0] << 0)); +} + +static unsigned long long +qedGetHeaderULL(const unsigned char *loc) +{ + return ( ((unsigned long)loc[7] << 56) + | ((unsigned long)loc[6] << 48) + | ((unsigned long)loc[5] << 40) + | ((unsigned long)loc[4] << 32) + | ((unsigned long)loc[3] << 24) + | ((unsigned long)loc[2] << 16) + | ((unsigned long)loc[1] << 8) + | ((unsigned long)loc[0] << 0)); +} + +static int +qedGetBackingStore(char **res, + int *format, + const unsigned char *buf, + size_t buf_size) +{ + unsigned long long flags; + unsigned long offset, size; + + *res = NULL; + /* Check if this image has a backing file */ + if (buf_size < QED_HDR_FEATURES_OFFSET+8) + return BACKING_STORE_INVALID; + flags = qedGetHeaderULL(buf + QED_HDR_FEATURES_OFFSET); + if (!(flags & QED_F_BACKING_FILE)) + return BACKING_STORE_OK; + + /* Parse the backing file */ + if (buf_size < QED_HDR_BACKING_FILE_OFFSET+8) + return BACKING_STORE_INVALID; + offset = qedGetHeaderUL(buf + QED_HDR_BACKING_FILE_OFFSET); + if (offset > buf_size) + return BACKING_STORE_INVALID; + size = qedGetHeaderUL(buf + QED_HDR_BACKING_FILE_SIZE); + if (size == 0) + return BACKING_STORE_OK; + if (offset + size > buf_size || offset + size < offset) + return BACKING_STORE_INVALID; + if (VIR_ALLOC_N(*res, size + 1) < 0) { + virReportOOMError(); + return BACKING_STORE_ERROR; + } + memcpy(*res, buf + offset, size); + (*res)[size] = '\0'; + + if (format) { + if (flags & QED_F_BACKING_FORMAT_NO_PROBE) + *format = VIR_STORAGE_FILE_RAW; + else + *format = VIR_STORAGE_FILE_AUTO_SAFE; + } + + return BACKING_STORE_OK; +} + /** * Return an absolute path corresponding to PATH, which is absolute or relative * to the directory containing BASE_FILE, or NULL on error -- 1.7.3.2.164.g6f10c

On 11/22/2010 09:23 AM, Adam Litke wrote:
Changes since V2: - VIR_STORAGE_FILE_AUTO_SAFE is not XML parsable - Break out QED header defines by field and add link to QED spec - Removed redundant overflow check in qedGetBackingStore
I had already applied your v1 series last week after folding in my suggested tweaks; would you mind rebasing this to provide just the subsequent patch(es) on top of what is already applied? -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

Sure, no problem. On Mon, 2010-11-22 at 09:41 -0700, Eric Blake wrote:
On 11/22/2010 09:23 AM, Adam Litke wrote:
Changes since V2: - VIR_STORAGE_FILE_AUTO_SAFE is not XML parsable - Break out QED header defines by field and add link to QED spec - Removed redundant overflow check in qedGetBackingStore
I had already applied your v1 series last week after folding in my suggested tweaks; would you mind rebasing this to provide just the subsequent patch(es) on top of what is already applied?
-- Thanks, Adam
participants (2)
-
Adam Litke
-
Eric Blake