diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c index 3010adb909bf17b702428fe84eeb40e851da1045..6e93ec43e117e661c067f4a97df5a9f39c119624 100644 --- a/block/qcow2-bitmap.c +++ b/block/qcow2-bitmap.c @@ -1004,7 +1004,8 @@ fail: return false; } -int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp) +int qcow2_reopen_bitmaps_rw_hint(BlockDriverState *bs, bool *header_updated, + Error **errp) { BDRVQcow2State *s = bs->opaque; Qcow2BitmapList *bm_list; @@ -1012,6 +1013,10 @@ int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp) GSList *ro_dirty_bitmaps = NULL; int ret = 0; + if (header_updated != NULL) { + *header_updated = false; + } + if (s->nb_bitmaps == 0) { /* No bitmaps - nothing to do */ return 0; @@ -1055,6 +1060,9 @@ int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp) error_setg_errno(errp, -ret, "Can't update bitmap directory"); goto out; } + if (header_updated != NULL) { + *header_updated = true; + } g_slist_foreach(ro_dirty_bitmaps, set_readonly_helper, false); } @@ -1065,6 +1073,11 @@ out: return ret; } +int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp) +{ + return qcow2_reopen_bitmaps_rw_hint(bs, NULL, errp); +} + /* store_bitmap_data() * Store bitmap to image, filling bitmap table accordingly. */ diff --git a/block/qcow2.c b/block/qcow2.c index cf4f3becae636fdaa266e70567a73be7167b7d7c..486f3e83b779c99099d307365aa41152ea99daa8 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1480,7 +1480,22 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, s->autoclear_features &= QCOW2_AUTOCLEAR_MASK; } - if (qcow2_load_dirty_bitmaps(bs, &local_err)) { + if (bdrv_dirty_bitmap_next(bs, NULL)) { + /* It's some kind of reopen with already existing dirty bitmaps. There + * are no known cases where we need loading bitmaps in such situation, + * so it's safer don't load them. + * + * Moreover, if we have some readonly bitmaps and we are reopening for + * rw we should reopen bitmaps correspondingly. + */ + if (bdrv_has_readonly_bitmaps(bs) && + !bdrv_is_read_only(bs) && !(bdrv_get_flags(bs) & BDRV_O_INACTIVE)) + { + bool header_updated = false; + qcow2_reopen_bitmaps_rw_hint(bs, &header_updated, &local_err); + update_header = update_header && !header_updated; + } + } else if (qcow2_load_dirty_bitmaps(bs, &local_err)) { update_header = false; } if (local_err != NULL) { diff --git a/block/qcow2.h b/block/qcow2.h index ccb92a9696d8a0205aaa59b011ab954cbd2b0a4a..d301f77cea57d305b4a18bf861b38a7fb68c2f3e 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -671,6 +671,8 @@ int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res, void **refcount_table, int64_t *refcount_table_size); bool qcow2_load_dirty_bitmaps(BlockDriverState *bs, Error **errp); +int qcow2_reopen_bitmaps_rw_hint(BlockDriverState *bs, bool *header_updated, + Error **errp); int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp); void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp); int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp); diff --git a/block/vmdk.c b/block/vmdk.c index f94c49a9c0d8e734289fc4e61d72df813cbe4bcf..84f8bbe480cbf944e87145af0b3bbd0617d52a80 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -47,6 +47,8 @@ #define VMDK4_FLAG_MARKER (1 << 17) #define VMDK4_GD_AT_END 0xffffffffffffffffULL +#define VMDK_EXTENT_MAX_SECTORS (1ULL << 32) + #define VMDK_GTE_ZEROED 0x1 /* VMDK internal error codes */ @@ -1250,6 +1252,10 @@ static int get_cluster_offset(BlockDriverState *bs, return zeroed ? VMDK_ZEROED : VMDK_UNALLOC; } + if (extent->next_cluster_sector >= VMDK_EXTENT_MAX_SECTORS) { + return VMDK_ERROR; + } + cluster_sector = extent->next_cluster_sector; extent->next_cluster_sector += extent->cluster_sectors; diff --git a/tests/qemu-iotests/169 b/tests/qemu-iotests/169 index 3a8db91f6f9337d1024a653984388187e388f710..153b10b6e75844f897621c3f11c8263020c1e875 100755 --- a/tests/qemu-iotests/169 +++ b/tests/qemu-iotests/169 @@ -140,16 +140,14 @@ def inject_test_case(klass, name, method, *args, **kwargs): mc = operator.methodcaller(method, *args, **kwargs) setattr(klass, 'test_' + name, new.instancemethod(mc, None, klass)) -for cmb in list(itertools.product((True, False), repeat=3)): +for cmb in list(itertools.product((True, False), repeat=4)): name = ('_' if cmb[0] else '_not_') + 'persistent_' name += ('_' if cmb[1] else '_not_') + 'migbitmap_' name += '_online' if cmb[2] else '_offline' - - # TODO fix shared-storage bitmap migration and enable cases for it - args = list(cmb) + [False] + name += '_shared' if cmb[3] else '_nonshared' inject_test_case(TestDirtyBitmapMigration, name, 'do_test_migration', - *args) + *list(cmb)) if __name__ == '__main__': diff --git a/tests/qemu-iotests/169.out b/tests/qemu-iotests/169.out index 594c16f49f2732b12af4f63193319d38be583876..b6f257674e9122cb4721d30059ded516bcdc6786 100644 --- a/tests/qemu-iotests/169.out +++ b/tests/qemu-iotests/169.out @@ -1,5 +1,5 @@ -........ +................ ---------------------------------------------------------------------- -Ran 8 tests +Ran 16 tests OK