Re: [Qemu-devel] [PATCH v6] block:add-cow file format
Okay, I will consider your suggestion in version 7. Thank you Marcelo and Stefan, :). On Fri, Jan 6, 2012 at 16:22, Stefan Hajnoczi wrote: > On Thu, Jan 05, 2012 at 01:46:08PM -0200, Marcelo Tosatti wrote: > > On Thu, Dec 29, 2011 at 05:36:59PM +0800, Dong Xu Wang wrote: > > > From: Dong Xu Wang > > > > > > Introduce a new file format: add-cow. The usage can be found in > add-cow.txt of > > > this patch. > > > > > > CC: Kevin Wolf > > > CC: Stefan Hajnoczi > > > Signed-off-by: Dong Xu Wang > > > --- > > > After applying this patch, qemu might can not compile, need apply this > patch first: > > > http://lists.gnu.org/archive/html/qemu-devel/2011-12/msg02527.html > > > > > > Makefile.objs |1 + > > > block.c|2 +- > > > block.h|1 + > > > block/add-cow.c| 429 > > > > block_int.h|1 + > > > docs/specs/add-cow.txt | 72 > > > 6 files changed, 505 insertions(+), 1 deletions(-) > > > create mode 100644 block/add-cow.c > > > create mode 100644 docs/specs/add-cow.txt > > > > > > > > > > +s->bitmap_size = ((bs->total_sectors + 7) >> 3); > > > +s->bitmap = qemu_blockalign(bs, s->bitmap_size); > > > + > > > +ret = bdrv_pread(bs->file, sizeof(header), s->bitmap, > > > +s->bitmap_size); > > > +if (ret != s->bitmap_size) { > > > +goto fail; > > > +} > > > > As noted previously, it is not acceptable to read the entire bitmap in > > memory since it might be very large. A cache, which limits the in-memory > > size of the bitmap, must be created. In the qcow2-cache.c file you can > > find an example (thats for qcow2 metadata cache). You can divide the > > bitmap in chunks of say, 4k, and have: > > > > int is_bit_set(int64_t bitnum, BlockDriverState *bs) > > { > > int64_t bitmap_entry = bitnum >> bits_per_entry; > > > > if (!is_in_bitmap_cache(bs, bitmap_entry)) > > read_from_disk(bs, bitmap_entry); > > > > return lookup_bitmap_cache(bs, bitnum); > > } > > > > And then limit the cache to a few megabytes. > > > > Also when setting a bit you must update cache and write > > to disk. > > I suspect it's also better to increase the bitmap granularity. The > bitmap should track allocation at a larger "cluster" size like 64 KB. > That way we reduce the number of I/O operations required to update > metadata - it reduces the amount of metadata by a factor of 65536 / 512 > = 128. > > If you imagine a random write workload with 4 KB block size there is an > advantage to a 64 KB cluster size since later I/Os may require no bitmap > updates where we already allocated a cluster in an earlier operation. > > The downside of a larger bitmap granularity is that writes are increased > to 64 KB, but if you run a benchmark I guess there is a threshold around > 32 or 64 KB where the reduction in I/O operations makes up for the > larger I/O size. It depends on your disks. > > Stefan > > >
Re: [Qemu-devel] [PATCH v6] block:add-cow file format
On Thu, Jan 05, 2012 at 01:46:08PM -0200, Marcelo Tosatti wrote: > On Thu, Dec 29, 2011 at 05:36:59PM +0800, Dong Xu Wang wrote: > > From: Dong Xu Wang > > > > Introduce a new file format: add-cow. The usage can be found in add-cow.txt > > of > > this patch. > > > > CC: Kevin Wolf > > CC: Stefan Hajnoczi > > Signed-off-by: Dong Xu Wang > > --- > > After applying this patch, qemu might can not compile, need apply this > > patch first: > > http://lists.gnu.org/archive/html/qemu-devel/2011-12/msg02527.html > > > > Makefile.objs |1 + > > block.c|2 +- > > block.h|1 + > > block/add-cow.c| 429 > > > > block_int.h|1 + > > docs/specs/add-cow.txt | 72 > > 6 files changed, 505 insertions(+), 1 deletions(-) > > create mode 100644 block/add-cow.c > > create mode 100644 docs/specs/add-cow.txt > > > > > > +s->bitmap_size = ((bs->total_sectors + 7) >> 3); > > +s->bitmap = qemu_blockalign(bs, s->bitmap_size); > > + > > +ret = bdrv_pread(bs->file, sizeof(header), s->bitmap, > > +s->bitmap_size); > > +if (ret != s->bitmap_size) { > > +goto fail; > > +} > > As noted previously, it is not acceptable to read the entire bitmap in > memory since it might be very large. A cache, which limits the in-memory > size of the bitmap, must be created. In the qcow2-cache.c file you can > find an example (thats for qcow2 metadata cache). You can divide the > bitmap in chunks of say, 4k, and have: > > int is_bit_set(int64_t bitnum, BlockDriverState *bs) > { > int64_t bitmap_entry = bitnum >> bits_per_entry; > > if (!is_in_bitmap_cache(bs, bitmap_entry)) > read_from_disk(bs, bitmap_entry); > > return lookup_bitmap_cache(bs, bitnum); > } > > And then limit the cache to a few megabytes. > > Also when setting a bit you must update cache and write > to disk. I suspect it's also better to increase the bitmap granularity. The bitmap should track allocation at a larger "cluster" size like 64 KB. That way we reduce the number of I/O operations required to update metadata - it reduces the amount of metadata by a factor of 65536 / 512 = 128. If you imagine a random write workload with 4 KB block size there is an advantage to a 64 KB cluster size since later I/Os may require no bitmap updates where we already allocated a cluster in an earlier operation. The downside of a larger bitmap granularity is that writes are increased to 64 KB, but if you run a benchmark I guess there is a threshold around 32 or 64 KB where the reduction in I/O operations makes up for the larger I/O size. It depends on your disks. Stefan
Re: [Qemu-devel] [PATCH v6] block:add-cow file format
On Thu, Dec 29, 2011 at 05:36:59PM +0800, Dong Xu Wang wrote: > From: Dong Xu Wang > > Introduce a new file format: add-cow. The usage can be found in add-cow.txt of > this patch. > > CC: Kevin Wolf > CC: Stefan Hajnoczi > Signed-off-by: Dong Xu Wang > --- > After applying this patch, qemu might can not compile, need apply this patch > first: > http://lists.gnu.org/archive/html/qemu-devel/2011-12/msg02527.html > > Makefile.objs |1 + > block.c|2 +- > block.h|1 + > block/add-cow.c| 429 > > block_int.h|1 + > docs/specs/add-cow.txt | 72 > 6 files changed, 505 insertions(+), 1 deletions(-) > create mode 100644 block/add-cow.c > create mode 100644 docs/specs/add-cow.txt > > +s->bitmap_size = ((bs->total_sectors + 7) >> 3); > +s->bitmap = qemu_blockalign(bs, s->bitmap_size); > + > +ret = bdrv_pread(bs->file, sizeof(header), s->bitmap, > +s->bitmap_size); > +if (ret != s->bitmap_size) { > +goto fail; > +} As noted previously, it is not acceptable to read the entire bitmap in memory since it might be very large. A cache, which limits the in-memory size of the bitmap, must be created. In the qcow2-cache.c file you can find an example (thats for qcow2 metadata cache). You can divide the bitmap in chunks of say, 4k, and have: int is_bit_set(int64_t bitnum, BlockDriverState *bs) { int64_t bitmap_entry = bitnum >> bits_per_entry; if (!is_in_bitmap_cache(bs, bitmap_entry)) read_from_disk(bs, bitmap_entry); return lookup_bitmap_cache(bs, bitnum); } And then limit the cache to a few megabytes. Also when setting a bit you must update cache and write to disk. > + > +if (s->image_file[0] == '\0') { > +ret = -ENOENT; > +goto fail; > +} > + > +ret = bdrv_file_open(&backing_bs, bs->backing_file, 0); > +if (ret < 0) { > +return ret; > +} > +bdrv_delete(backing_bs); > + > +s->image_hd = bdrv_new(""); > + > +if (path_has_protocol(s->image_file)) { > +pstrcpy(image_filename, sizeof(image_filename), > +s->image_file); > +} else { > +path_combine(image_filename, sizeof(image_filename), > + bs->filename, s->image_file); > +} > + > +image_drv = bdrv_find_format("raw"); > +ret = bdrv_open(s->image_hd, image_filename, flags, image_drv); > +if (ret < 0) { > +bdrv_delete(s->image_hd); > +s->image_hd = NULL; > +goto fail; > +} Please make sure it is possible to create a snapshot with the snapshot_blkdev command, of a raw image. It is necessary for live block copy, as described here: http://patchwork.ozlabs.org/patch/134257/ Also please update that document, later, with raw examples. Thanks
Re: [Qemu-devel] [PATCH v6] block:add-cow file format
On Sat, Dec 31, 2011 at 9:17 AM, Dong Xu Wang wrote: > On Fri, Dec 30, 2011 at 22:09, Stefan Hajnoczi wrote: >> On Thu, Dec 29, 2011 at 05:36:59PM +0800, Dong Xu Wang wrote: >> > + ret = bdrv_file_open(&backing_bs, bs->backing_file, 0); >> > + if (ret < 0) { >> > + return ret; >> > + } >> > + bdrv_delete(backing_bs); >> >> What does this do? (It leaks s->bitmap when it fails.) > > > I wanna make sure backing_file exists while opening. block.c:bdrv_open() opens the backing file after .bdrv_open() has returned. It fails if the backing file does not exist. There's no need to duplicate this. >> > + s->image_hd = bdrv_new(""); >> > + >> > + if (path_has_protocol(s->image_file)) { >> > + pstrcpy(image_filename, sizeof(image_filename), >> > + s->image_file); >> > + } else { >> > + path_combine(image_filename, sizeof(image_filename), >> > + bs->filename, s->image_file); >> > + } >> > + >> > + image_drv = bdrv_find_format("raw"); >> > + ret = bdrv_open(s->image_hd, image_filename, flags, image_drv); >> > + if (ret < 0) { >> > + bdrv_delete(s->image_hd); >> > + s->image_hd = NULL; >> > + goto fail; >> > + } >> >> TODO If you were wondering why I put "TODO" here it's because I had some thoughts when reviewing but didn't fully investigate it yet. When I send the rest of my feedback I'll include my comment here. (I should have removed this before replying :)) >> > + 1036 - 2059: image_file >> > + image_file is a raw file, While using >> > image_file, must >> > + together with image_file. All unused bytes are >> > padded >> >> "While using image_file, must together with image_file" >> >> What does this mean? > > > I mean while using add-cow, must together with image_file and backing_file. > Both of them can not be missing. > Errors with sentences like that, I will correct them in v7. That sounds like qemu-img create behavior which should not be part of the file format specification. The only impact on the file format speficiation is that backing_file can be an empty string but image_file must always be a valid filename.
Re: [Qemu-devel] [PATCH v6] block:add-cow file format
On Fri, Dec 30, 2011 at 22:09, Stefan Hajnoczi wrote: > On Thu, Dec 29, 2011 at 05:36:59PM +0800, Dong Xu Wang wrote: > > Some comments on everything but the I/O path, which I haven't reviewed > yet: > > > diff --git a/block/add-cow.c b/block/add-cow.c > > new file mode 100644 > > index 000..95af5b7 > > --- /dev/null > > +++ b/block/add-cow.c > > @@ -0,0 +1,429 @@ > > Missing GPL or LGPL license header. > > > +#include "qemu-common.h" > > +#include "block_int.h" > > +#include "module.h" > > + > > +#define ADD_COW_MAGIC (((uint64_t)'A' << 56) | ((uint64_t)'D' << > 48) | \ > > +((uint64_t)'D' << 40) | ((uint64_t)'_' << > 32) | \ > > +((uint64_t)'C' << 24) | ((uint64_t)'O' << > 16) | \ > > +((uint64_t)'W' << 8) | 0xFF) > > +#define ADD_COW_VERSION 1 > > +#define ADD_COW_FILE_LEN1024 > > + > > +typedef struct AddCowHeader { > > +uint64_tmagic; > > +uint32_tversion; > > +charbacking_file[ADD_COW_FILE_LEN]; > > +charimage_file[ADD_COW_FILE_LEN]; > > +uint64_tsize; > > +charreserved[492]; > > +} QEMU_PACKED AddCowHeader; > > + > > +typedef struct BDRVAddCowState { > > +charimage_file[ADD_COW_FILE_LEN]; > > Why is this field needed? > > Yes, not needed. > > > +BlockDriverState*image_hd; > > +uint8_t *bitmap; > > +uint64_tbitmap_size; > > +CoMutex lock; > > +} BDRVAddCowState; > > + > > +static int add_cow_probe(const uint8_t *buf, int buf_size, const char > *filename) > > +{ > > +const AddCowHeader *header = (const void *)buf; > > + > > +if (be64_to_cpu(header->magic) == ADD_COW_MAGIC && > > +be32_to_cpu(header->version) == ADD_COW_VERSION) { > > +return 100; > > +} else { > > +return 0; > > +} > > +} > > + > > +static int add_cow_open(BlockDriverState *bs, int flags) > > +{ > > +AddCowHeaderheader; > > +int64_t size; > > +charimage_filename[ADD_COW_FILE_LEN]; > > +BlockDriver *image_drv = NULL; > > +int ret; > > +BDRVAddCowState *s = bs->opaque; > > +BlockDriverState*backing_bs = NULL; > > + > > +ret = bdrv_pread(bs->file, 0, &header, sizeof(header)); > > +if (ret != sizeof(header)) { > > +goto fail; > > +} > > + > > +if (be64_to_cpu(header.magic) != ADD_COW_MAGIC) { > > +ret = -EINVAL; > > +goto fail; > > +} > > +if (be32_to_cpu(header.version) != ADD_COW_VERSION) { > > +char version[64]; > > +snprintf(version, sizeof(version), "ADD-COW version %d", > header.version); > > +qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE, > > +bs->device_name, "add-cow", version); > > +ret = -ENOTSUP; > > +goto fail; > > +} > > + > > +size = be64_to_cpu(header.size); > > +bs->total_sectors = size / BDRV_SECTOR_SIZE; > > + > > +QEMU_BUILD_BUG_ON(sizeof(bs->backing_file) != > sizeof(header.backing_file)); > > +QEMU_BUILD_BUG_ON(sizeof(s->image_file) != > sizeof(header.image_file)); > > +pstrcpy(bs->backing_file, sizeof(bs->backing_file), > > +header.backing_file); > > +pstrcpy(s->image_file, sizeof(s->image_file), > > +header.image_file); > > This assumes that header.backing_file and header.image_file is > NUL-terminated. If the file happened to have the magic number and > version but does not include '\0' bytes in the header.backing_file then > we may crash here when trying to read beyond the end of the header > struct. > > Image format code should be robust. Please use strncpy(3) carefully > instead of pstrcpy(). > > Also please update the file format specification to either make these > fields NUL-terminated or NUL-terminated unless the length is 1024 > characters (in which case there is no NUL but the string still ends). > Okay. > > > + > > +s->bitmap_size = ((bs->total_sectors + 7) >> 3); > > +s->bitmap = qemu_blockalign(bs, s->bitmap_size); > > + > > +ret = bdrv_pread(bs->file, sizeof(header), s->bitmap, > > +s->bitmap_size); > > +if (ret != s->bitmap_size) { > > +goto fail; > > +} > > + > > +if (s->image_file[0] == '\0') { > > +ret = -ENOENT; > > +goto fail; > > +} > > + > > +ret = bdrv_file_open(&backing_bs, bs->backing_file, 0); > > +if (ret < 0) { > > +return ret; > > +} > > +bdrv_delete(backing_bs); > > What does this do? (It leaks s->bitmap when it fails.) > I wanna make sure backing_file exists while opening. > > > + > > +s->image_hd = bdrv_new(""); > > + > > +if (path_has_protocol(s->image_file)) { > > +pstrcpy(image_filename, sizeof(image_filename), > > +s->image_file); > > +} else { > > +path_combine(image_filename, sizeof(image_filename)
Re: [Qemu-devel] [PATCH v6] block:add-cow file format
On Thu, Dec 29, 2011 at 05:36:59PM +0800, Dong Xu Wang wrote: Some comments on everything but the I/O path, which I haven't reviewed yet: > diff --git a/block/add-cow.c b/block/add-cow.c > new file mode 100644 > index 000..95af5b7 > --- /dev/null > +++ b/block/add-cow.c > @@ -0,0 +1,429 @@ Missing GPL or LGPL license header. > +#include "qemu-common.h" > +#include "block_int.h" > +#include "module.h" > + > +#define ADD_COW_MAGIC (((uint64_t)'A' << 56) | ((uint64_t)'D' << 48) | > \ > +((uint64_t)'D' << 40) | ((uint64_t)'_' << 32) | \ > +((uint64_t)'C' << 24) | ((uint64_t)'O' << 16) | \ > +((uint64_t)'W' << 8) | 0xFF) > +#define ADD_COW_VERSION 1 > +#define ADD_COW_FILE_LEN1024 > + > +typedef struct AddCowHeader { > +uint64_tmagic; > +uint32_tversion; > +charbacking_file[ADD_COW_FILE_LEN]; > +charimage_file[ADD_COW_FILE_LEN]; > +uint64_tsize; > +charreserved[492]; > +} QEMU_PACKED AddCowHeader; > + > +typedef struct BDRVAddCowState { > +charimage_file[ADD_COW_FILE_LEN]; Why is this field needed? > +BlockDriverState*image_hd; > +uint8_t *bitmap; > +uint64_tbitmap_size; > +CoMutex lock; > +} BDRVAddCowState; > + > +static int add_cow_probe(const uint8_t *buf, int buf_size, const char > *filename) > +{ > +const AddCowHeader *header = (const void *)buf; > + > +if (be64_to_cpu(header->magic) == ADD_COW_MAGIC && > +be32_to_cpu(header->version) == ADD_COW_VERSION) { > +return 100; > +} else { > +return 0; > +} > +} > + > +static int add_cow_open(BlockDriverState *bs, int flags) > +{ > +AddCowHeaderheader; > +int64_t size; > +charimage_filename[ADD_COW_FILE_LEN]; > +BlockDriver *image_drv = NULL; > +int ret; > +BDRVAddCowState *s = bs->opaque; > +BlockDriverState*backing_bs = NULL; > + > +ret = bdrv_pread(bs->file, 0, &header, sizeof(header)); > +if (ret != sizeof(header)) { > +goto fail; > +} > + > +if (be64_to_cpu(header.magic) != ADD_COW_MAGIC) { > +ret = -EINVAL; > +goto fail; > +} > +if (be32_to_cpu(header.version) != ADD_COW_VERSION) { > +char version[64]; > +snprintf(version, sizeof(version), "ADD-COW version %d", > header.version); > +qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE, > +bs->device_name, "add-cow", version); > +ret = -ENOTSUP; > +goto fail; > +} > + > +size = be64_to_cpu(header.size); > +bs->total_sectors = size / BDRV_SECTOR_SIZE; > + > +QEMU_BUILD_BUG_ON(sizeof(bs->backing_file) != > sizeof(header.backing_file)); > +QEMU_BUILD_BUG_ON(sizeof(s->image_file) != sizeof(header.image_file)); > +pstrcpy(bs->backing_file, sizeof(bs->backing_file), > +header.backing_file); > +pstrcpy(s->image_file, sizeof(s->image_file), > +header.image_file); This assumes that header.backing_file and header.image_file is NUL-terminated. If the file happened to have the magic number and version but does not include '\0' bytes in the header.backing_file then we may crash here when trying to read beyond the end of the header struct. Image format code should be robust. Please use strncpy(3) carefully instead of pstrcpy(). Also please update the file format specification to either make these fields NUL-terminated or NUL-terminated unless the length is 1024 characters (in which case there is no NUL but the string still ends). > + > +s->bitmap_size = ((bs->total_sectors + 7) >> 3); > +s->bitmap = qemu_blockalign(bs, s->bitmap_size); > + > +ret = bdrv_pread(bs->file, sizeof(header), s->bitmap, > +s->bitmap_size); > +if (ret != s->bitmap_size) { > +goto fail; > +} > + > +if (s->image_file[0] == '\0') { > +ret = -ENOENT; > +goto fail; > +} > + > +ret = bdrv_file_open(&backing_bs, bs->backing_file, 0); > +if (ret < 0) { > +return ret; > +} > +bdrv_delete(backing_bs); What does this do? (It leaks s->bitmap when it fails.) > + > +s->image_hd = bdrv_new(""); > + > +if (path_has_protocol(s->image_file)) { > +pstrcpy(image_filename, sizeof(image_filename), > +s->image_file); > +} else { > +path_combine(image_filename, sizeof(image_filename), > + bs->filename, s->image_file); > +} > + > +image_drv = bdrv_find_format("raw"); > +ret = bdrv_open(s->image_hd, image_filename, flags, image_drv); > +if (ret < 0) { > +bdrv_delete(s->image_hd); > +s->image_hd = NULL; > +goto fail; > +} TODO > + > +qemu_co_mutex_init(&s->lock); > +return 0; > + fail: > +g_free(s->bitmap); > +
[Qemu-devel] [PATCH v6] block:add-cow file format
From: Dong Xu Wang Introduce a new file format: add-cow. The usage can be found in add-cow.txt of this patch. CC: Kevin Wolf CC: Stefan Hajnoczi Signed-off-by: Dong Xu Wang --- After applying this patch, qemu might can not compile, need apply this patch first: http://lists.gnu.org/archive/html/qemu-devel/2011-12/msg02527.html Makefile.objs |1 + block.c|2 +- block.h|1 + block/add-cow.c| 429 block_int.h|1 + docs/specs/add-cow.txt | 72 6 files changed, 505 insertions(+), 1 deletions(-) create mode 100644 block/add-cow.c create mode 100644 docs/specs/add-cow.txt diff --git a/Makefile.objs b/Makefile.objs index f753d83..23fab70 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -31,6 +31,7 @@ block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o block-nested-y += raw.o cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o +block-nested-y += add-cow.o block-nested-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o block-nested-y += qed-check.o block-nested-y += parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o diff --git a/block.c b/block.c index aa9d142..0f52a67 100644 --- a/block.c +++ b/block.c @@ -187,7 +187,7 @@ static void bdrv_io_limits_intercept(BlockDriverState *bs, } /* check if the path starts with ":" */ -static int path_has_protocol(const char *path) +int path_has_protocol(const char *path) { #ifdef _WIN32 if (is_windows_drive(path) || diff --git a/block.h b/block.h index 0e3ff9f..f5bf078 100644 --- a/block.h +++ b/block.h @@ -289,6 +289,7 @@ char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn); char *get_human_readable_size(char *buf, int buf_size, int64_t size); int path_is_absolute(const char *path); +int path_has_protocol(const char *path); void path_combine(char *dest, int dest_size, const char *base_path, const char *filename); diff --git a/block/add-cow.c b/block/add-cow.c new file mode 100644 index 000..95af5b7 --- /dev/null +++ b/block/add-cow.c @@ -0,0 +1,429 @@ +#include "qemu-common.h" +#include "block_int.h" +#include "module.h" + +#define ADD_COW_MAGIC (((uint64_t)'A' << 56) | ((uint64_t)'D' << 48) | \ +((uint64_t)'D' << 40) | ((uint64_t)'_' << 32) | \ +((uint64_t)'C' << 24) | ((uint64_t)'O' << 16) | \ +((uint64_t)'W' << 8) | 0xFF) +#define ADD_COW_VERSION 1 +#define ADD_COW_FILE_LEN1024 + +typedef struct AddCowHeader { +uint64_tmagic; +uint32_tversion; +charbacking_file[ADD_COW_FILE_LEN]; +charimage_file[ADD_COW_FILE_LEN]; +uint64_tsize; +charreserved[492]; +} QEMU_PACKED AddCowHeader; + +typedef struct BDRVAddCowState { +charimage_file[ADD_COW_FILE_LEN]; +BlockDriverState*image_hd; +uint8_t *bitmap; +uint64_tbitmap_size; +CoMutex lock; +} BDRVAddCowState; + +static int add_cow_probe(const uint8_t *buf, int buf_size, const char *filename) +{ +const AddCowHeader *header = (const void *)buf; + +if (be64_to_cpu(header->magic) == ADD_COW_MAGIC && +be32_to_cpu(header->version) == ADD_COW_VERSION) { +return 100; +} else { +return 0; +} +} + +static int add_cow_open(BlockDriverState *bs, int flags) +{ +AddCowHeaderheader; +int64_t size; +charimage_filename[ADD_COW_FILE_LEN]; +BlockDriver *image_drv = NULL; +int ret; +BDRVAddCowState *s = bs->opaque; +BlockDriverState*backing_bs = NULL; + +ret = bdrv_pread(bs->file, 0, &header, sizeof(header)); +if (ret != sizeof(header)) { +goto fail; +} + +if (be64_to_cpu(header.magic) != ADD_COW_MAGIC) { +ret = -EINVAL; +goto fail; +} +if (be32_to_cpu(header.version) != ADD_COW_VERSION) { +char version[64]; +snprintf(version, sizeof(version), "ADD-COW version %d", header.version); +qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE, +bs->device_name, "add-cow", version); +ret = -ENOTSUP; +goto fail; +} + +size = be64_to_cpu(header.size); +bs->total_sectors = size / BDRV_SECTOR_SIZE; + +QEMU_BUILD_BUG_ON(sizeof(bs->backing_file) != sizeof(header.backing_file)); +QEMU_BUILD_BUG_ON(sizeof(s->image_file) != sizeof(header.image_file)); +pstrcpy(bs->backing_file, sizeof(bs->backing_file), +header.backing_file); +pstrcpy(s->image_file, sizeof(s->image_file), +header.image_file); + +s->bitmap_size = ((bs->total_sectors + 7) >> 3); +s->bitmap = qemu_blockalign(bs, s->bitmap_size); +