* [Qemu-devel] [PATCH 0/2] Introducing qcow2 extensions + keep backing file format @ 2009-03-03 14:33 Uri Lublin 2009-03-03 14:33 ` [Qemu-devel] [PATCH 1/2] " Uri Lublin 0 siblings, 1 reply; 5+ messages in thread From: Uri Lublin @ 2009-03-03 14:33 UTC (permalink / raw) To: qemu-devel; +Cc: Uri Lublin Qcow2 extensions are build of magic (id) len (in bytes) and data. They reside between the end of the header and the filename. We can keep the backing file format in a such a qcow2 extension, to 1. Provide a way to know the backing file format without probing it (setting the format at creation time). 2. Enable using qcow2 format over host block devices. (only if the user specifically asks for it, by providing the format at creation time). I've added bdrv_create2 and drv->bdrv_create2 (implemented only by block-qcow2 currently) to pass the backing-format to create. Based on a work done by Shahar Frank. Also fixes a security flaw found by Daniel P. Berrange on [1] which summarizes: "Autoprobing: just say no." [1] http://lists.gnu.org/archive/html/qemu-devel/2008-12/msg01083.html Changes from V4: old commented code deleted. fix temporary snapshot (e.g. -snapshot) support. Signed-off-by: Uri Lublin <uril@redhat.com> ^ permalink raw reply [flat|nested] 5+ messages in thread
* [Qemu-devel] [PATCH 1/2] Introducing qcow2 extensions + keep backing file format 2009-03-03 14:33 [Qemu-devel] [PATCH 0/2] Introducing qcow2 extensions + keep backing file format Uri Lublin @ 2009-03-03 14:33 ` Uri Lublin 2009-03-03 14:33 ` [Qemu-devel] [PATCH 2/2] qemu-img: adding a "-F base_fmt" option to "qemu-img create -b" Uri Lublin 0 siblings, 1 reply; 5+ messages in thread From: Uri Lublin @ 2009-03-03 14:33 UTC (permalink / raw) To: qemu-devel; +Cc: Uri Lublin Qcow2 extensions are build of magic (id) len (in bytes) and data. They reside between the end of the header and the filename. We can keep the backing file format in a such a qcow2 extension, to 1. Provide a way to know the backing file format without probing it (setting the format at creation time). 2. Enable using qcow2 format over host block devices. (only if the user specifically asks for it, by providing the format at creation time). I've added bdrv_create2 and drv->bdrv_create2 (implemented only by block-qcow2 currently) to pass the backing-format to create. Based on a work done by Shahar Frank. Also fixes a security flaw found by Daniel P. Berrange on [1] which summarizes: "Autoprobing: just say no." [1] http://lists.gnu.org/archive/html/qemu-devel/2008-12/msg01083.html Signed-off-by: Uri Lublin <uril@redhat.com> --- block-qcow2.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- block.c | 29 +++++++++++++-- block.h | 4 ++ block_int.h | 6 +++ 4 files changed, 141 insertions(+), 6 deletions(-) diff --git a/block-qcow2.c b/block-qcow2.c index 465dcd6..222d423 100644 --- a/block-qcow2.c +++ b/block-qcow2.c @@ -45,6 +45,7 @@ //#define DEBUG_ALLOC //#define DEBUG_ALLOC2 +//#define DEBUG_EXT #define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb) #define QCOW_VERSION 2 @@ -77,6 +78,14 @@ typedef struct QCowHeader { uint64_t snapshots_offset; } QCowHeader; + +typedef struct { + uint32_t magic; + uint32_t len; +} QCowExtension; +#define QCOW_EXT_MAGIC_END 0 +#define QCOW_EXT_MAGIC_BACKING_FORMAT 0xE2792ACA + typedef struct __attribute__((packed)) QCowSnapshotHeader { /* header is 8 byte aligned */ uint64_t l1_table_offset; @@ -189,6 +198,66 @@ static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename) return 0; } + +/* read qcow2 extension and fill bs + * start reading from start_offset + * finish reading upon magic of value 0 or when end_offset reached + * unknown magic is skipped (future extension this version knows nothing about) + * return 0 upon success, non-0 otherwise + */ +static int qcow_read_extensions(BlockDriverState *bs, uint64_t start_offset, + uint64_t end_offset) +{ + BDRVQcowState *s = bs->opaque; + QCowExtension ext; + uint64_t offset; + +#ifdef DEBUG_EXT + printf("qcow_read_extensions: start=%ld end=%ld\n", start_offset, end_offset); +#endif + offset = start_offset; + while (offset < end_offset) { + +#ifdef DEBUG_EXT + /* Sanity check */ + if (offset >= s->cluster_size) + printf("qcow_handle_extension: suspicious offset %lu\n", offset); + + printf("attemting to read extended header in offset %lu\n", offset); +#endif + + if (bdrv_pread(s->hd, offset, &ext, sizeof(ext)) != sizeof(ext)) { + fprintf(stderr, "qcow_handle_extension: ERROR: pread fail from offset %lu\n", + offset); + return 1; + } + be32_to_cpus(&ext.magic); + be32_to_cpus(&ext.len); + offset += sizeof(ext); + switch (ext.magic) { + case QCOW_EXT_MAGIC_END: + break; + case QCOW_EXT_MAGIC_BACKING_FORMAT: + if (ext.len >= sizeof(bs->backing_format)) { + fprintf(stderr, "ERROR: ext_backing_format: len=%u too large" + " (>=%lu)\n", + ext.len, sizeof(bs->backing_format)); + return 2; + } + if (bdrv_pread(s->hd, offset , bs->backing_format, + ext.len) != ext.len) + return 3; + bs->backing_format[ext.len] = '\0'; +#ifdef DEBUG_EXT + printf("Qcow2: Got format extension %s\n", bs->backing_format); +#endif + offset += ((ext.len + 7) & ~7); + } + } + + return 0; +} + static int qcow_open(BlockDriverState *bs, const char *filename, int flags) { BDRVQcowState *s = bs->opaque; @@ -278,6 +347,10 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags) scan_refcount(bs, &s->highest_alloc, &s->nc_free); + /* read qcow2 extensions */ + if (qcow_read_extensions(bs, sizeof(header), header.backing_file_offset)) + goto fail; + /* read the backing file name */ if (header.backing_file_offset != 0) { len = header.backing_file_size; @@ -1462,13 +1535,17 @@ static void create_refcount_update(QCowCreateState *s, } } -static int qcow_create(const char *filename, int64_t total_size, - const char *backing_file, int flags) +static int qcow_create2(const char *filename, int64_t total_size, + const char *backing_file, const char *backing_format, + int flags) { int fd, header_size, backing_filename_len, l1_size, i, shift, l2_bits; + int backing_format_len = 0; QCowHeader header; uint64_t tmp, offset; QCowCreateState s1, *s = &s1; + QCowExtension ext = {0, 0}; + memset(s, 0, sizeof(*s)); @@ -1482,6 +1559,12 @@ static int qcow_create(const char *filename, int64_t total_size, header_size = sizeof(header); backing_filename_len = 0; if (backing_file) { + if (backing_format) { + ext.magic = QCOW_EXT_MAGIC_BACKING_FORMAT; + backing_format_len = strlen(backing_format); + ext.len = (backing_format_len + 7) & ~7; + header_size += ((sizeof(ext) + ext.len + 7) & ~7); + } header.backing_file_offset = cpu_to_be64(header_size); backing_filename_len = strlen(backing_file); header.backing_file_size = cpu_to_be32(backing_filename_len); @@ -1526,6 +1609,19 @@ static int qcow_create(const char *filename, int64_t total_size, /* write all the data */ write(fd, &header, sizeof(header)); if (backing_file) { + if (backing_format_len) { + char zero[16]; + int d = ext.len - backing_format_len; + + memset(zero, 0, sizeof(zero)); + cpu_to_be32s(&ext.magic); + cpu_to_be32s(&ext.len); + write(fd, &ext, sizeof(ext)); + write(fd, backing_format, backing_format_len); + if (d>0) { + write(fd, zero, d); + } + } write(fd, backing_file, backing_filename_len); } lseek(fd, s->l1_table_offset, SEEK_SET); @@ -1545,6 +1641,12 @@ static int qcow_create(const char *filename, int64_t total_size, return 0; } +static int qcow_create(const char *filename, int64_t total_size, + const char *backing_file, int flags) +{ + return qcow_create2(filename, total_size, backing_file, NULL, flags); +} + static int qcow_make_empty(BlockDriverState *bs) { #if 0 @@ -2670,4 +2772,6 @@ BlockDriver bdrv_qcow2 = { .bdrv_snapshot_delete = qcow_snapshot_delete, .bdrv_snapshot_list = qcow_snapshot_list, .bdrv_get_info = qcow_get_info, + + .bdrv_create2 = qcow_create2, }; diff --git a/block.c b/block.c index 4f4bf7c..0939cad 100644 --- a/block.c +++ b/block.c @@ -172,6 +172,20 @@ BlockDriver *bdrv_find_format(const char *format_name) return NULL; } +int bdrv_create2(BlockDriver *drv, + const char *filename, int64_t size_in_sectors, + const char *backing_file, const char *backing_format, + int flags) +{ + if (drv->bdrv_create2) + return drv->bdrv_create2(filename, size_in_sectors, backing_file, + backing_format, flags); + if (drv->bdrv_create) + return drv->bdrv_create(filename, size_in_sectors, backing_file, + flags); + return -ENOTSUP; +} + int bdrv_create(BlockDriver *drv, const char *filename, int64_t size_in_sectors, const char *backing_file, int flags) @@ -351,7 +365,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, if (!bs1) { return -ENOMEM; } - if (bdrv_open(bs1, filename, 0) < 0) { + if (bdrv_open2(bs1, filename, 0, drv) < 0) { bdrv_delete(bs1); return -1; } @@ -371,11 +385,14 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, else realpath(filename, backing_filename); - if (bdrv_create(&bdrv_qcow2, tmp_filename, - total_size, backing_filename, 0) < 0) { + if (bdrv_create2(&bdrv_qcow2, tmp_filename, + total_size, backing_filename, + (drv ? drv->format_name : NULL), + 0) < 0) { return -1; } filename = tmp_filename; + drv = &bdrv_qcow2; bs->is_temporary = 1; } @@ -420,6 +437,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, #endif if (bs->backing_file[0] != '\0') { /* if there is a backing file, use it */ + BlockDriver *back_drv = NULL; bs->backing_hd = bdrv_new(""); if (!bs->backing_hd) { fail: @@ -428,7 +446,10 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, } path_combine(backing_filename, sizeof(backing_filename), filename, bs->backing_file); - if (bdrv_open(bs->backing_hd, backing_filename, open_flags) < 0) + if (bs->backing_format) + back_drv = bdrv_find_format(bs->backing_format); + if (bdrv_open2(bs->backing_hd, backing_filename, open_flags, + back_drv) < 0) goto fail; } diff --git a/block.h b/block.h index e1927dd..e19fd8f 100644 --- a/block.h +++ b/block.h @@ -64,6 +64,10 @@ BlockDriver *bdrv_find_format(const char *format_name); int bdrv_create(BlockDriver *drv, const char *filename, int64_t size_in_sectors, const char *backing_file, int flags); +int bdrv_create2(BlockDriver *drv, + const char *filename, int64_t size_in_sectors, + const char *backing_file, const char *backing_format, + int flags); BlockDriverState *bdrv_new(const char *device_name); void bdrv_delete(BlockDriverState *bs); int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags); diff --git a/block_int.h b/block_int.h index 781789c..8c373ff 100644 --- a/block_int.h +++ b/block_int.h @@ -85,6 +85,11 @@ struct BlockDriver { /* to control generic scsi devices */ int (*bdrv_ioctl)(BlockDriverState *bs, unsigned long int req, void *buf); + /* new create with backing file format */ + int (*bdrv_create2)(const char *filename, int64_t total_sectors, + const char *backing_file, const char *backing_format, + int flags); + BlockDriverAIOCB *free_aiocb; struct BlockDriver *next; }; @@ -107,6 +112,7 @@ struct BlockDriverState { char filename[1024]; char backing_file[1024]; /* if non zero, the image is a diff of this file image */ + char backing_format[16]; /* if non-zero and backing_file exists */ int is_temporary; int media_changed; -- 1.6.0.6 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* [Qemu-devel] [PATCH 2/2] qemu-img: adding a "-F base_fmt" option to "qemu-img create -b" 2009-03-03 14:33 ` [Qemu-devel] [PATCH 1/2] " Uri Lublin @ 2009-03-03 14:33 ` Uri Lublin 0 siblings, 0 replies; 5+ messages in thread From: Uri Lublin @ 2009-03-03 14:33 UTC (permalink / raw) To: qemu-devel; +Cc: Uri Lublin If the user specifies the backing file format, then when opening the backing file, there is no need to probe the (backing file) image to figure out its format. This follows my previous patch implementing bdrv_create2 which keeps (for qcow2 only) the backing file format as a qcow2-extension Suggested by Daniel P. Berrange. Signed-off-by: Uri Lublin <uril@redhat.com> --- qemu-img.c | 24 ++++++++++++++++++++---- qemu-img.texi | 4 +++- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index d83ffe3..2cf0e1f 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -25,6 +25,7 @@ #include "osdep.h" #include "block_int.h" #include <assert.h> +#include <stdio.h> #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN @@ -58,7 +59,7 @@ static void help(void) "QEMU disk image utility\n" "\n" "Command syntax:\n" - " create [-e] [-6] [-b base_image] [-f fmt] filename [size]\n" + " create [-e] [-6] [-F fmt] [-b base_image] [-f fmt] filename [size]\n" " commit [-f fmt] filename\n" " convert [-c] [-e] [-6] [-f fmt] [-O output_fmt] [-B output_base_image] filename [filename2 [...]] output_filename\n" " info [-f fmt] filename\n" @@ -218,6 +219,7 @@ static int img_create(int argc, char **argv) { int c, ret, flags; const char *fmt = "raw"; + const char *base_fmt = NULL; const char *filename; const char *base_filename = NULL; uint64_t size; @@ -226,13 +228,16 @@ static int img_create(int argc, char **argv) flags = 0; for(;;) { - c = getopt(argc, argv, "b:f:he6"); + c = getopt(argc, argv, "F:b:f:he6"); if (c == -1) break; switch(c) { case 'h': help(); break; + case 'F': + base_fmt = optarg; + break; case 'b': base_filename = optarg; break; @@ -253,7 +258,15 @@ static int img_create(int argc, char **argv) size = 0; if (base_filename) { BlockDriverState *bs; - bs = bdrv_new_open(base_filename, NULL); + BlockDriver *base_drv = NULL; + + if (base_fmt) { + base_drv = bdrv_find_format(base_fmt); + if (base_drv == NULL) + error("Unknown basefile format '%s'", base_fmt); + } + + bs = bdrv_new_open(base_filename, base_fmt); bdrv_get_geometry(bs, &size); size *= 512; bdrv_delete(bs); @@ -284,9 +297,12 @@ static int img_create(int argc, char **argv) if (base_filename) { printf(", backing_file=%s", base_filename); + if (base_fmt) + printf(", backing_fmt=%s", + base_fmt); } printf(", size=%" PRIu64 " kB\n", size / 1024); - ret = bdrv_create(drv, filename, size / 512, base_filename, flags); + ret = bdrv_create2(drv, filename, size / 512, base_filename, base_fmt, flags); if (ret < 0) { if (ret == -ENOTSUP) { error("Formatting or formatting option not supported for file format '%s'", fmt); diff --git a/qemu-img.texi b/qemu-img.texi index a40f841..deef2ab 100644 --- a/qemu-img.texi +++ b/qemu-img.texi @@ -8,7 +8,7 @@ usage: qemu-img command [command options] The following commands are supported: @table @option -@item create [-e] [-6] [-b @var{base_image}] [-f @var{fmt}] @var{filename} [@var{size}] +@item create [-e] [-6] [-F @var{base_fmt}] [-b @var{base_image}] [-f @var{fmt}] @var{filename} [@var{size}] @item commit [-f @var{fmt}] @var{filename} @item convert [-c] [-e] [-6] [-f @var{fmt}] [-O @var{output_fmt}] [-B @var{output_base_image}] @var{filename} [@var{filename2} [...]] @var{output_filename} @item info [-f @var{fmt}] @var{filename} @@ -27,6 +27,8 @@ forces the output image to be created as a copy on write image of the specified base image; @code{output_base_image} should have the same content as the input's base image, however the path, image format, etc may differ +@item base_fmt +is the disk image format of @var{base_image}. for more information look at @var{fmt} @item fmt is the disk image format. It is guessed automatically in most cases. The following formats are supported: -- 1.6.0.6 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* [Qemu-devel] [PATCH For Review 0/2] qemu block changes: keep backing file format v3 @ 2009-02-04 16:08 Uri Lublin 2009-02-04 16:08 ` Uri Lublin 0 siblings, 1 reply; 5+ messages in thread From: Uri Lublin @ 2009-02-04 16:08 UTC (permalink / raw) To: qemu-devel; +Cc: Uri Lublin This is another implementation for keeping a backing file format, such that we would not need probing to figure it out. This time I introduce qcow2 extensions which can be used in the future. I using one such an extension to keeping the backing file format, and use it when opening a file. Qcow2 extensions are build of magic (id) len (in bytes) and data. They reside between the end of the header and the filename. We keep the backing file format in a such a qcow2 extension, to 1. Provide a way to know the backing file format without probing it (setting the format at creation time). 2. Enable using qcow2 format over host block devices. (only if the user specifically asks for it, by providing the format at creation time). I've added bdrv_create2 and drv->bdrv_create2 (implemented only by block-qcow2 currently) to pass the backing-format to create. Based on a work done by Shahar Frank. Also fixes a security flaw found by Daniel P. Berrange on [1] which summarizes: "Autoprobing: just say no." [1] http://lists.gnu.org/archive/html/qemu-devel/2008-12/msg01083.html First patch implements qcow2 extensions + bdrv_create2 Second patch modifies qemu-img such that the user can use it. Currently this is implemented only for qcow2, but touches code in some block*.[ch] files. An alternative that touches only block-qcow2.c is possible, but will need to change the implementation of -snapshot, and call bdrv_open2 directly from qcow_open. Please review, Thanks, Uri. ^ permalink raw reply [flat|nested] 5+ messages in thread
* [Qemu-devel] [PATCH For Review 0/2] qemu block changes: keep backing file format v3 2009-02-04 16:08 [Qemu-devel] [PATCH For Review 0/2] qemu block changes: keep backing file format v3 Uri Lublin @ 2009-02-04 16:08 ` Uri Lublin 2009-02-04 16:08 ` [Qemu-devel] [PATCH 1/2] Introducing qcow2 extensions + keep backing file format Uri Lublin 0 siblings, 1 reply; 5+ messages in thread From: Uri Lublin @ 2009-02-04 16:08 UTC (permalink / raw) To: qemu-devel; +Cc: Uri Lublin This is another implementation for keeping a backing file format, such that we would not need probing to figure it out. This time I introduce qcow2 extensions which can be used in the future. I assing one such an extension to keeping the backing file format, and use it when opening a file. Qcow2 extensions are build of magic (id) len (in bytes) and data. They reside between the end of the header and the filename. We keep the backing file format in a such a qcow2 extension, to 1. Provide a way to know the backing file format without probing it (setting the format at creation time). 2. Enable using qcow2 format over host block devices. (only if the user specifically asks for it, by providing the format at creation time). I've added bdrv_create2 and drv->bdrv_create2 (implemented only by block-qcow2 currently) to pass the backing-format to create. Based on a work done by Shahar Frank. Also fixes a security flaw found by Daniel P. Berrange on [1] which summarizes: "Autoprobing: just say no." [1] http://lists.gnu.org/archive/html/qemu-devel/2008-12/msg01083.html Currently this is implemented only for qcow2, but touches code in some block*.[ch] files. An alternative that touches only block-qcow2.c is possible, but will need to change the implementation of -snapshot, and call bdrv_open2 directly from qcow_open. Please review, Thanks, Uri. ^ permalink raw reply [flat|nested] 5+ messages in thread
* [Qemu-devel] [PATCH 1/2] Introducing qcow2 extensions + keep backing file format 2009-02-04 16:08 ` Uri Lublin @ 2009-02-04 16:08 ` Uri Lublin 2009-02-04 16:08 ` [Qemu-devel] [PATCH 2/2] qemu-img: adding a "-F base_fmt" option to "qemu-img create -b" Uri Lublin 0 siblings, 1 reply; 5+ messages in thread From: Uri Lublin @ 2009-02-04 16:08 UTC (permalink / raw) To: qemu-devel; +Cc: Uri Lublin Qcow2 extensions are build of magic (id) len (in bytes) and data. They reside between the end of the header and the filename. We can keep the backing file format in a such a qcow2 extension, to 1. Provide a way to know the backing file format without probing it (setting the format at creation time). 2. Enable using qcow2 format over host block devices. (only if the user specifically asks for it, by providing the format at creation time). I've added bdrv_create2 and drv->bdrv_create2 (implemented only by block-qcow2 currently) to pass the backing-format to create. Based on a work done by Shahar Frank. Also fixes a security flaw found by Daniel P. Berrange on [1] which summarizes: "Autoprobing: just say no." [1] http://lists.gnu.org/archive/html/qemu-devel/2008-12/msg01083.html Signed-off-by: Uri Lublin <uril@redhat.com> --- block-qcow2.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- block.c | 29 +++++++++++++- block.h | 4 ++ block_int.h | 6 +++ 4 files changed, 149 insertions(+), 5 deletions(-) diff --git a/block-qcow2.c b/block-qcow2.c index 8a5b621..d2263d5 100644 --- a/block-qcow2.c +++ b/block-qcow2.c @@ -45,6 +45,7 @@ //#define DEBUG_ALLOC //#define DEBUG_ALLOC2 +//#define DEBUG_EXT #define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb) #define QCOW_VERSION 2 @@ -77,6 +78,21 @@ typedef struct QCowHeader { uint64_t snapshots_offset; } QCowHeader; + +typedef struct { + /* + * Alternatives: + * should I make them uint64_t ? + * should I add version ? + * should I use a single magic and add type field ? + * should I keep number-of-extenstions ? + */ + uint32_t magic; + uint32_t len; +} QCowExtension; +#define QCOW_EXT_MAGIC_END 0 +#define QCOW_EXT_MAGIC_BACKING_FORMAT 0xE2792ACA + typedef struct __attribute__((packed)) QCowSnapshotHeader { /* header is 8 byte aligned */ uint64_t l1_table_offset; @@ -189,6 +205,66 @@ static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename) return 0; } + +/* read qcow2 extension and fill bs + * start reading from start_offset + * finish reading upon magic of value 0 or when end_offset reached + * unknown magic is skipped (future extension this version knows nothing about) + * return 0 upon success, non-0 otherwise + */ +static int qcow_read_extensions(BlockDriverState *bs, uint64_t start_offset, + uint64_t end_offset) +{ + BDRVQcowState *s = bs->opaque; + QCowExtension ext; + uint64_t offset; + +#ifdef DEBUG_EXT + printf("qcow_read_extensions: start=%ld end=%ld\n", start_offset, end_offset); +#endif + offset = start_offset; + while (offset < end_offset) { + +#ifdef DEBUG_EXT + /* Sanity check */ + if (offset >= s->cluster_size) + printf("qcow_handle_extension: suspicious offset %lu\n", offset); + + printf("attemting to read extended header in offset %lu\n", offset); +#endif + + if (bdrv_pread(s->hd, offset, &ext, sizeof(ext)) != sizeof(ext)) { + fprintf(stderr, "qcow_handle_extension: ERROR: pread fail from offset %lu\n", + offset); + return 1; + } + be32_to_cpus(&ext.magic); + be32_to_cpus(&ext.len); + offset += sizeof(ext); + switch (ext.magic) { + case QCOW_EXT_MAGIC_END: + break; + case QCOW_EXT_MAGIC_BACKING_FORMAT: + if (ext.len >= sizeof(bs->backing_format)) { + fprintf(stderr, "ERROR: ext_backing_format: len=%u too large" + " (>=%lu)\n", + ext.len, sizeof(bs->backing_format)); + return 2; + } + if (bdrv_pread(s->hd, offset , bs->backing_format, + ext.len) != ext.len) + return 3; + bs->backing_format[ext.len] = '\0'; +#ifdef DEBUG_EXT + printf("Qcow2: Got format extension %s\n", bs->backing_format); +#endif + offset += ((ext.len + 7) & ~7); + } + } + + return 0; +} + static int qcow_open(BlockDriverState *bs, const char *filename, int flags) { BDRVQcowState *s = bs->opaque; @@ -286,6 +362,10 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags) scan_refcount(bs, &s->highest_alloc, &s->nc_free); + /* read qcow2 extensions */ + if (qcow_read_extensions(bs, sizeof(header), header.backing_file_offset)) + goto fail; + /* read the backing file name */ if (header.backing_file_offset != 0) { len = header.backing_file_size; @@ -1477,13 +1557,17 @@ static void create_refcount_update(QCowCreateState *s, } } -static int qcow_create(const char *filename, int64_t total_size, - const char *backing_file, int flags) +static int qcow_create2(const char *filename, int64_t total_size, + const char *backing_file, const char *backing_format, + int flags) { int fd, header_size, backing_filename_len, l1_size, i, shift, l2_bits; + int backing_format_len = 0; QCowHeader header; uint64_t tmp, offset; QCowCreateState s1, *s = &s1; + QCowExtension ext = {0, 0}; + memset(s, 0, sizeof(*s)); @@ -1497,6 +1581,12 @@ static int qcow_create(const char *filename, int64_t total_size, header_size = sizeof(header); backing_filename_len = 0; if (backing_file) { + if (backing_format) { + ext.magic = QCOW_EXT_MAGIC_BACKING_FORMAT; + backing_format_len = strlen(backing_format); + ext.len = (backing_format_len + 7) & ~7; + header_size += ((sizeof(ext) + ext.len + 7) & ~7); + } header.backing_file_offset = cpu_to_be64(header_size); backing_filename_len = strlen(backing_file); header.backing_file_size = cpu_to_be32(backing_filename_len); @@ -1545,6 +1635,19 @@ static int qcow_create(const char *filename, int64_t total_size, /* write all the data */ write(fd, &header, sizeof(header)); if (backing_file) { + if (backing_format_len) { + char zero[16]; + int d = ext.len - backing_format_len; + + memset(zero, 0, sizeof(zero)); + cpu_to_be32s(&ext.magic); + cpu_to_be32s(&ext.len); + write(fd, &ext, sizeof(ext)); + write(fd, backing_format, backing_format_len); + if (d>0) { + write(fd, zero, d); + } + } write(fd, backing_file, backing_filename_len); } lseek(fd, s->l1_table_offset, SEEK_SET); @@ -1569,6 +1672,12 @@ static int qcow_create(const char *filename, int64_t total_size, return -ENOMEM; } +static int qcow_create(const char *filename, int64_t total_size, + const char *backing_file, int flags) +{ + return qcow_create2(filename, total_size, backing_file, NULL, flags); +} + static int qcow_make_empty(BlockDriverState *bs) { #if 0 @@ -2726,4 +2835,6 @@ BlockDriver bdrv_qcow2 = { .bdrv_snapshot_delete = qcow_snapshot_delete, .bdrv_snapshot_list = qcow_snapshot_list, .bdrv_get_info = qcow_get_info, + + .bdrv_create2 = qcow_create2, }; diff --git a/block.c b/block.c index b3d2f12..368948c 100644 --- a/block.c +++ b/block.c @@ -174,6 +174,20 @@ BlockDriver *bdrv_find_format(const char *format_name) return NULL; } +int bdrv_create2(BlockDriver *drv, + const char *filename, int64_t size_in_sectors, + const char *backing_file, const char *backing_format, + int flags) +{ + if (drv->bdrv_create2) + return drv->bdrv_create2(filename, size_in_sectors, backing_file, + backing_format, flags); + if (drv->bdrv_create) + return drv->bdrv_create(filename, size_in_sectors, backing_file, + flags); + return -ENOTSUP; +} + int bdrv_create(BlockDriver *drv, const char *filename, int64_t size_in_sectors, const char *backing_file, int flags) @@ -350,6 +364,9 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, /* if there is a backing file, use it */ bs1 = bdrv_new(""); +/* if (drv) */ +/* pstrcpy(bs1->backing_format, sizeof(bs->backing_format), */ +/* drv->format_name); */ if (!bs1) { return -ENOMEM; } @@ -373,8 +390,10 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, else realpath(filename, backing_filename); - if (bdrv_create(&bdrv_qcow2, tmp_filename, - total_size, backing_filename, 0) < 0) { + if (bdrv_create2(&bdrv_qcow2, tmp_filename, + total_size, backing_filename, + (drv ? drv->format_name : NULL), + 0) < 0) { return -1; } filename = tmp_filename; @@ -424,6 +443,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, #endif if (bs->backing_file[0] != '\0') { /* if there is a backing file, use it */ + BlockDriver *back_drv = NULL; bs->backing_hd = bdrv_new(""); if (!bs->backing_hd) { fail: @@ -432,7 +452,10 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, } path_combine(backing_filename, sizeof(backing_filename), filename, bs->backing_file); - if (bdrv_open(bs->backing_hd, backing_filename, open_flags) < 0) + if (bs->backing_format) + back_drv = bdrv_find_format(bs->backing_format); + if (bdrv_open2(bs->backing_hd, backing_filename, open_flags, + back_drv) < 0) goto fail; } diff --git a/block.h b/block.h index e1927dd..e19fd8f 100644 --- a/block.h +++ b/block.h @@ -64,6 +64,10 @@ BlockDriver *bdrv_find_format(const char *format_name); int bdrv_create(BlockDriver *drv, const char *filename, int64_t size_in_sectors, const char *backing_file, int flags); +int bdrv_create2(BlockDriver *drv, + const char *filename, int64_t size_in_sectors, + const char *backing_file, const char *backing_format, + int flags); BlockDriverState *bdrv_new(const char *device_name); void bdrv_delete(BlockDriverState *bs); int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags); diff --git a/block_int.h b/block_int.h index e83fd2c..349f66e 100644 --- a/block_int.h +++ b/block_int.h @@ -85,6 +85,11 @@ struct BlockDriver { /* to control generic scsi devices */ int (*bdrv_ioctl)(BlockDriverState *bs, unsigned long int req, void *buf); + /* new create with backing file format */ + int (*bdrv_create2)(const char *filename, int64_t total_sectors, + const char *backing_file, const char *backing_format, + int flags); + BlockDriverAIOCB *free_aiocb; struct BlockDriver *next; }; @@ -107,6 +112,7 @@ struct BlockDriverState { char filename[1024]; char backing_file[1024]; /* if non zero, the image is a diff of this file image */ + char backing_format[16]; /* if non-zero and backing_file exists */ int is_temporary; int media_changed; -- 1.6.0.6 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* [Qemu-devel] [PATCH 2/2] qemu-img: adding a "-F base_fmt" option to "qemu-img create -b" 2009-02-04 16:08 ` [Qemu-devel] [PATCH 1/2] Introducing qcow2 extensions + keep backing file format Uri Lublin @ 2009-02-04 16:08 ` Uri Lublin 0 siblings, 0 replies; 5+ messages in thread From: Uri Lublin @ 2009-02-04 16:08 UTC (permalink / raw) To: qemu-devel; +Cc: Uri Lublin If the user specifies the backing file format, then when opening the backing file, there is no need to probe the (backing file) image to figure out its format. This follows my previous patch implementing bdrv_create2 which keeps (for qcow2 only) the backing file format as a qcow2-extension Suggested by Daniel P. Berrange. Signed-off-by: Uri Lublin <uril@redhat.com> --- qemu-img.c | 24 ++++++++++++++++++++---- qemu-img.texi | 4 +++- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index 6b852fb..2cb97e1 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -25,6 +25,7 @@ #include "osdep.h" #include "block_int.h" #include <assert.h> +#include <stdio.h> #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN @@ -58,7 +59,7 @@ static void help(void) "QEMU disk image utility\n" "\n" "Command syntax:\n" - " create [-e] [-6] [-b base_image] [-f fmt] filename [size]\n" + " create [-e] [-6] [-F fmt] [-b base_image] [-f fmt] filename [size]\n" " commit [-f fmt] filename\n" " convert [-c] [-e] [-6] [-f fmt] [-O output_fmt] [-B output_base_image] filename [filename2 [...]] output_filename\n" " info [-f fmt] filename\n" @@ -218,6 +219,7 @@ static int img_create(int argc, char **argv) { int c, ret, flags; const char *fmt = "raw"; + const char *base_fmt = NULL; const char *filename; const char *base_filename = NULL; uint64_t size; @@ -226,13 +228,16 @@ static int img_create(int argc, char **argv) flags = 0; for(;;) { - c = getopt(argc, argv, "b:f:he6"); + c = getopt(argc, argv, "F:b:f:he6"); if (c == -1) break; switch(c) { case 'h': help(); break; + case 'F': + base_fmt = optarg; + break; case 'b': base_filename = optarg; break; @@ -253,7 +258,15 @@ static int img_create(int argc, char **argv) size = 0; if (base_filename) { BlockDriverState *bs; - bs = bdrv_new_open(base_filename, NULL); + BlockDriver *base_drv = NULL; + + if (base_fmt) { + base_drv = bdrv_find_format(base_fmt); + if (base_drv == NULL) + error("Unknown basefile format '%s'", base_fmt); + } + + bs = bdrv_new_open(base_filename, base_fmt); bdrv_get_geometry(bs, &size); size *= 512; bdrv_delete(bs); @@ -284,9 +297,12 @@ static int img_create(int argc, char **argv) if (base_filename) { printf(", backing_file=%s", base_filename); + if (base_fmt) + printf(", backing_fmt=%s", + base_fmt); } printf(", size=%" PRIu64 " kB\n", size / 1024); - ret = bdrv_create(drv, filename, size / 512, base_filename, flags); + ret = bdrv_create2(drv, filename, size / 512, base_filename, base_fmt, flags); if (ret < 0) { if (ret == -ENOTSUP) { error("Formatting or formatting option not supported for file format '%s'", fmt); diff --git a/qemu-img.texi b/qemu-img.texi index a40f841..deef2ab 100644 --- a/qemu-img.texi +++ b/qemu-img.texi @@ -8,7 +8,7 @@ usage: qemu-img command [command options] The following commands are supported: @table @option -@item create [-e] [-6] [-b @var{base_image}] [-f @var{fmt}] @var{filename} [@var{size}] +@item create [-e] [-6] [-F @var{base_fmt}] [-b @var{base_image}] [-f @var{fmt}] @var{filename} [@var{size}] @item commit [-f @var{fmt}] @var{filename} @item convert [-c] [-e] [-6] [-f @var{fmt}] [-O @var{output_fmt}] [-B @var{output_base_image}] @var{filename} [@var{filename2} [...]] @var{output_filename} @item info [-f @var{fmt}] @var{filename} @@ -27,6 +27,8 @@ forces the output image to be created as a copy on write image of the specified base image; @code{output_base_image} should have the same content as the input's base image, however the path, image format, etc may differ +@item base_fmt +is the disk image format of @var{base_image}. for more information look at @var{fmt} @item fmt is the disk image format. It is guessed automatically in most cases. The following formats are supported: -- 1.6.0.6 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* [Qemu-devel] [PATCH 0/2] qemu block changes: keep backing file format v2 @ 2009-01-26 18:39 Uri Lublin 2009-01-26 18:39 ` [Qemu-devel] [PATCH 1/2] Introducing hidden image format in backing file name Uri Lublin 0 siblings, 1 reply; 5+ messages in thread From: Uri Lublin @ 2009-01-26 18:39 UTC (permalink / raw) To: qemu-devel; +Cc: Uri Lublin The purpose of this patches is to keep the backing file format together with its name, to 1. Provide a way to know the backing file format without probing it (setting the format at creation time). 2. Enable using qcow2 format (and others) over host block devices. (only if the user specifically asks for it, by providing the format). I call "hidden image format" to the following format of a backing file name: "name\0format". Although it can be considered a hack, that's an easy way to support old images with new qemu as well as old qemu with new images (in which case probing would be done), without changing the qcow2 header. If a hidden format exists, use it for the backing file. If no hidden format (or an unknown one) exists we go back to probing. Based on a previous patch from Shahar Frank. http://lists.gnu.org/archive/html/qemu-devel/2008-12/msg01083.html The "name\0format" was suggested by Kevin Wolf on the above thread. Also fixes a security flaw found by Daniel P. Berrange on that same thread which summarizes: "Autoprobing: just say no." The first patch introduces the hidden image format. The second patch enable the user to specify the image format for the backing file upon image creation. Changes from v1: use "name\0format" instead of "fmt:FMT:name" Examples: ### Let /dev/loop0 and /dev/loop1 be qemu-images of format qcow2 and raw. ### 1. Specify qcow2 backing file. demonstrates qcow2 over host block device # ./qemu-img create -F qcow2 -b /dev/loop0 -f qcow2 /tmp/u0.qcow2 Formatting '/tmp/u0.qcow2', fmt=qcow2, backing_file=/dev/loop0, backing_fmt=qcow2, size=20971520 kB # ./x86_64-softmmu/qemu-system-x86_64 -L pc-bios/ -drive file=/tmp/u0.qcow2,format=qcow2 Works with no probing. ### 2. Specify raw backing file. # ./qemu-img create -F raw -b /dev/loop1 -f qcow2 /tmp/u1.qcow2 Formatting '/tmp/u1.qcow2', fmt=qcow2, backing_file=/dev/loop1, backing_fmt=raw, size=307200 kB ### 3. Do not specify backing file format (qcow2). ### Probing of /dev/loop0 "finds" a "host_device" format (instead of qcow2) ### and results with the guest fails to boot. ### Note: wrong size upon create. # ./qemu-img create -b /dev/loop0 -f qcow2 /tmp/p0.qcow2 Formatting '/tmp/p0.qcow2', fmt=qcow2, backing_file=/dev/loop0, size=4245292 kB # ./x86_64-softmmu/qemu-system-x86_64 -L pc-bios/ -drive file=/tmp/p0.qcow2,format=qcow2 Probing /dev/loop0 and guest fails to boot. ### 4. Do not specify backing file format (raw). ### Probing of /dev/loop1 "finds" a "host_device" format ### and results with the guest successfully boot. ### If however a VM with /dev/loop1 is was previously started and the guest ### modified the beginning of the file (writing a fake qcow2 header) ### there is a security problem as the guest user can now access almost ### any file on the host (e.g. /etc/passwd). # ./qemu-img create -b /dev/loop1 -f qcow2 /tmp/p1.qcow2 Formatting '/tmp/p1.qcow2', fmt=qcow2, backing_file=/dev/loop1, size=307200 kB # ./x86_64-softmmu/qemu-system-x86_64 -L pc-bios/ -drive file=/tmp/p1.qcow2,format=qcow2 Works with probing. ^ permalink raw reply [flat|nested] 5+ messages in thread
* [Qemu-devel] [PATCH 1/2] Introducing hidden image format in backing file name. 2009-01-26 18:39 [Qemu-devel] [PATCH 0/2] qemu block changes: keep backing file format v2 Uri Lublin @ 2009-01-26 18:39 ` Uri Lublin 2009-01-26 18:39 ` Uri Lublin 0 siblings, 1 reply; 5+ messages in thread From: Uri Lublin @ 2009-01-26 18:39 UTC (permalink / raw) To: qemu-devel; +Cc: Uri Lublin The purpose of this patches is to keep the backing file format together with its name, to 1. Provide a way to know the backing file format without probing it (setting the format at creation time). 2. Enable using qcow2 format (and others) over host block devices. (only if the user specifically asks for it, by providing the format). I call "hidden image format" to the following format of a backing file name: "name\0format". Although it can be considered a hack, that's an easy way to support old images with new qemu as well as old qemu with new images (in which case probing would be done), without changing the qcow2 header. If a hidden format exists, use it for the backing file. If no hidden format (or an unknown one) exists we go back to probing. Based on a previous patch from Shahar Frank. http://lists.gnu.org/archive/html/qemu-devel/2008-12/msg01083.html The "name\0format" was suggested by Kevin Wolf on the above thread. Also fixes a security flaw found by Daniel P. Berrange on that same thread which summarizes: "Autoprobing: just say no." Signed-off-by: Uri Lublin <uril@redhat.com> --- block-qcow2.c | 5 +++++ block.c | 27 ++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletions(-) diff --git a/block-qcow2.c b/block-qcow2.c index 8a5b621..4b46b84 100644 --- a/block-qcow2.c +++ b/block-qcow2.c @@ -1499,6 +1499,11 @@ static int qcow_create(const char *filename, int64_t total_size, if (backing_file) { header.backing_file_offset = cpu_to_be64(header_size); backing_filename_len = strlen(backing_file); + + /* account for hidden format */ + if (backing_file[backing_filename_len + 1] != '\0') + backing_filename_len += strlen(backing_file + + backing_filename_len + 1) + 1; header.backing_file_size = cpu_to_be32(backing_filename_len); header_size += backing_filename_len; } diff --git a/block.c b/block.c index 50ec589..b43debc 100644 --- a/block.c +++ b/block.c @@ -254,6 +254,23 @@ static BlockDriver *find_protocol(const char *filename) return NULL; } +/* + * if a hidden file format exist, returns it's appropriate drv + * otherwise returns NULL + */ +static BlockDriver* get_backing_file_format(const char *filename) +{ + BlockDriver *drv = NULL; + int len; + + /* Support hidden format in filename: "name\0format\0" */ + len = strlen(filename); + if (filename[len + 1] != '\0') + drv = bdrv_find_format(filename + len + 1); + return drv; +} + + /* XXX: force raw format if block or character device ? It would simplify the BSD case */ static BlockDriver *find_image_format(const char *filename) @@ -263,6 +280,11 @@ static BlockDriver *find_image_format(const char *filename) uint8_t buf[2048]; BlockDriverState *bs; + /* first check for hidden format */ + drv = get_backing_file_format(filename); + if (drv) + return drv; + /* detect host devices. By convention, /dev/cdrom[N] is always recognized as a host CDROM */ if (strstart(filename, "/dev/cdrom", NULL)) @@ -423,6 +445,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, } #endif if (bs->backing_file[0] != '\0') { + BlockDriver *backing_drv ; /* if there is a backing file, use it */ bs->backing_hd = bdrv_new(""); if (!bs->backing_hd) { @@ -430,9 +453,11 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, bdrv_close(bs); return -ENOMEM; } + backing_drv = get_backing_file_format(bs->backing_file); path_combine(backing_filename, sizeof(backing_filename), filename, bs->backing_file); - if (bdrv_open(bs->backing_hd, backing_filename, open_flags) < 0) + if (bdrv_open2(bs->backing_hd, backing_filename, open_flags, + backing_drv) < 0) goto fail; } -- 1.6.0.6 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* [Qemu-devel] [PATCH 1/2] Introducing hidden image format in backing file name. 2009-01-26 18:39 ` [Qemu-devel] [PATCH 1/2] Introducing hidden image format in backing file name Uri Lublin @ 2009-01-26 18:39 ` Uri Lublin 2009-01-26 18:39 ` [Qemu-devel] [PATCH 2/2] qemu-img: adding a "-F base_fmt" option to "qemu-img create -b" Uri Lublin 0 siblings, 1 reply; 5+ messages in thread From: Uri Lublin @ 2009-01-26 18:39 UTC (permalink / raw) To: qemu-devel; +Cc: Uri Lublin The purpose of this patch is to 1. Provide a way to know the backing file format without probing it (setting the format at creation time). 2. Enable using qcow2 format (and others) over host block devices. (only if the user specifically asks for it, by providing the format). If no hidden format (or an unknown one) is provided we go back to probing. I call "hidden image format" to the following format of a backing file name: "name\0format". Although it can be considered a hack, that's an easy way to support old images with new qemu as well as old qemu with new images (in which case probing would be done), without changing the qcow2 header. Based on a previous patch from Shahar Frank. http://lists.gnu.org/archive/html/qemu-devel/2008-12/msg01083.html The "name\0format" was suggested by Kevin Wolf on the above thread. Also fixes a security flaw found by Daniel P. Berrange on that same thread which summarizes: "Autoprobing: just say no." Signed-off-by: Uri Lublin <uril@redhat.com> --- block-qcow2.c | 5 +++++ block.c | 27 ++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletions(-) diff --git a/block-qcow2.c b/block-qcow2.c index 8a5b621..4b46b84 100644 --- a/block-qcow2.c +++ b/block-qcow2.c @@ -1499,6 +1499,11 @@ static int qcow_create(const char *filename, int64_t total_size, if (backing_file) { header.backing_file_offset = cpu_to_be64(header_size); backing_filename_len = strlen(backing_file); + + /* account for hidden format */ + if (backing_file[backing_filename_len + 1] != '\0') + backing_filename_len += strlen(backing_file + + backing_filename_len + 1) + 1; header.backing_file_size = cpu_to_be32(backing_filename_len); header_size += backing_filename_len; } diff --git a/block.c b/block.c index 50ec589..b43debc 100644 --- a/block.c +++ b/block.c @@ -254,6 +254,23 @@ static BlockDriver *find_protocol(const char *filename) return NULL; } +/* + * if a hidden file format exist, returns it's appropriate drv + * otherwise returns NULL + */ +static BlockDriver* get_backing_file_format(const char *filename) +{ + BlockDriver *drv = NULL; + int len; + + /* Support hidden format in filename: "name\0format\0" */ + len = strlen(filename); + if (filename[len + 1] != '\0') + drv = bdrv_find_format(filename + len + 1); + return drv; +} + + /* XXX: force raw format if block or character device ? It would simplify the BSD case */ static BlockDriver *find_image_format(const char *filename) @@ -263,6 +280,11 @@ static BlockDriver *find_image_format(const char *filename) uint8_t buf[2048]; BlockDriverState *bs; + /* first check for hidden format */ + drv = get_backing_file_format(filename); + if (drv) + return drv; + /* detect host devices. By convention, /dev/cdrom[N] is always recognized as a host CDROM */ if (strstart(filename, "/dev/cdrom", NULL)) @@ -423,6 +445,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, } #endif if (bs->backing_file[0] != '\0') { + BlockDriver *backing_drv ; /* if there is a backing file, use it */ bs->backing_hd = bdrv_new(""); if (!bs->backing_hd) { @@ -430,9 +453,11 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, bdrv_close(bs); return -ENOMEM; } + backing_drv = get_backing_file_format(bs->backing_file); path_combine(backing_filename, sizeof(backing_filename), filename, bs->backing_file); - if (bdrv_open(bs->backing_hd, backing_filename, open_flags) < 0) + if (bdrv_open2(bs->backing_hd, backing_filename, open_flags, + backing_drv) < 0) goto fail; } -- 1.6.0.6 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* [Qemu-devel] [PATCH 2/2] qemu-img: adding a "-F base_fmt" option to "qemu-img create -b" 2009-01-26 18:39 ` Uri Lublin @ 2009-01-26 18:39 ` Uri Lublin 0 siblings, 0 replies; 5+ messages in thread From: Uri Lublin @ 2009-01-26 18:39 UTC (permalink / raw) To: qemu-devel; +Cc: Uri Lublin If the user specifies the backing file format, then when opening the backing file, there is no need to probe the (backing file) image to figure out its format. This follows my previous patch implementing hidden image format within the backing file name. Suggested by Daniel P. Berrange. Signed-off-by: Uri Lublin <uril@redhat.com> --- qemu-img.c | 33 ++++++++++++++++++++++++++++++--- qemu-img.texi | 4 +++- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index 6b852fb..29e5f45 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -25,6 +25,7 @@ #include "osdep.h" #include "block_int.h" #include <assert.h> +#include <stdio.h> #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN @@ -58,7 +59,7 @@ static void help(void) "QEMU disk image utility\n" "\n" "Command syntax:\n" - " create [-e] [-6] [-b base_image] [-f fmt] filename [size]\n" + " create [-e] [-6] [-F fmt] [-b base_image] [-f fmt] filename [size]\n" " commit [-f fmt] filename\n" " convert [-c] [-e] [-6] [-f fmt] [-O output_fmt] [-B output_base_image] filename [filename2 [...]] output_filename\n" " info [-f fmt] filename\n" @@ -218,21 +219,26 @@ static int img_create(int argc, char **argv) { int c, ret, flags; const char *fmt = "raw"; + const char *base_fmt = NULL; const char *filename; const char *base_filename = NULL; uint64_t size; const char *p; BlockDriver *drv; + char filename_buff[1024]; flags = 0; for(;;) { - c = getopt(argc, argv, "b:f:he6"); + c = getopt(argc, argv, "F:b:f:he6"); if (c == -1) break; switch(c) { case 'h': help(); break; + case 'F': + base_fmt = optarg; + break; case 'b': base_filename = optarg; break; @@ -253,7 +259,15 @@ static int img_create(int argc, char **argv) size = 0; if (base_filename) { BlockDriverState *bs; - bs = bdrv_new_open(base_filename, NULL); + BlockDriver *base_drv = NULL; + + if (base_fmt) { + base_drv = bdrv_find_format(base_fmt); + if (base_drv == NULL) + error("Unknown basefile format '%s'", base_fmt); + } + + bs = bdrv_new_open(base_filename, base_fmt); bdrv_get_geometry(bs, &size); size *= 512; bdrv_delete(bs); @@ -284,8 +298,21 @@ static int img_create(int argc, char **argv) if (base_filename) { printf(", backing_file=%s", base_filename); + if (base_fmt) + printf(", backing_fmt=%s", + base_fmt); } printf(", size=%" PRIu64 " kB\n", size / 1024); + if (base_filename) { + memset(filename_buff, 0, sizeof(filename_buff)); + pstrcpy(filename_buff, sizeof(filename_buff), base_filename); + if (base_fmt) { + int len; + len = strlen(filename_buff); + pstrcat(filename_buff + len + 1, sizeof(filename_buff) - (len + 1), base_fmt); + } + base_filename = filename_buff; + } ret = bdrv_create(drv, filename, size / 512, base_filename, flags); if (ret < 0) { if (ret == -ENOTSUP) { diff --git a/qemu-img.texi b/qemu-img.texi index a40f841..deef2ab 100644 --- a/qemu-img.texi +++ b/qemu-img.texi @@ -8,7 +8,7 @@ usage: qemu-img command [command options] The following commands are supported: @table @option -@item create [-e] [-6] [-b @var{base_image}] [-f @var{fmt}] @var{filename} [@var{size}] +@item create [-e] [-6] [-F @var{base_fmt}] [-b @var{base_image}] [-f @var{fmt}] @var{filename} [@var{size}] @item commit [-f @var{fmt}] @var{filename} @item convert [-c] [-e] [-6] [-f @var{fmt}] [-O @var{output_fmt}] [-B @var{output_base_image}] @var{filename} [@var{filename2} [...]] @var{output_filename} @item info [-f @var{fmt}] @var{filename} @@ -27,6 +27,8 @@ forces the output image to be created as a copy on write image of the specified base image; @code{output_base_image} should have the same content as the input's base image, however the path, image format, etc may differ +@item base_fmt +is the disk image format of @var{base_image}. for more information look at @var{fmt} @item fmt is the disk image format. It is guessed automatically in most cases. The following formats are supported: -- 1.6.0.6 ^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2009-03-03 14:35 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2009-03-03 14:33 [Qemu-devel] [PATCH 0/2] Introducing qcow2 extensions + keep backing file format Uri Lublin 2009-03-03 14:33 ` [Qemu-devel] [PATCH 1/2] " Uri Lublin 2009-03-03 14:33 ` [Qemu-devel] [PATCH 2/2] qemu-img: adding a "-F base_fmt" option to "qemu-img create -b" Uri Lublin -- strict thread matches above, loose matches on Subject: below -- 2009-02-04 16:08 [Qemu-devel] [PATCH For Review 0/2] qemu block changes: keep backing file format v3 Uri Lublin 2009-02-04 16:08 ` Uri Lublin 2009-02-04 16:08 ` [Qemu-devel] [PATCH 1/2] Introducing qcow2 extensions + keep backing file format Uri Lublin 2009-02-04 16:08 ` [Qemu-devel] [PATCH 2/2] qemu-img: adding a "-F base_fmt" option to "qemu-img create -b" Uri Lublin 2009-01-26 18:39 [Qemu-devel] [PATCH 0/2] qemu block changes: keep backing file format v2 Uri Lublin 2009-01-26 18:39 ` [Qemu-devel] [PATCH 1/2] Introducing hidden image format in backing file name Uri Lublin 2009-01-26 18:39 ` Uri Lublin 2009-01-26 18:39 ` [Qemu-devel] [PATCH 2/2] qemu-img: adding a "-F base_fmt" option to "qemu-img create -b" Uri Lublin
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).