On Tue, Nov 15, 2011 at 01:28:51PM +0800, Dong Xu Wang wrote: > From: Dong Xu Wang <wdon...@linux.vnet.ibm.com> > > Provide a new file format: add-cow. The usage can be found in add-cow.txt of > this patch. > > Signed-off-by: Dong Xu Wang <wdon...@linux.vnet.ibm.com> > --- > Makefile.objs | 1 + > block.c | 2 +- > block.h | 1 + > block/add-cow.c | 417 > ++++++++++++++++++++++++++++++++++++++++++++++++ > block_int.h | 1 + > docs/specs/add-cow.txt | 57 +++++++ > 6 files changed, 478 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 d7a6539..ad99243 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 86910b0..a2be27b 100644 > --- a/block.c > +++ b/block.c > @@ -106,7 +106,7 @@ int is_windows_drive(const char *filename) > #endif > > /* check if the path starts with "<protocol>:" */ > -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 051a25d..836284f 100644 > --- a/block.h > +++ b/block.h > @@ -276,6 +276,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 0000000..54d30a9 > --- /dev/null > +++ b/block/add-cow.c > @@ -0,0 +1,417 @@ > +#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_LEN 1024 > + > +typedef struct AddCowHeader { > + uint64_t magic; > + uint32_t version; > + char backing_file[ADD_COW_FILE_LEN]; > + char image_file[ADD_COW_FILE_LEN]; > + uint64_t size; > +} QEMU_PACKED AddCowHeader; > + > +typedef struct BDRVAddCowState { > + char image_file[ADD_COW_FILE_LEN]; > + BlockDriverState *image_hd; > + uint8_t *bitmap; > + uint64_t bitmap_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) > +{ > + AddCowHeader header; > + int64_t size; > + char image_filename[ADD_COW_FILE_LEN]; > + int image_flags; > + BlockDriver *image_drv = NULL; > + int ret; > + BDRVAddCowState *state = (BDRVAddCowState *)(bs->opaque); > + > + ret = bdrv_pread(bs->file, 0, &header, sizeof(header)); > + if (ret != sizeof(header)) { > + goto fail; > + } > + > + if (be64_to_cpu(header.magic) != ADD_COW_MAGIC || > + be32_to_cpu(header.version) != ADD_COW_VERSION) { > + ret = -EINVAL; > + goto fail; > + } > + > + size = be64_to_cpu(header.size); > + bs->total_sectors = size / BDRV_SECTOR_SIZE; > + > + QEMU_BUILD_BUG_ON(sizeof(state->image_file) != > sizeof(header.image_file)); > + pstrcpy(bs->backing_file, sizeof(bs->backing_file), > + header.backing_file); > + pstrcpy(state->image_file, sizeof(state->image_file), > + header.image_file); > + > + state->bitmap_size = ((bs->total_sectors + 7) >> 3); > + state->bitmap = g_malloc0(state->bitmap_size); > + > + ret = bdrv_pread(bs->file, sizeof(header), state->bitmap, > + state->bitmap_size); > + if (ret != state->bitmap_size) { > + goto fail; > + }
Reading the entire bitmap in memory is not acceptable, it may be huge. Better mmap it and use msync(MS_SYNC) when writing it back. This way the host can free memory easily upon pressure. > + /* If there is a image_file, must be together with backing_file */ > + if (state->image_file[0] != '\0') { > + state->image_hd = bdrv_new(""); > + > + if (path_has_protocol(state->image_file)) { > + pstrcpy(image_filename, sizeof(image_filename), > + state->image_file); > + } else { > + path_combine(image_filename, sizeof(image_filename), > + bs->filename, state->image_file); > + } > + > + image_drv = bdrv_find_format("raw"); > + image_flags = > + (flags & (~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING))) | > BDRV_O_RDWR; Why are you modifying flags here?