[libvirt] [PATCH 0/2] Support the QED disk image format

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 (2): QED: Basic support for QED images Support for probing qed image metadata src/util/storage_file.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++- src/util/storage_file.h | 1 + 2 files changed, 85 insertions(+), 1 deletions(-) -- 1.7.3.2.164.g6f10c

Add an entry in fileTypeInfo for QED image files. Signed-off-by: Adam Litke <agl@us.ibm.com> Cc: Stefan Hajnoczi <stefan.hajnoczi@uk.ibm.com> Cc: Anthony Liguori <aliguori@linux.vnet.ibm.com> --- src/util/storage_file.c | 9 ++++++++- src/util/storage_file.h | 1 + 2 files changed, 9 insertions(+), 1 deletions(-) diff --git a/src/util/storage_file.c b/src/util/storage_file.c index 4098383..6e099ed 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 40 + /* VMDK needs at least this to find backing store, * other formats need less */ #define STORAGE_MAX_HEAD (20*512) @@ -151,6 +153,11 @@ static struct FileTypeInfo const fileTypeInfo[] = { LV_BIG_ENDIAN, 4, 2, QCOWX_HDR_IMAGE_SIZE, 8, 1, QCOW2_HDR_CRYPT, qcow2GetBackingStore, }, + [VIR_STORAGE_FILE_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

On Wed, Nov 17, 2010 at 01:52:41PM -0600, Adam Litke wrote:
Add an entry in fileTypeInfo for QED image files.
Signed-off-by: Adam Litke <agl@us.ibm.com> Cc: Stefan Hajnoczi <stefan.hajnoczi@uk.ibm.com> Cc: Anthony Liguori <aliguori@linux.vnet.ibm.com> --- src/util/storage_file.c | 9 ++++++++- src/util/storage_file.h | 1 + 2 files changed, 9 insertions(+), 1 deletions(-)
diff --git a/src/util/storage_file.c b/src/util/storage_file.c index 4098383..6e099ed 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 40 + /* VMDK needs at least this to find backing store, * other formats need less */ #define STORAGE_MAX_HEAD (20*512) @@ -151,6 +153,11 @@ static struct FileTypeInfo const fileTypeInfo[] = { LV_BIG_ENDIAN, 4, 2, QCOWX_HDR_IMAGE_SIZE, 8, 1, QCOW2_HDR_CRYPT, qcow2GetBackingStore, }, + [VIR_STORAGE_FILE_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,
ACK Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

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> 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, 77 insertions(+), 1 deletions(-) diff --git a/src/util/storage_file.c b/src/util/storage_file.c index 6e099ed..51ee0c8 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) @@ -105,6 +107,11 @@ static int vmdk4GetBackingStore(char **, int *, #define QCOW2_HDR_EXTENSION_BACKING_FORMAT 0xE2792ACA #define QED_HDR_IMAGE_SIZE 40 +#define QED_HDR_FEATURES_OFFSET 16 +#define QED_HDR_BACKING_FILE_OFFSET 56 +#define QED_HDR_BACKING_FILE_SIZE 60 +#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 */ @@ -156,7 +163,7 @@ static struct FileTypeInfo const fileTypeInfo[] = { [VIR_STORAGE_FILE_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, @@ -416,6 +423,75 @@ 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 (size + 1 == 0) + 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 = virStorageFileFormatTypeFromString("raw"); + else + *format = VIR_STORAGE_FILE_AUTO; + } + + 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 Wed, Nov 17, 2010 at 01:52:42PM -0600, Adam Litke wrote:
Implement getBackingStore() for QED images. The header format is defined in the QED spec: http://wiki.qemu.org/Features/QED .
+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 (size + 1 == 0) + 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 = virStorageFileFormatTypeFromString("raw"); + else + *format = VIR_STORAGE_FILE_AUTO; + } + + return BACKING_STORE_OK; +}
Setting *format = VIR_STORAGE_FILE_AUTO is going to make non-raw backing files unusuable in a out of the box libvirt configuration. libvirt will refuse to recurse into any backing file marked 'auto' for security reasons, treating them as raw. In virDomainDiskDefForeachPath from src/conf/domain_conf.c .... format = meta.backingStoreFormat; if (format == VIR_STORAGE_FILE_AUTO && !allowProbing) format = VIR_STORAGE_FILE_RAW; /* Stops further recursion */ } while (nextpath); The thing is that this QED format can do safe auto probing, so we need to distinguish it from formats which can't do safe auto probing. We probably need to add a separate SAFE_AUTO for this, and handle that case in src/conf/domain_conf.c by adding if (format == VIR_STORAGE_FILE_SAFE_AUTO) format = VIR_STORAGE_FILE_AUTO; in the end of that loop, which will allow it to continue the loop with probing for that backing store. Regards, Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
participants (2)
-
Adam Litke
-
Daniel P. Berrange