From: John Baboval <baboval@spineless.org>
To: qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PATCH v10] Support vhd type VHD_DIFFERENCING
Date: Thu, 16 Apr 2015 14:26:13 -0400 [thread overview]
Message-ID: <552FFEC5.5090900@spineless.org> (raw)
In-Reply-To: <1425478712-4146-1-git-send-email-gongxiaodong1@huawei.com>
Thank you for this patch.
I found a few places where you have 32-bit integer overflows that result
in failure. They are marked inline below.
On 03/04/2015 09:18 AM, Xiaodong Gong wrote:
> diff --git a/block/vpc.c b/block/vpc.c
> index 46803b1..d9a8d19 100644
> --- a/block/vpc.c
> +++ b/block/vpc.c
> @@ -29,17 +29,29 @@
> #if defined(CONFIG_UUID)
> #include <uuid/uuid.h>
> #endif
> +#include <glib.h>
>
> /**************************************************************/
>
> #define HEADER_SIZE 512
> +#define DYNAMIC_HEADER_SIZE 1024
> +#define PARENT_LOCATOR_NUM 8
> +#define TBBATMAP_HEAD_SIZE 28
> +
> +#define MACX_PREFIX_LEN 7 /* file:// */
> +
> +#define PLATFORM_MACX 0x4D616358
> +#define PLATFORM_W2RU 0x57327275
> +#define PLATFORM_W2KU 0x57326B75
> +
> +#define VHD_VERSION(major, minor) (((major) << 16) | ((minor) & 0x0000FFFF))
>
> //#define CACHE
>
> enum vhd_type {
> VHD_FIXED = 2,
> VHD_DYNAMIC = 3,
> - VHD_DIFFERENCING = 4,
> + VHD_DIFF = 4,
> };
>
> // Seconds since Jan 1, 2000 0:00:00 (UTC)
> @@ -138,6 +150,15 @@ typedef struct BDRVVPCState {
> Error *migration_blocker;
> } BDRVVPCState;
>
> +typedef struct vhd_tdbatmap_header {
> + char magic[8]; /* always "tdbatmap" */
> +
> + uint64_t batmap_offset;
> + uint32_t batmap_size;
> + uint32_t batmap_version;
> + uint32_t checksum;
> +} QEMU_PACKED VHDTdBatmapHeader;
> +
> static uint32_t vpc_checksum(uint8_t* buf, size_t size)
> {
> uint32_t res = 0;
> @@ -157,6 +178,224 @@ static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename)
> return 0;
> }
>
> +static int vpc_decode_maxc_loc(BlockDriverState *bs, uint32_t data_length)
> +{
> + GIConv cd;
> + gchar *inbuf, *outbuf, *buf;
> + gsize inbyteleft, outbyteleft, outbyte;
> + int ret = 0;
> + gsize ret1;
> + gint ret2;
> +
> + if (!bs || !bs->backing_file || !data_length) {
> + return -1;
> + }
> +
> + cd = g_iconv_open("ASCII", "UTF8");
> + if (cd == (GIConv) -1) {
> + return -1;
> + }
> +
> + inbuf = bs->backing_file;
> + outbuf = buf = (gchar *) g_malloc(data_length + 1);
> + if (!outbuf) {
> + ret = -1;
> + goto fail2;
> + }
> + inbyteleft = outbyteleft = data_length;
> +
> + ret1 = g_iconv(cd, &inbuf, &inbyteleft, &outbuf, &outbyteleft);
> + if (ret1 == (gsize) -1 || inbyteleft) {
> + ret = -1;
> + goto fail1;
> + }
> + outbyte = data_length - outbyteleft;
> + if (outbyte > sizeof(bs->backing_file) - 1) {
> + ret = -1;
> + goto fail1;
> + }
> + if (outbyte < MACX_PREFIX_LEN) {
> + ret = -1;
> + goto fail1;
> + }
> + buf[outbyte] = '\0';
> +
> + pstrcpy(bs->backing_file, sizeof(bs->backing_file), buf + MACX_PREFIX_LEN);
> +
> +fail1:
> + g_free(buf);
> + buf = NULL;
> +
> +fail2:
> + ret2 = g_iconv_close(cd);
> + if (ret2 == (gint) -1) {
> + ret = -1;
> + }
> +
> + return ret;
> +}
> +
> +static int vpc_decode_w2u_loc(BlockDriverState *bs, uint32_t data_length)
> +{
> + GIConv cd;
> + gchar *buf, *inbuf, *outbuf;
> + gsize inbyteleft, outbyteleft, outbyte;
> + gchar *ptr;
> + char len = 0;
> + int ret = 0;
> + gsize ret1;
> + gint ret2;
> +
> + if (!bs || !bs->backing_file || !data_length) {
> + return -1;
> + }
> +
> + cd = g_iconv_open("ASCII", "UTF-16LE");
> + if (cd == (GIConv) -1) {
> + return -1;
> + }
> +
> + inbuf = bs->backing_file;
> + outbuf = buf = ptr = (char *) g_malloc(data_length + 1);
> + if (!buf) {
> + ret = -1;
> + goto fail2;
> + }
> + inbyteleft = outbyteleft = data_length;
> +
> + ret1 = g_iconv(cd, &inbuf, &inbyteleft, &outbuf, &outbyteleft);
> + if (ret1 == (gsize) -1 || inbyteleft) {
> + ret = -1;
> + goto fail1;
> + }
> + outbyte = data_length - outbyteleft;
> + if (outbyte > sizeof(bs->backing_file) - 1) {
> + ret = -1;
> + goto fail1;
> + }
> + buf[outbyte] = '\0';
> +
> + while (ptr != outbuf) {
> + if (*ptr == '\\') {
> + *ptr = '/';
> + }
> + ptr++;
> + }
> + ptr = strstr(buf, ":");
> + if (ptr) {
> + *ptr = '.';
> + len = ptr - buf;
> + }
> +
> + pstrcpy(bs->backing_file, sizeof(bs->backing_file), buf + len);
> +
> +fail1:
> + g_free(buf);
> + buf = NULL;
> +
> +fail2:
> + ret2 = g_iconv_close(cd);
> + if (ret2 == (gint) -1) {
> + return -1;
> + }
> +
> + return ret;
> +}
> +
> +static int vpc_decode_parent_loc(uint32_t platform,
> + BlockDriverState *bs,
> + uint32_t data_length)
> +{
> + int ret;
> +
> + switch (platform) {
> + case PLATFORM_MACX:
> + ret = vpc_decode_maxc_loc(bs, data_length);
> + if (ret < 0) {
> + return ret;
> + }
> + break;
> +
> + case PLATFORM_W2RU:
> + /* fall through! */
> + case PLATFORM_W2KU:
> + ret = vpc_decode_w2u_loc(bs, data_length);
> + if (ret < 0) {
> + return ret;
> + }
> + break;
> +
> + default:
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static int vpc_read_backing_loc(VHDDynDiskHeader *dyndisk_header,
> + BlockDriverState *bs,
> + Error **errp)
> +{
> + BDRVVPCState *s = bs->opaque;
> + uint64_t data_offset;
> + uint32_t data_length;
> + uint32_t platform;
> + bool done = false;
> + uint64_t parent_locator_offset = 0;
> + int i;
> + int ret = 0;
> +
> + for (i = 0; i < PARENT_LOCATOR_NUM; i++) {
> + platform =
> + be32_to_cpu(dyndisk_header->parent_locator[i].platform);
> + data_offset =
> + be64_to_cpu(dyndisk_header->parent_locator[i].data_offset);
> + data_length =
> + be32_to_cpu(dyndisk_header->parent_locator[i].data_length);
> +
> + /* Extend the location offset */
> + if (parent_locator_offset < data_offset) {
> + parent_locator_offset = data_offset;
> + }
> +
> + if (done) {
> + continue;
> + }
> +
> + /* Read location of backing file */
> + if (data_offset > s->max_table_entries * s->block_size) {
This multiplication overflows resulting in failure...
> + return -1;
> + }
> + if (data_length > sizeof(bs->backing_file) - 1) {
> + return -1;
> + }
> + ret = bdrv_pread(bs->file, data_offset, bs->backing_file,
> + data_length);
> + if (ret < 0) {
> + return ret;
> + }
> +
> + bs->backing_file[data_length] = '\0';
> +
> + /* Decode the parent location */
> + ret = vpc_decode_parent_loc(platform, bs, data_length);
> + if (ret < 0) {
> + return ret;
> + }
> +
> + /* Right parent location is got */
> + if (bs->backing_file[0] != '\0') {
> + done = true;
> + }
> + }
> +
> + if (!done) {
> + return -1;
> + }
> +
> + return parent_locator_offset;
> +}
> +
> static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
> Error **errp)
> {
> @@ -164,11 +403,14 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
> int i;
> VHDFooter *footer;
> VHDDynDiskHeader *dyndisk_header;
> - uint8_t buf[HEADER_SIZE];
> + uint8_t buf[DYNAMIC_HEADER_SIZE];
> + uint8_t tdbatmap_header_buf[TBBATMAP_HEAD_SIZE];
> uint32_t checksum;
> uint64_t computed_size;
> - int disk_type = VHD_DYNAMIC;
> + uint32_t disk_type;
> int ret;
> + VHDTdBatmapHeader *tdbatmap_header;
> + uint64_t parent_locator_offset = 0;
>
> ret = bdrv_pread(bs->file, 0, s->footer_buf, HEADER_SIZE);
> if (ret < 0) {
> @@ -176,6 +418,8 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
> }
>
> footer = (VHDFooter *) s->footer_buf;
> + disk_type = be32_to_cpu(footer->type);
> +
> if (strncmp(footer->creator, "conectix", 8)) {
> int64_t offset = bdrv_getlength(bs->file);
> if (offset < 0) {
> @@ -230,9 +474,9 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
> goto fail;
> }
>
> - if (disk_type == VHD_DYNAMIC) {
> + if (disk_type == VHD_DYNAMIC || disk_type == VHD_DIFF) {
> ret = bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf,
> - HEADER_SIZE);
> + DYNAMIC_HEADER_SIZE);
> if (ret < 0) {
> goto fail;
> }
> @@ -286,6 +530,47 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
> s->free_data_block_offset =
> (s->bat_offset + (s->max_table_entries * 4) + 511) & ~511;
>
> + /* Read tdbatmap header by offset */
> + if (be32_to_cpu(footer->version) >= VHD_VERSION(1, 2)) {
> + ret = bdrv_pread(bs->file, s->free_data_block_offset,
> + tdbatmap_header_buf, TBBATMAP_HEAD_SIZE);
> + if (ret < 0) {
> + goto fail;
> + }
> +
> + tdbatmap_header = (VHDTdBatmapHeader *) tdbatmap_header_buf;
> + if (!strncmp(tdbatmap_header->magic, "tdbatmap", 8)) {
> + s->free_data_block_offset =
> + be32_to_cpu(tdbatmap_header->batmap_size) * 512
> + + be64_to_cpu(tdbatmap_header->batmap_offset);
> + }
> + }
> +
> + if (dyndisk_header->parent_name[0] || dyndisk_header->parent_name[1]) {
> + int len;
> +
> + /* Read parent location from dyn header table */
> + ret = parent_locator_offset = vpc_read_backing_loc(dyndisk_header,
> + bs, errp);
> + if (ret < 0) {
> + goto fail;
> + }
> +
> + /* Fix me : Set parent format to avoid probing to raw in
> + * format probe framework */
> + len = strlen("vpc");
> + if (sizeof(bs->backing_format) - 1 < len) {
> + goto fail;
> + }
> + pstrcpy(bs->backing_format, sizeof(bs->backing_format), "vpc");
> + }
> +
> + if (s->free_data_block_offset < parent_locator_offset
> + + BDRV_SECTOR_SIZE) {
> + s->free_data_block_offset = parent_locator_offset
> + + BDRV_SECTOR_SIZE;
> + }
> +
> for (i = 0; i < s->max_table_entries; i++) {
> be32_to_cpus(&s->pagetable[i]);
> if (s->pagetable[i] != 0xFFFFFFFF) {
> @@ -340,35 +625,76 @@ static int vpc_reopen_prepare(BDRVReopenState *state,
> }
>
> /*
> - * Returns the absolute byte offset of the given sector in the image file.
> - * If the sector is not allocated, -1 is returned instead.
> + * Returns the absolute byte offset of the given sector in the differencing
> + * image file.
> + *
> + * If error happened, -1 is returned.
> *
> - * The parameter write must be 1 if the offset will be used for a write
> - * operation (the block bitmaps is updated then), 0 otherwise.
> + * When write all type or read dynamic, if the sector is not allocated, -2
> + * is returned instead. If the sector is allocated in current file, the block
> + * offset is returned.
> + *
> + * When read diff. If the sector is not allocated, -2 is returned instead.
> + * If the sector is allocated in the backing file, -3 is returned. If the
> + * sector is allocated in current file, the block offset is returned.
> */
> static inline int64_t get_sector_offset(BlockDriverState *bs,
> - int64_t sector_num, int write)
> + int64_t sector_num, bool write, bool diff)
> {
> BDRVVPCState *s = bs->opaque;
> - uint64_t offset = sector_num * 512;
> - uint64_t bitmap_offset, block_offset;
> + uint64_t offset = sector_num << BDRV_SECTOR_BITS;
> + uint64_t bitmap_offset;
> uint32_t pagetable_index, pageentry_index;
> + int64_t block_offset = LONG_MIN;
> + int ret;
>
> pagetable_index = offset / s->block_size;
> - pageentry_index = (offset % s->block_size) / 512;
> + pageentry_index = (offset % s->block_size) >> BDRV_SECTOR_BITS;
>
> - if (pagetable_index >= s->max_table_entries || s->pagetable[pagetable_index] == 0xffffffff)
> - return -1; // not allocated
> + if (pagetable_index >= s->max_table_entries) {
> + return -2;
> + }
> + if (s->pagetable[pagetable_index] == 0xffffffff) {
> + if (!write && diff) {
> + return -3; /* parent allocated */
> + } else {
> + return -2; /* not allocated */
> + }
> + }
>
> - bitmap_offset = 512 * (uint64_t) s->pagetable[pagetable_index];
> - block_offset = bitmap_offset + s->bitmap_size + (512 * pageentry_index);
> + bitmap_offset = (uint64_t) s->pagetable[pagetable_index]
> + << BDRV_SECTOR_BITS;
> +
> + if (!diff || write) {
> + block_offset = bitmap_offset + s->bitmap_size
> + + (pageentry_index << BDRV_SECTOR_BITS);
> + } else {
> + uint32_t bitmap_index, bitmapentry_index;
> + uint8_t bitmap[s->bitmap_size];
>
> + if (bitmap_offset > s->max_table_entries * s->block_size) {
This one too....
> + return -1;
> + }
> + ret = bdrv_pread(bs->file, bitmap_offset, bitmap, s->bitmap_size);
> + if (ret < 0) {
> + return -1;
> + }
> +
> + bitmap_index = pageentry_index / 8;
> + bitmapentry_index = 7 - pageentry_index % 8;
> + if (bitmap[bitmap_index] & 0x1 << bitmapentry_index) {
> + block_offset = bitmap_offset + s->bitmap_size
> + + (pageentry_index << BDRV_SECTOR_BITS);
> + } else {
> + return -3;
> + }
> + }
> // We must ensure that we don't write to any sectors which are marked as
> // unused in the bitmap. We get away with setting all bits in the block
> // bitmap each time we write to a new block. This might cause Virtual PC to
> // miss sparse read optimization, but it's not a problem in terms of
> // correctness.
> - if (write && (s->last_bitmap_offset != bitmap_offset)) {
> + if (!diff && write && (s->last_bitmap_offset != bitmap_offset)) {
> uint8_t bitmap[s->bitmap_size];
>
> s->last_bitmap_offset = bitmap_offset;
> @@ -437,7 +763,8 @@ static int rewrite_footer(BlockDriverState* bs)
> *
> * Returns the sectors' offset in the image file on success and < 0 on error
> */
> -static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num)
> +static int64_t alloc_block(BlockDriverState *bs, int64_t sector_num,
> + bool diff)
> {
> BDRVVPCState *s = bs->opaque;
> int64_t bat_offset;
> @@ -457,7 +784,11 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num)
> s->pagetable[index] = s->free_data_block_offset / 512;
>
> // Initialize the block's bitmap
> - memset(bitmap, 0xff, s->bitmap_size);
> + if (diff) {
> + memset(bitmap, 0x0, s->bitmap_size);
> + } else {
> + memset(bitmap, 0xff, s->bitmap_size);
> + }
> ret = bdrv_pwrite_sync(bs->file, s->free_data_block_offset, bitmap,
> s->bitmap_size);
> if (ret < 0) {
> @@ -477,7 +808,7 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num)
> if (ret < 0)
> goto fail;
>
> - return get_sector_offset(bs, sector_num, 0);
> + return get_sector_offset(bs, sector_num, false, diff);
>
> fail:
> s->free_data_block_offset -= (s->block_size + s->bitmap_size);
> @@ -501,37 +832,71 @@ static int vpc_read(BlockDriverState *bs, int64_t sector_num,
> uint8_t *buf, int nb_sectors)
> {
> BDRVVPCState *s = bs->opaque;
> - int ret;
> - int64_t offset;
> - int64_t sectors, sectors_per_block;
> VHDFooter *footer = (VHDFooter *) s->footer_buf;
> + int64_t sectors_per_block = s->block_size >> BDRV_SECTOR_BITS;
> + int64_t offset, sectors;
> + int ret;
>
> - if (be32_to_cpu(footer->type) == VHD_FIXED) {
> + switch (be32_to_cpu(footer->type)) {
> + case VHD_FIXED:
> return bdrv_read(bs->file, sector_num, buf, nb_sectors);
> - }
> - while (nb_sectors > 0) {
> - offset = get_sector_offset(bs, sector_num, 0);
>
> - sectors_per_block = s->block_size >> BDRV_SECTOR_BITS;
> - sectors = sectors_per_block - (sector_num % sectors_per_block);
> - if (sectors > nb_sectors) {
> - sectors = nb_sectors;
> + case VHD_DYNAMIC:
> + while (nb_sectors > 0) {
> + sectors = sectors_per_block - (sector_num % sectors_per_block);
> + if (sectors > nb_sectors) {
> + sectors = nb_sectors;
> + }
> +
> + offset = get_sector_offset(bs, sector_num, false, false);
> + if (offset == -1) {
> + return -1;
> + } else if (offset == -2) {
> + memset(buf, 0, sectors * BDRV_SECTOR_SIZE);
> + } else {
> + ret = bdrv_pread(bs->file, offset, buf,
> + sectors * BDRV_SECTOR_SIZE);
> + if (ret != sectors * BDRV_SECTOR_SIZE) {
> + return -1;
> + }
> + }
> +
> + nb_sectors -= sectors;
> + sector_num += sectors;
> + buf += sectors * BDRV_SECTOR_SIZE;
> }
> + break;
>
> - if (offset == -1) {
> - memset(buf, 0, sectors * BDRV_SECTOR_SIZE);
> - } else {
> - ret = bdrv_pread(bs->file, offset, buf,
> - sectors * BDRV_SECTOR_SIZE);
> - if (ret != sectors * BDRV_SECTOR_SIZE) {
> + case VHD_DIFF:
> + while (nb_sectors > 0) {
> + offset = get_sector_offset(bs, sector_num, false, true);
> + if (offset == -1) {
> return -1;
> + } else if (offset == -2) {
> + memset(buf, 0, BDRV_SECTOR_SIZE);
> + } else if (offset == -3) {
> + ret = bdrv_pread(bs->backing_hd, sector_num << BDRV_SECTOR_BITS
> + , buf, BDRV_SECTOR_SIZE);
> + if (ret < 0) {
> + return -1;
> + }
> + } else {
> + ret = bdrv_pread(bs->file, offset, buf, BDRV_SECTOR_SIZE);
> + if (ret != BDRV_SECTOR_SIZE) {
> + return -1;
> + }
> }
> +
> + nb_sectors--;
> + sector_num++;
> + buf += BDRV_SECTOR_SIZE;
> }
> + break;
>
> - nb_sectors -= sectors;
> - sector_num += sectors;
> - buf += sectors * BDRV_SECTOR_SIZE;
> + default:
> + return -1;
> }
> +
> return 0;
> }
>
> @@ -546,41 +911,101 @@ static coroutine_fn int vpc_co_read(BlockDriverState *bs, int64_t sector_num,
> return ret;
> }
>
> +static inline int64_t write_bitmap(BlockDriverState *bs, int64_t sector_num,
> + int64_t sectors)
> +{
> + BDRVVPCState *s = bs->opaque;
> + uint64_t offset = sector_num << BDRV_SECTOR_BITS;
> + uint64_t bitmap_offset;
> + uint32_t pagetable_index, pageentry_index;
> + uint8_t bitmap[s->bitmap_size];
> + uint32_t bitmap_index, bitmapbit_index;
> + int i;
> + int ret;
> +
> + pagetable_index = offset / s->block_size;
> + pageentry_index = (offset % s->block_size) / 512;
> + bitmap_offset = 512 * (uint64_t) s->pagetable[pagetable_index];
> +
> + if (bitmap_offset > s->max_table_entries * s->block_size) {
And here...
> + return -1;
> + }
> + ret = bdrv_pread(bs->file, bitmap_offset, bitmap, s->bitmap_size);
> + if (ret < 0) {
> + return -1;
> + }
> +
> + for (i = 0; i < sectors; i++) {
> + bitmap_index = pageentry_index / 8;
> + bitmapbit_index = 7 - pageentry_index % 8;
> + bitmap[bitmap_index] |= (0x1 << bitmapbit_index);
> + pageentry_index++;
> + }
> + ret = bdrv_pwrite(bs->file, bitmap_offset, bitmap, s->bitmap_size);
> + if (ret < 0) {
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> static int vpc_write(BlockDriverState *bs, int64_t sector_num,
> const uint8_t *buf, int nb_sectors)
> {
> BDRVVPCState *s = bs->opaque;
> - int64_t offset;
> - int64_t sectors, sectors_per_block;
> - int ret;
> - VHDFooter *footer = (VHDFooter *) s->footer_buf;
> + VHDFooter *footer = (VHDFooter *) s->footer_buf;
> + int64_t sectors_per_block = s->block_size >> BDRV_SECTOR_BITS;
> + int64_t offset, sectors;
> + bool diff = true;
> + int ret = 0;
>
> - if (be32_to_cpu(footer->type) == VHD_FIXED) {
> + switch (be32_to_cpu(footer->type)) {
> + case VHD_FIXED:
> return bdrv_write(bs->file, sector_num, buf, nb_sectors);
> - }
> - while (nb_sectors > 0) {
> - offset = get_sector_offset(bs, sector_num, 1);
>
> - sectors_per_block = s->block_size >> BDRV_SECTOR_BITS;
> - sectors = sectors_per_block - (sector_num % sectors_per_block);
> - if (sectors > nb_sectors) {
> - sectors = nb_sectors;
> - }
> + case VHD_DYNAMIC:
> + diff = false;
> + /* fall-through ! */
> +
> + case VHD_DIFF:
> + while (nb_sectors > 0) {
> + sectors = sectors_per_block - (sector_num % sectors_per_block);
> + if (sectors > nb_sectors) {
> + sectors = nb_sectors;
> + }
>
> - if (offset == -1) {
> - offset = alloc_block(bs, sector_num);
> - if (offset < 0)
> + offset = get_sector_offset(bs, sector_num, true, diff);
> + if (offset == -1) {
> return -1;
> - }
> + } else if (offset == -2) {
> + offset = alloc_block(bs, sector_num, diff);
> + if (offset < 0) {
> + return -1;
> + }
> + }
>
> - ret = bdrv_pwrite(bs->file, offset, buf, sectors * BDRV_SECTOR_SIZE);
> - if (ret != sectors * BDRV_SECTOR_SIZE) {
> - return -1;
> + ret = bdrv_pwrite(bs->file, offset, buf,
> + sectors * BDRV_SECTOR_SIZE);
> + if (ret != sectors * BDRV_SECTOR_SIZE) {
> + return -1;
> + }
> +
> + if (diff) {
> + ret = write_bitmap(bs, sector_num, sectors);
> + if (ret < 0) {
> + return -1;
> + }
> + }
> +
> + nb_sectors -= sectors;
> + sector_num += sectors;
> + buf += sectors * BDRV_SECTOR_SIZE;
> }
>
> - nb_sectors -= sectors;
> - sector_num += sectors;
> - buf += sectors * BDRV_SECTOR_SIZE;
> + break;
> +
> + default:
> + return -1;
> }
>
> return 0;
> @@ -906,6 +1331,7 @@ static BlockDriver bdrv_vpc = {
> .bdrv_close = vpc_close,
> .bdrv_reopen_prepare = vpc_reopen_prepare,
> .bdrv_create = vpc_create,
> + .supports_backing = true,
>
> .bdrv_read = vpc_co_read,
> .bdrv_write = vpc_co_write,
prev parent reply other threads:[~2015-04-16 18:26 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-03-04 14:18 [Qemu-devel] [PATCH v10] Support vhd type VHD_DIFFERENCING Xiaodong Gong
2015-03-04 22:15 ` Philipp Hahn
2015-03-08 1:53 ` Xiaodong Gong
2015-03-08 10:53 ` Philipp Hahn
2015-03-11 6:22 ` Xiaodong Gong
2015-03-11 8:55 ` Philipp Hahn
2015-03-12 11:32 ` Xiaodong Gong
2015-04-16 18:26 ` John Baboval [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=552FFEC5.5090900@spineless.org \
--to=baboval@spineless.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.